2017年6月22日木曜日

The Rust Programming Language 2nd 4日目 Ownership 1

![](https://doc.rust-lang.org/book/second-edition/]
Apache License Version 2.0

Understanding Owenership

ownership(所有権)はRustの最大の特徴で,メモリを安全に扱うことを可能にしている.
この章ではサンプルコードに rust fn main() はいちいち書かないことにする.

4.1 What is Ownership?

The Stack and the Heap

stackとheapはプログラムから見た仮想メモリの構造.あるいはOSから見た物理メモリの管理方法.
stackはデータを読み込んだ順に積み上げ(push),その逆順に読み込まれ,読み込まれた値を削除する(pop).

stackから値を取り出すとき,取り出す値をいちいち検索しなくて良い(検索できない)うえstackのデータはすべて同じビット長なので,stackは高速.プログラムが関数を呼ぶとき,その引数とローカル変数はstackにpushされて,関数が実行し終わるとそれらはpopされる.
一方,コンパイル時にはbit長がわからなないデータや,bit長が変わるデータのときは,heapを使う.heapにデータを入れようとすると,OSは空いているメモリの一部をheapのために割り当てて,そのメモリの番地(ポインタ)をプログラムに渡す.これをallocationという.stackにpushすることはallocationとは呼ばない.heapへのアクセスは,ポインタを経由しなければならないので,stackよりも遅い.heapを使うときは,heap上のデータの複製を最小限にし,使わなくなったデータは削除して,メモリ空間を開けなければならない.

Ownership Rules

  1. Rustの変数はそれぞれownerという変数を持っている.
  2. それぞれの変数について,同時に複数のownerは存在できない.
  3. ownerがスコープから出ると,その変数はRustのdrop関数によって削除される.

The String type

コンパイル時にすでに決まっている文字列はstring literalと言ってstackに保存されるが,ユーザーからの入力を受け付けるなどするため,コンパイル時に決まっていない文字列はString型といって,heapに保存される.

Ways Variables and Data Interact: Move

変数がheapであるときはRust特有のmoveという現象によって,他の言語では起こらないエラーが出る.
s1という変数は

という形をしていて,ポインタ,長さ,最大長さのデータがスタックとしてあって,さらにポインタの先に具体的なデータが存在する.ここでs2 = s1としたとき,複製されるのはポインタ,長さ,最大長さのデータだけで,具体的なデータは使いまわされる.

enter image description here
さらに,スコープから出たs1とs2を削除しようとして,同じポインタを二度dropしようとすると,衝突が起こって脆弱性につながる.そこでRustはs2=s1を発行した時点でs1は無効な変数であると考え,s1のスタックを削除する.
これは同時に,Rustは自動的には”深い”コピーを作らないということでもある.

fn main() {
  let s1 = String::from("hello");   // Stringはheap
  let s2 = s1;

  println!("s1 = {}", s1);
  println!("s2 = {}", s2);
}

shell

error[E0382]: use of moved value: `s1`
 --> src/main.rs:5:23
  |
3 |   let s2 = s1;
  |       -- value moved here
4 |
5 |   println!("s1 = {}", s1);
  |                       ^^ value used here after move
  |
  = note: move occurs because `s1` has type `std::string::String`, which does not implement the `Copy` trait
  ```

#### Ways Variables and Data Interact: Clone
深いコピーを作りたいときには```clone()```を使う.
*src/main.rs*
```rust
fn main() {
  let s1 = String::from("hello");   // Stringはheap
  let mut s2 = s1.clone();          // hardcopy


  s2.push_str("_world!");
  println!("s1 = {}", s1);
  println!("s2 = {}", s2);
}




<div class="se-preview-section-delimiter"></div>

shell

Finished dev [unoptimized + debuginfo] target(s) in 0.35 secs
 Running `target/debug/ownership`
s1 = hello
s2 = hello_world!




<div class="se-preview-section-delimiter"></div>

Stack-Only Data: Copy

integerやfloatのような,heapを使わず,stackだけに保存されるデータ型では,常に深いコピーが行われる.
src/main.rs

fn main() {
  let x = 5;
  let y = x;

  println!("the value of x is: {}", x);
  println!("the value of y is: {}", y);
}




<div class="se-preview-section-delimiter"></div>

bash

Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs
 Running `target/debug/ownership`
the value of x is: 5
the value of y is: 5




<div class="se-preview-section-delimiter"></div>

Ownership and Functions

関数の引数に変数を与えるときも,moveの特性に注意しなければならない.

src/main.rs

fn main() {
  let s = String::from("hello");
  takes_ownership(s);                         // この時点でsは失効

  let x = 5;
  makes_copy(x);

  println!("{}", s);                          // ここでsは参照できない.
}

fn takes_ownership(some_string: String) {
  println!("{}", some_string);
}

fn makes_copy(some_integer: i32) {
  println!("{}", some_integer);
}




<div class="se-preview-section-delimiter"></div>

shell

error[E0382]: use of moved value: `s`
 --> src/main.rs:7:18
  |
3 |   takes_ownership(s);
  |                   - value moved here
...
7 |   println!("{}", s);
  |                  ^ value used here after move
  |
  = note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait

error: aborting due to previous error

error: Could not compile `ownership`.

To learn more, run the command again with --verbose.

Basic Analysis (Jiri Lebl) 24日目 completeとcompact

CC BY-NC-SA 3.0

7.4 Completeness nad compactness

は距離空間とする.

7.4.1 Cauchy sequences and completeness

Definition 7.4.1

がCauchy列である

Proposition 7.4.2

距離空間の収束列はCauchy列である.
proof.

がに収束するなら,点列の収束の定義から

を満たすが存在する.

Definition 7.4.3

がComplete(完備)である
の任意のCauchy列がの点に収束する.

Proposition 7.4.4

にユークリッド距離を入れた距離空間は完備である.
proof. 略

7.4.2 Completeness

Definition 7.4.5

について,がcompact(コンパクト)である
をみたす開集合族があるとき,有限個を取り出してとなるようにできる.

Proposition 7.4.6

がコンパクトであるとき,は有界かつ閉集合である.
proof. 略

Lemma 7.4.7 (Lebesgue covering lemma)

とする.の任意の点列がの点に収束する部分列を持つとする.がのopen coverとすると,任意のに,となるを選べるようなが存在する.
proof.

対偶によって示す.どのをとっても,任意のでをみたさないようにを選べると仮定する.
どのにも,となるようなは存在する.よってなるがある.をみたすをとる.かつならば

が成立.すなわち. よっては収束する部分列を持ち得ない.

Theorem 7.4.8

がcompact の任意の点列がの点に収束する部分列を持つ.
proof.


対偶法を用いる.
とする.で,たかだか有限個のにが成立するようなが存在すると仮定する.このとき

が成立する.つまりはのopen coverである.
から有限個を取り出すと,その和集合は有限集合となって,を被覆できない.これは矛盾.


仮定のもとで,open cover をとる.Lemma 7.4.7から,任意のにとなるを選べるが存在する.
と,をみたすをとる.であれば,有限な被覆をみつけたことになる.そうでないとき,があって,をみたすがあって,である.これを無限回繰り返せるとき,無限列が得られる.
は,が成り立つから,Cauchy列でない.したがってはcompactでない.

Proposition 7.4.10

がcompactでが閉集合ならはcompact.
proof. 略

Theorem 7.4.11 (Heine-Borel)

が有界かつ閉集合ならはcompact
proof. 略

2017年6月20日火曜日

The Rust Programming Language 2nd 3日目 変数,基本型,関数

https://doc.rust-lang.org/book/second-edition/
Apache License Version 2.0

Common Programing Concepts

多くの言語に共通する機能がRustではどう実現されているか

3.1 Variables and Mutability

bash

cargo new --bin variables

で実験するプロジェクトを作る.
Rustでは,変数はデフォルトではimmutableである.つまり,一度変数に値を代入するとその後変更できない.

src/main.rs

fn main() {
  let x = 5;
  println!("The value of x is: {}", x);
  x = 6;
  println!("The value of x is: {}", x);
}

cargo runでビルドして実行してみると,

error[E0384]: re-assignment of immutable variable `x`
 --> src/main.rs:4:5
  |
2 |     let x = 5;
  |         - first assignment to `x`
3 |     println!("The value of x is: {}", x);
4 |     x = 6;
  |     ^^^^^ re-assignment of immutable variable

とエラーが出る.こうして,Rustはプログラマが予期しない代入を防いでいる.

しかし,いちいち新しい変数を用意するのは不便なときもある.そこで
src/main.rs

fn main() {
  let mut x = 5;
  println!("The value of x is: {}", x);
  x = 6;
  println!("The value of x is: {}", x);
}

とすると,

   Compiling variables v0.1.0 (file:///home/ren/Projects/variables)
    Finished dev [unoptimized + debuginfo] target(s) in 0.34 secs
     Running `target/debug/variables`
The value of x is: 5
The value of x is: 6

このようにletによる変数宣言と同時にmutによって変数をmutableにすることが出来る.

3.2 Differences Between Variables and Constants

定数とimmutableな変数は似ているが,いくつか違いがある.
1. immutable変数はmutによってmutableにできる.
2. 定数にはプログラムのどこからでも参照できる.
3. 定数はプログラム実行時に計算される値は代入できない.つまり,コンパイル時に決定される値しか代入できない.

Shadowing

新しい変数をすでにある変数と同じ名前で宣言することをshadowingという.このとき,新しい変数ははじめの変数をshadowしているといい,はじめの変数は新たな変数にshadowされたという.

src/main.rs

fn main() {
  let x = 5;
  let x = x + 1; // shadow 1回目
  let x = 2 * x; // shadow 2回目

  println!("The value of x is: {}", x);
}

shell

ren@ren-ThinkCentre-Edge72:~/Projects/variables$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
     Running `target/debug/variables`
The value of x is: 12

mutableな変数でも,宣言したあとで型を変えることはできない(静的型付).

src/main.rs

fn main() {
  let mut spaces = "  "; // 右辺は文字列
  spaces = spces.len();  // 右辺は整数の2
}

shell

ren@ren-ThinkCentre-Edge72:~/Projects/variables$ vim src/main.rs

   Compiling variables v0.1.0 (file:///home/ren/Projects/variables)
error[E0308]: mismatched types
 --> src/main.rs:3:14
  |
3 |     spaces = spaces.len()
  |              ^^^^^^^^^^^^ expected &str, found usize
  |
  = note: expected type `&str`
             found type `usize`

変数名を型を変えながら使いまわしたいとき,shadowingが有効.

Data Types

Rustは静的型付言語だが,変数宣言時に型を指定しなくても,コンパイラが推測してくれる.しかし,プログラマが型を指定しなければならない場合もある.

Scalar Types

整数,浮動小数点数,真理値,文字は長さが固定されている変数であり,scalarという.

Integer Types (自然数型)

自然数型は符号のあるなしとビット長によっての10種類がある.ビット長は8, 16, 32, 64, そしてアーキテクチャ依存のsize長がある.符号付きならi,符号なしならuを頭につけて,ビット長を尾につけてその型を指定できる.例えば符号なし32bitなら u32 である. Rustのデフォルトはi32で,64bit CPUでもこれが最も早く処理できることが多い.

src/main.rs

fn main() {
  let x:i32 = 2147483648;     // i32だとオーバーフローする値
  println!("x is {}", x);
}

shell

Compiling variables v0.1.0 (file:///home/ren/Projects/variables)
warning: literal out of range for i32
--> src/main.rs:2:13
|
2 |     let x = 2147483648;
|             ^^^^^^^^^^
|
= note: #[warn(overflowing_literals)] on by default

 Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
  Running `target/debug/variables`
x is -2147483648 

オーバーフローする値を代入しても,オーバーフローしないような型にしてくれるわけではない.コンパイルエラーにはならず,コンパイル時に警告される.

Floating-Point Types (浮動小数点数型)

小数点以下が表現できる.32bit長(f32)と64bit長(f64)があるが,速さはほとんど同じなので64bit長がよく使われる.

Numeric Operations

算術的演算はpythonと同じ記法で行える.しかし,自然数と浮動小数点数の演算を直接行うことはできない.

src/main.rs

fn main() {
  let a = 3;
  let b = 3.0;
  let c = a + b;
  println!("int plus float: {}", c);
}

shell

Compiling variables v0.1.0 (file:///home/ren/Projects/variables)
error[E0277]: the trait bound `{integer}: std::ops::Add<{float}>` is not satisfied
--> src/main.rs:4:13
|
4 |     let c = a + b;
|             ^^^^^ the trait `std::ops::Add<{float}>` is not implemented for `{integer}`
|
= note: no implementation for `{integer} + {float}`

error: aborting due to previous error

error: Could not compile `variables`.

To learn more, run the command again with --verbose.

The Boolean Type

真理値はboolによって指定できて,trueかfalseの値だけを取る.
型を指定せずとも,trueかfalseを宣言時に代入すれば,コンパイラがbool型と推測する.

The Character Type

1文字を表現できるスカラー型はcharで,内部ではUnicodeを保持する.

Compound Types

長さが2以上ある変数の型.tupleとarrayがある.

Grouping Values into Tuples

必ずしも共通でない型の値たちを一つの変数に代入する型.カッコでくくり,コンマで要素を区切る.タプル定義でも型推測は行われるが,プログラマが型を指定することも出来る.タプルの要素を取り出す方法は2つある.
1. pattern matching: タプルの長さと同じ個数の変数にタプルを代入し,求めたい要素の入っている変数にアクセスする
2. index: タプルの一番左の要素を0として,求めたい変数のインデックスがiなら,tupple.iでアクセスできる.

src/main.rs

fn main() {
  let tup = (500, 6.4, 1);
  let typed_tup: (i32, f64, u8) = (500, 6.4, 1);
  let (x, y, z ) = tup;
  println!("The value of y is: {}", y);           // pattern matchingによるアクセス

  println!("The value of y is: {}", typed_tup.1); // indexによるアクセス
}

shell

Compiling variables v0.1.0 (file:///home/ren/Projects/variables)
 ~ 略 (一度も使っていない変数があると怒られる) ~ 
Finished dev [unoptimized + debuginfo] target(s) in 0.43 secs
 Running `target/debug/variables`
The value of y is: 6.4
The value of y is: 6.4

Arrays

tuppleと違って,すべての要素が同じ型でなければならない.また,長さは固定である.定義するときは’[ ]’でくくって、コンマで要素を区切る.arrayもtuppleのようなインデックスが振られているが,アクセスするにはarray[i]と書く.arrayの長さに反するインデックスでアクセスしようとすると,コンパイルエラーは起きないが実行時にpanicする.

src/main.rs

fn main() {
  let a = [1, 2, 3, 4, 5];
  let index = 10;
  let element = a[index];

  println!("The value of element is: {}", element);
}

shell

Compiling variables v0.1.0 (file:///home/ren/Projects/variables)
 Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
  Running `target/debug/variables`
thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.

3.3 How Functions Work

新しくfunctionsプロジェクトを作る.
関数はfn <関数名>() {}で定義され,{}の中身が実際に実行される.2つ以上関数をつくって,片方からもう片方の関数を利用することが出来る.

src/main.rs

fn main() {
  println!("Hello, world!");

  another_function();
}  

fn another_function() {
  println!("Another function.");
}

shell

Compiling functions v0.1.0 (file:///home/ren/Projects/functions)
 Finished dev [unoptimized + debuginfo] target(s) in 0.36 secs
  Running `target/debug/functions`
Hello, world!
Another function.

Function Parameters

関数の引数は,fn name () {}の()の中で指定する.引数の名前だけでなく,型も同時に指定しなければならない.

src/main.rs

fn main() {
  another_function(1, 2);
}

fn another_function(x:i32, y) {  // yの型を指定していない.
  println!("x is {}", x);
  println!("y is {}", y);
}

shell

Compiling functions v0.1.0 (file:///home/ren/Projects/functions)
error: expected one of `:` or `@`, found `)`
--> src/main.rs:6:29
|
6 | fn another_function(x:i32, y) {
|                             ^ expected one of `:` or `@` here

error[E0425]: cannot find value `y` in this scope
--> src/main.rs:8:25
|
8 |     println!("y is {}", y);
|                         ^ did you mean `x`?

error: aborting due to 2 previous errors

error: Could not compile `functions`.

Statements and Expressions

Rustはepxressionベースの言語である.statementとexpressionの違いは,後者が返り値を返すが,前者はそうでないという点である.
変数宣言や関数定義はstatementであるから,返り値を返さない.よって

let x = (let y = 6);

はコンパイルできない.
一方で,expressionはプログラムの大半を占めている.

fn main() {
  let x = 5;      // 5自体はexpressionで,5を返す. expressionはstatementの一部になれる.

  let y = {
    let x = 3;    
    x + 1         
  };              // {}はexpression

  println!("The value of y is: {}", y);  // マクロはexpression
}

最後に;のない行はexpressionであり,;を加えるとstatementになる.

Functions with Return Values

関数はfn name () -> type {}によって返り値を返すようにすることが出来る.返される値は,{}の中の最後のexpressionの値である.
src/main.rs

fn five() -> i32 {
  4;   // このステートメントは特に何もしない.
  5    // これが{}の中の最後のexpressionだから,これの返り値がfive()の返り値になる.
}

fn main() {
  let x = five();
  println!("The value of x is: {}", x);
}

shell

Compiling functions v0.1.0 (file:///home/ren/Projects/functions)
 Finished dev [unoptimized + debuginfo] target(s) in 0.34 secs
  Running `target/debug/functions`
The value of x is: 5

返り値が返されると定めた関数にepxressionがない場合,コンパイルエラーになる.

src/main.rs

fn plus_one(x:i32) -> i32 {
  x + 1;
}

fn main() {
  let x = plus_one(5);
  println!("The value of x  is: {}", x);
}

shell

Compiling functions v0.1.0 (file:///home/ren/Projects/functions)
error[E0308]: mismatched types
--> src/main.rs:1:27
|
1 |   fn plus_one(x:i32) -> i32 {
|  ___________________________^
2 | |   
3 | |   x + 1;
4 | | }
| |_^ expected (), found i32
|
= note: expected type `()`
          found type `i32`
help: consider removing this semicolon:
--> src/main.rs:3:8
|
3 |   x + 1;
|        ^

error: aborting due to previous error

error: Could not compile `functions`.

To learn more, run the command again with --verbose.

Control Flow

条件分岐とループ

if expression

if condition_1 {codeblock_1} else if condition_2 {codeblock_2} … else {codeblock_0}
condition_1から順にconditionがtrueか調べられ,condition_kがtrueならcodeblock_kが実行され,すべてのconditionがfalseなら,codeblock_0が実行される.elseがない場合,何も実行されない.codeblockたちをifのarmと呼ぶことがある.conditionは,評価するとBoolを返すexpressionでなければならない.

src/main.rs

fn main() {
  let number = 3;
  if number < 5 {
    println!("condition was true");
  } else {
    println!("condition was false");
  }
}

shell

Compiling branches v0.1.0 (file:///home/ren/Projects/branches)
 Finished dev [unoptimized + debuginfo] target(s) in 0.35 secs
  Running `target/debug/branches`
condition was true

Using if in a let statement

ifはexpressionなので,letを使った変数宣言の右辺に置くことが出来る.
src/main.rs

fn main() {
  let condition = true;
  let number = if condition {
    5
  } else {
    6
  };

  println!("The value of number is: {}", number);
}

shell

Compiling branches v0.1.0 (file:///home/ren/Projects/branches)
 Finished dev [unoptimized + debuginfo] target(s) in 0.34 secs
  Running `target/debug/branches`
The value of number is: 5

ここで,変数numberにはconditionの真偽によって{5}, {6}のコードブロックの返り値が代入されるが,このコードブロックたちの返す値の型が異なっていると,numberの型が推測できず,コンパイルエラーになる.
src/main.rs

fn main() {
  let condition = true;
  let number = if condition {
    5
  } else {
    "six"
  };

  println!("The value of number is: {}", number);
}

shell

Compiling branches v0.1.0 (file:///home/ren/Projects/branches)
error[E0308]: if and else have incompatible types
--> src/main.rs:3:16
|
3 |     let number = if condition {
|  ________________^
4 | |       5
5 | |     } else {
6 | |         "six"
7 | |       };
| |_______^ expected integral variable, found &str
|
= note: expected type `{integer}`
          found type `&str`

error: aborting due to previous error

error: Could not compile `branches`.

Repetition with Loops

Rustはloop,while,forの3種類のループを実装している.

Repeating Code with loop

明示的にbreakされるまでループを続ける.

src/main.rs

fn main() {
  loop {
    println!("again!");
  }
}

shell

again!  # 無限ループ

Conditional Loops with while

ループ中毎回条件を評価し,条件がfalseになったらループを中断する.
src/main.rs

fn main() {
  let mut number = 3;
  while number != 0 {
    println!("{}", number);
    number = number - 1;
  }
  println!("LIFTOFF!!!");
}

shell

Compiling branches v0.1.0 (file:///home/ren/Projects/branches)
 Finished dev [unoptimized + debuginfo] target(s) in 0.35 secs
  Running `target/debug/branches`
3
2
1
LIFTOFF!!!

Looping Through a Collection with for

tuppleやarrayの要素ごとに処理を実行したいとき,forが使える.また,決まった回数ループしたい場合,Range型にforを使って実現できる.

src/main.rs

fn main() {
  for number in (1..4).rev() { 
    println!("{}!", number)
  }
  println!("LIFTOFF!!!");
}

shell

Compiling branches v0.1.0 (file:///home/ren/Projects/branches)
 Finished dev [unoptimized + debuginfo] target(s) in 0.38 secs
  Running `target/debug/branches`
3!
2!
1!
LIFTOFF!!!

Summary (練習)
1. 華氏を摂氏に変換するプログラムを書け.
2. n番目のフィボナッチ数を計算するプログラムを書け

  1. src/main.rs
use std::io;

fn main() {
  println!("Input F temperature!");
  let mut f = String::new();
  io::stdin().read_line(&mut f).expect("Failed to read line.");
  let f: f64 = f.trim().parse().expect("Please type a number!");

  let c = (f - 32.0) * 5.0 / 9.0;
  println!("Fahrenheit {} is Celsius {}", f, c);
}

shell

Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
 Running `target/debug/branches`
Input F temperature!
911
Fahrenheit 911 is Celsius 488.3333333333333
  1. src/main.rs
use std::io;

fn main() {
  println!("Input integer n!");
  let mut  n = String::new();
  io::stdin().read_line(&mut n).expect("Failed to read line.");
  let n: u32 = n.trim().parse().expect("Plase type an intger!");

  let ans = fibb(n);
  println!("The kth fibbonacci number is: {}", ans);

}

fn fibb(k: u32) -> u32 {
  let ans:u32 = if k == 1 {
   1 } else if k == 2 {
   1 } else { fibb(k-1) + fibb(k-2)};

  ans
}

shell

Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
 Running `target/debug/branches`
Input integer n!
12
The kth fibbonacci number is: 144

2017年6月19日月曜日

Linear Algebra (D. Cherney et al.) 8日目

CC BY-NC-SA 3.0

Chapter 8. Determinants

8.1 The Determinant Formula

8.1.2 Pemutations (置換)

のような順序を考える集合の並び替えをpermutation(置換)という.ある置換は,全単射な写像であると考えることが出来る.

と書き下すことが出来る.置換には以下の重要な性質がある.
1. 要素数の集合の置換は個ある.
2. 任意の置換は,2つの要素の順番を交換する置換(特に互換という)の有限個の適用によって表現できる.
3. 任意の置換について,を表現する互換の個数は常に偶数か奇数で,偶数であるときを偶置換,奇数であるとき奇置換という.

Definition the sign function

置換に,その偶奇性を返す関数を符号関数といい

で定める.

Definition the determinant (行列式)

のdeterminant(行列式)を,

と定める.ただし,はの置換の集合とする.

Theorem 8.1.1

が,すべての要素がである行を一つ以上持つとき,.

Swapping rows

行基本変形によって行列式がどうなるか調べる.
行列の行を交換した行列をとする.ある置換について,とを交換した置換を考えると,あきらかに

したがって,とすると,

よって,行の交換によって,行列式は符号のみ変化する.

corollary

が2つ以上同じ行を持つとき,その2つを選んで交換した行列をとすると,

8.2 Elementary Matrices and Determinants

8.2.2 Row Multiplication

のある行を倍した行列をとすると,

8.2.3

のある行の倍を他の行に加えた行列をとすると,

8.2.4 Determinant of Products

行列に左からかけて基本変形を行う行列
1. : 行目と行目を交換する
2. : 行目を倍する
3. : 行目を倍して行目に加える

について,が成立する.
行列の被約階段行列に変形できるとき,それをと書く.が上の基本変形行列を左からけけてにできるとき,つまりとできるとき,
1. が可逆でないとき,にはすべての要素がである行が存在するので,.
2. が可逆であるとき,は単位行列で,.
行列の積の行列式はそれぞれの行列の行列式の積だから,

Theorem 8.2.2

は可逆でない

Basic Analysis (Jiri Lebl) 23日目 距離空間上の点列の極限

CC BY-NC-SA 3.0

7.3 Sequences and convergence

は距離空間とする.

7.3.1 Sequences

Definition 7.3.1

上の点列とはという写像.をと書く.またをとも書く.
が有界である

部分列は数列の部分列と同じように定義する.

点列の収束は数列の収束の一般化で,数列の場合は絶対値を距離としたのを,その距離空間での距離に置き換えただけで,したがって殆どの数列の収束に関する定理は点列の場合でも成立する.

7.3.2 Convergence in Euclidean space

この節では,距離はすべてユークリッド距離とする.

Proposition 7.3.7

について,と書くと,
が収束する 任意のに が収束する.

proof.


とする.任意のになるが存在する.
あるを固定すると,

が成立するから,はに収束する.
()
任意のに,なるが存在する.
が存在して,から,たしかに.

7.3.3 Convergencec and topology

Proposition 7.3.8

とする.
の任意の開近傍について,ならばなるがある.
proof. 略

Proposition 7.3.9

は閉集合で,がに収束するなら.
proof. 略

Proposition 7.3.10

で,
なるが存在する.
proof.


とProp. 7.3.9から成立

Prop. 7.2.20から,が存在する.の極限はである.

2017年6月18日日曜日

The Rust Programming Language 2nd 2日目 Example: Guessing Game

https://doc.rust-lang.org/book/second-edition/
Apache License Version 2.0

2. Guessing Game

数あてゲームを作る.
bash

cargo new guessing_gaame --bin

で新しいプロジェクトを作成する.ランダムな整数を生成するのにrandクレートを使うので,Cargo.tomlにrandを追加する.クレートはrustコードのパッケージであって,randはlibraryクレートと言って,他のプログラムで利用されるコードが入っている.

Cargo.toml

[dependencies]
rand = "0.3.14"

main.rs

use std::io;                 // 標準ライブラリのioを名前空間に追加.
                                        // std::io::stdin()をio::stdin()と省略できる.
use std::cmp::Ordering;
use rand::Rng;

fn main() {                            // Rustではfn <関数名>で関数を定義する.
                                       // Cと同じくmainが最初に実行される.

  println!("Guess the number!");        // 文字列をコンソールに書き出すマクロ.
                                        // !は関数でなくマクロを読んでいることを表している.
                                        // インデントは4スペースがいいらしいが色々と統一したいので2スペース
                                        // ;でexpressionの終わりを明示する.
                                        // Cなどの,行の終わりに;を打つ言語とはちょっと違うらしい(後述).

  let secret_number = rand::thread_rng().gen_range(1, 101); // thread_rng()がランダムなジェネレーターをつくる
                                                            // .gen_range(1,101)で範囲内の値で生成するようにする

  loop {                   // 中でbreakするまで繰り返す.カウンタを使わない分処理が早い
    println!("Please input your guess");

    let mut guess = String::new();      // 変数の宣言は'let'で行う. 'mut'によって変数guessを可変にする.
                                        // let foo=bar;などとすると,fooにはbarが代入されて以後変更できない
                                        // String::new()は長さが可変な文字列型Stringのassociated functionで,
                                        // 新しい空の文字列を作成する.

    io::stdin().read_line(&mut guess)   // 後述(1)
      .expect("Failed to read line");

    let guess: u32 = match guess.trim().parse() { // 後述 (2)
      Ok(num) => num,
      Err(_)  => continue,
    };

    println!("You guessed: {}", guess); // 変数を文字列に埋め込んで出力する方法はpythonと同じ

    match guess.cmp(&secret_number) {   // 後述 (3)
      Ordering::Less     => println!("Too small!"),
      Ordering::Greater  => println!("Too big!"),
      Ordering::Equal    => {
        println!("You win!");
        break;
      }
    }
  }
}

(1)

    io::stdin().read_line(&mut guess)   // 後述(1)
      .expect("Failed to read line");

io::stdin()は標準入出力のhandleのインスタンスを返す.そのインスタンスのメソッドread_lineが入力を読み取り,guessに文字列として代入する.代入先の変数は可変でなければならない.&はこの引数がreferenceであることを表していて,いちいち新しくメモリを割り当てさせない.referenceはChap.4で詳しく論じる.
一行目で行われた処理はguessに値を代入することだが,read_line()はio::Reuslt型の返り値を返す.Result型は’Ok’か’Err’の値しか取らない.’Ok’は処理が正常に行われたとき返され,’Err’はそうでないときに返される.Result型のexpectメソッドによって,実行時のインスタンスがErrであったときはexpectの引数である文字列を表示し,プログラムはクラッシュする.Resultのインスタンスにexpectをつけないとコンパイル時に警告される.

(2)

    let guess: u32 = match guess.trim().parse() { // 後述 (2)
      Ok(num) => num,
      Err(_)  => continue,
    };

let <変数名> :<変数型>によって,型を指定して変数を定義できる.
新しい変数guessをu32型として定義して,もとあったguessを数値に変換した値を新しいguessに代入する.(このように,同じ名前の変数を定義して,もとあった変数を加工した値を代入することをshadowingという.)
trim()メソッドによって文字列の始まりと終わりにある空白を削除し,更にparse()によって改行記号があればそれを削除する.parse()が正常に機能したか否かをmatch expressionによって条件分岐し,正常な場合は新しいguessに,古いguessを数値として代入する.異常な場合はcontinueによって直ちに次にループを実行する.
Err()の’‘はcatchall記号で,エラーの詳細が何であっても,Errならこれに一致する.

match A { B => b, C => c, D => d, ...};

は, A がXに等しいときxを返したり実行したりする.

(3)

    match guess.cmp(&secret_number) {   // 後述 (3)
      Ordering::Less     => println!("Too small!"),
      Ordering::Greater  => println!("Too big!"),
      Ordering::Equal    => {
        println!("You win!");
        break;
      }

cmpメソッドはもとのインスタンスと引数の大小比較を行い,std::cmp::Ordering型のインスタンス{Less,Greater,Equal}のどれかを返す.返されたインスタンスが何であるかによる条件分岐をmatch expressionで実現する.

2017年6月17日土曜日

The Rust Programming Language 2nd 1日目 Introduction

https://doc.rust-lang.org/book/second-edition/
Apache License Version 2.0

1. Introduction

1.2 Hello, World!

Creating a Project with Cargo

シェル上で

cargo new hello_cargo --bin

を実行して,カレントディレクトリ以下に”hello_cargo”プロジェクトのディレクトリが作成されて,その中には必要なファイルのテンプレートが入っている.”–bin”によってライブラリでなく実行ファイルを作成することを明示している.

hello_cargo/
 ├ cargo.toml : プロジェクトの情報を書く
 └ src/       : ソースコードを置くディレクトリ
   └ main.rs : ソースコードの拡張子はrs

cargo.tomlにはプロジェクトの情報を書く.

[package]
name = "hello_cargo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]

[dependencies]

[package]欄にはプログラムの名前と著者の情報を書く.
[dependencies]欄には,このプログラムが使用するcrate(他の言語でいうライブラリ)の名前を書く.ここに書かれたcrateをcargoがダウンロードしてきて,ビルド時にリンクしてくれる.

Building and Running a Cargo Project

cargo build

によってhello_cargo直下にtargetディレクトリ以下が作られ,ビルドされた実行ファイルはtarget/debug/hello_cargo である.

cargo run 

によって,ビルドしたら直ちに実行してくれる.ソースコードに変更がない場合,ビルドをやり直すことはせず,以前つくった実行ファイルをまた実行する.

Building for Release

“cargo build”でビルドされた実行ファイルはデバッグ用の機能が埋め込まれ,最適化もされていない.”cargo build –release”によって,最適化が行われた実行ファイルが”target/release”に作成される.