2017年7月22日土曜日

The Rust Programming Language 2nd 15日目 テスト1

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

Testing

Rustはコードの中にテストを書き込むことを許している.

How to Write Tests

testはRustの関数で,testでないコードが期待した通りに動いているか確かめる.test関数のbodyはふつう, 1.準備, 2.テストしたいコード, 期待する結果の3つを含んでいる.ここではtest attribute(属性)といくつかのマクロ,そしてshould_panic attributeを学ぶ.

The Anatomy of a Test Function

attributeはRustコードのメタデータで,chap.5 ですでにderiveを扱った.test attribute付きの関数がRustのテストコードである.関数をtest関数にするには,#[test]fnの上の行に書く.cargo testによってテストを実行し,test関数のどれが成功してどれが失敗したかを返す.
testの働きを実験を,自動生成されるtemplate testを通して見ていく.そのあと実際のtestを書いてみる.
ライブラリプロジェクトadderを生成すると,src/lib.rsにはすでにテストコードが書いてある.
src/lib.rs listing 11-1

#[cfg(test)]
mod tests {
  #[test]
  fn it_works() {}
  }
}

it_works() {}は何もしないから,テストを無事通過する.

shell

$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished dev [unoptimized + debuginfo] target(s) in 0.22 secs
     Running target/debug/deps/adder-ce99bcc2479f4607

running 1 test
test tests::it_works ... ok     // testsモジュールのit_worksが正常と言っている

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

   Doc-tests adder  // documentに対するテスト

running 0 tests     // docを書いていないのでテストは行われない

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured

失敗するテストを書いてみる.test functionがどこかでpanicするとテストは失敗する.
src/lib.rs listing 11-3

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }

    #[test]
    fn anoter() {
        panic!("Make this test fail");
    }
}

shell listing 11-4

running 2 tests
test tests::exploration ... ok
test tests::another ... FAILED

failures:

---- tests::another stdout ----
    thread 'tests::another' panicked at 'Make this test fail', src/lib.rs:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.

failures:
    tests::another

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured

error: test failed

test tests::anotherFAILEDだったと言っている.成功したit_worksには触れられず,anotherの失敗の理由と,失敗したtestの一覧が表示され,最後にtest全体の要約が表示される.testが失敗するのはpanicが生じたときだけではない次節では,panicは起きないが予期した結果と違った計算を行ったときエラーを出すマクロを学ぶ.

Checking Result with the assert! Macro

assert! macroはtest functionがfalseを返したとき場合にpanic!を呼び,testを失敗させる.

rectangle/src/lib.rs listing 11-5

#[cfg(test)]
mod tests {
  use super::*;  // tests modの外に有るstructをスコープに入れる

  #[test]
  fn larger_can_hold_smaller() {
    let larger = Rectangle { length:8, width: 7};
    let smaller = Rectangle { length:5, width: 1};

    assert!(larger.can_hold(&smaller));             // assert!(ture)
  }

  #[test]
  fn smaller_can_not_hold_larger() {
    let larger = Rectangle {length: 8, width: 7};
    let smaller = Rectangle {length: 5, width: 1};

    assert!(!smaller.can_hold(&larger))             // assert!(!false)
  }
}

#[derive(Debug)]
pub struct Rectangle {
  length: u32,
  width: u32,
}
impl Rectangle {
  pub fn can_hold(&self, other: &Rectangle) -> bool {
    self.length > other.length && self.width > other.width
  }
}

listing 11-5では,Rectangleのcan_holdメソッドが真となる場合と偽になる場合の両方を確かめている.計算の結果がfalseであることを確かめたいなら,assert!(!false)によって,確かにfalseである場合のみtestを通過させるようにできる.
shell

running 2 tests
test tests::larger_can_hold_smaller ... ok
test tests::smaller_can_not_hold_larger ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured

また,コードにバグを埋め込んでみる.ここではRectangle.can_holdの不等号演算子の一つを逆にしてみる.
self.length < other.length && self.width > other.width
結果は
shell

running 2 tests
test tests::smaller_can_not_hold_larger ... ok
test tests::larger_can_hold_smaller ... FAILED

failures:

---- tests::larger_can_hold_smaller stdout ----
        thread 'tests::larger_can_hold_smaller' panicked at 'assertion failed: larger.can_hold(&smaller)', src/lib.rs:10
note: Run with `RUST_BACKTRACE=1` for a backtrace.



failures:
    tests::larger_can_hold_smaller

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured

と,やはり失敗したtestの詳細と全体の要約を出力してくる.

Testing Equality with the assert_eq! and assert_ne! Macros

ある関数が適当なfuncが数値や文字列xxxを返すときにのみ通過するテストは,assert(func()== xxx)などとすれば書けるのだが,手間を省くためにassert_eq!(xxx, func())として同じ意味になるマクロassert_eq!が定義されている.また,assert_ne!(xxx, funct())func()の返り値がxxxでない場合のみ通過する.どちらのマクロも,テストを通過しなかったときには問題となっている関数の返り値と想定された値を出力する.例えば
src/lib.rs listing 11-7

pub fn add_two(a: i32) -> i32 {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_adds_two() {
        assert_eq!(4, add_two(2));
    }
}

は無事通過し,ここでadd_twoのbodyをa+3に書き換えてテストを再度実行すると
shell

test tests::it_adds_two ... FAILED

failures:

---- tests::it_adds_two stdout ----
        thread 'tests::it_adds_two' panicked at 'assertion failed: `(left == right)` (left: `4`, right: `5`)', src/lib.rs:11
note: Run with `RUST_BACKTRACE=1` for a backtrace.

と,左辺,すなわち予期した値は4であるのに,返り値が5であったとしてエラーを返してくる.
ここで我々はassert_eq!(xxx, func())と,左辺に左に予期した値,右に関数を書いたが,この順序が逆でも構わないし,両方が関数でも構わない.例えば
src/lib.rs listing 11-7-0

pub fn add_two(a: i32) -> i32 {
    a + 2
}

pub fn mut_3(a: i32) -> i32 {
    a * 3
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn mul_and_add() {
        assert_eq!(mut_3(4), add_two(10));
    }
}

はテストを通過する.

assert_eq!assert_ne!は内部で==!=演算子をそれぞれ使っており,また失敗時にはマクロの引数をdebug formattingによって出力する.ゆえに,比較される値はPartialE1Debug traitを実装していなければならない.全ての基本型と殆どの標準ライブラリ型はこれらのtraitを実装しているが,プログラマが実装したstructやenumにassert_eq!assert_ne!を適用するには,以上のtraitを実装しなければならない.しかしこれらのtraitはderivableだから,chap.5で見たように,#[derive(PartialEq, Debug)]定義時に注釈することで,簡単に実装できる.derivable traitについてはappendix Cに詳しい.

Custom Failure Messages

テストが失敗したときに好きなメッセージを出力させることが出来る.assert!は1つ,assert_eq!, assert_ne!は2つの引数を必ず取るが,さらに引数を与えると,それらはformat!マクロによって加工されるので,format stringと適当な変数を引数に渡すと,適当にパースして出力してくれる.例えば,人名を引数としてその人を歓迎する関数を作ってテストするときには以下のようなコードが考えられる.

src/lib.rs listing

pub fn greeting(name: &str) -> String {
  format!("Hello {}!", name)
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  fn greeting_contains_name() {
    let result = greeting("Carol");
    assert!(result.contains("Carol"));
  }
}

これはテストを通過する.greetingのbodyをString::from("Hello!")としてバグを入れると,
shell

test tests::greeting_contains_name ... FAILED

failures:

---- tests::greeting_contains_name stdout ----
        thread 'tests::greeting_contains_name' panicked at 'assertion failed: result.contains("Carol")', src/lib.rs:12
note: Run with `RUST_BACKTRACE=1` for a backtrace.

とエラーを生じる.assertionが失敗したことを言っているが,よりエラーを見やすくするために,greeting関数の返り値を表示するようにする.
src/lib.rs

#[test]
fn greeting_contains_name() {
    let result = greeting("Carol");
    assert!(
        result.contains("Carol"),
        "Greeting did not contain name, value was `{}`", result
    );    // 第二引数はプレースホルダー{}を持てる文字列で,
          // 第三引数以降がそのプレースホルダーに入る.
}

ここでまたテストを行うと
shell

test tests::greeting_contains_name ... FAILED

failures:

---- tests::greeting_contains_name stdout ----
        thread 'tests::greeting_contains_name' panicked at 'Greeting did not contain name, value was 'Hello'', src/lib.rs:12
note: Run with `RUST_BACKTRACE=1` for a backtrace.

と,確かにエラーメッセージが想定したとおりになる.

Checking for Panics with should_panic

予期した通りの値を返すかを確かめるのと同じくらいに,発生したエラーを予期したとおりに対処するか確かめるのは重要である.たとえばChap. 9, listing9-8で定義したGuess型で,そのinstanceは必ず1から100の値を取ることを約束したので,Guessのinstanceでその範囲から外れたものを作ろうとしたときには確かにpanicを起こすことを確かめたい.
これをshould_panic attributeを関数につけて実現する.shold_panicは,それがつけられた関数がpanicを起こすときにのみテストを通過するようにする.
src/lib.rs listing 11-8

struct Guess {
  value: u32,
}

impl Guess {
  pub fn new(value: u32) -> Guess {
    if value < 1 || value > 100 {
      panic!("Guess value must be between 1 and 100, got {}", value);
    }

    Guess {
      value
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  #[should_panic]
  fn greater_than_100() {
    Guess::new(200);
  }
}

これは確かにテストを通過する.
shell

running 1 test
test tests::greater_than_100 ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured

ここでnew()における条件を外すと,
shell

running 1 test
test tests::greater_than_100 ... FAILED

failures:

failures:
    tests::greater_than_100

test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured

と,正常にGuessの新しいinstanceが作られてしまうので,エラーを生じる.should_panicは,予期した形のpanicでなくともpanicを拾うとテストに通してしまうので,should_panicexpectedというパラメータを渡して,より厳密なテストを行うことが出来る.expectedには文字列が入って,panic時のメッセージにその文字列が現れるときのみテストを通すようにする.例えば
src/lib.rs listing 11-9

struct Guess {
  value: u32,
}

impl Guess {
  pub fn new(value: u32) -> Guess {
    if value < 1 {
      panic!("Guess value must be greater than or equal to 1, got {}.", value);
    }
    else if value > 100 {
      panic!("Guess value must be less than or equal to 100, got {}", value);
    }

    Guess {
      value
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;

  #[test]
  #[should_panic(expected = "Guess value must be less than or equal to 100")]
  fn greater_than_100() {
    Guess::new(200);
  }
}

をテストにかけると,確かにpanicが生じ,しかも値が100を上回るときのメッセージが与えられるから,テストを通過する.
また,if value < 1else if value > 100において数値と不等号を交換すると,

shell

test tests::greater_than_100 ... FAILED

failures:

---- tests::greater_than_100 stdout ----
        thread 'tests::greater_than_100' panicked at 'Guess value must be greater than or equal to 1, got 200.', src/lib.rs:8
note: Run with `RUST_BACKTRACE=1` for a backtrace.
note: Panic did not include expected string 'Guess value must be less than or equal to 100'

と,予期したメッセージと返されたメッセージが異なるため,panicが生じてもshould_panicはテストを通過させない.

以上でテストの書き方を学んだので,つぎはテストを行っているとき内部で何が起きているかとか,cargo testの様々なオプションを見ていくことにする.

2017年7月20日木曜日

MIT OCW, Fundamentals of Probability 14日目 モーメント母関数1

David Gamarnik, and John Tsitsiklis. 6.436J Fundamentals of Probability. Fall 2008. Massachusetts Institute of Technology: MIT OpenCourseWare, https://ocw.mit.edu. License: Creative Commons BY-NC-SA.

モーメント母関数からは逃げられなかったよ・・・

Lecture 14. Moment Generating FUnctions

momment generating function(モーメント母関数)とその類概念(probability generating function, characterstic function)はprobability distributionを1変数の関数で表現する方法の一つである.

1. Moment Generating Fucntions

1.1 Definition

Definition 14-1

random variable のmoment generating functionを

と定める.また,domain を,と定める.

がdiscrete random variableでPMFがならば

がcontinuous random variableでPMFがならば

1.2 The Domain of the Moment Generating Function

から,である.discrete random variableでならば,である.一方Cauchy distributino では,である.一般にを含む区間である.

1.3 Invension of Transforms

の定義から,においてが与えられればのdistributionが得られる.一方以外の点ではのdistributionはわからない.

Theorem 14-1 Inversion Theorem

(a) 上で有限なら,の固有のCDFを与える.
(b) で成り立つとき,は同じCDFを持つ.

1.4 Moment Generating Properties

の0における微分係数を考える.微分と積分の順序交換が可能と仮定すると


よって次モーメントはで計算できる.

1.5 The Probability Generating Function

Definition 14-2


probability generating functionという.普通である.

ならばとその微分係数がで存在するので,というPMFを持っているとき,

だから,

である.であればから容易にが得られる

1.6 Examples

Example

とすると,

Example

とすると,

Example

とすると,

1.7 Properties of Moment Generating Functions

Theorem 14-2

(a) なら
(b) が独立なら
(c) が独立でである確率が,である確率がであるとすると

proof.

(a)
(b)
(c)

Example: (Normal random variables)

(a) で,とする.で,
(b) とすると

inversion propertyから

2017年7月19日水曜日

The Rust Programming Language 2nd 13日目 GenericとTraits

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

Generic Types, Traits, and Lifetimes

同じロジックでも,扱う変数の型が違えばこれまで学んだ関数の定義方法では,型ごとに似たような関数をいくつも書かなければならない.このようなロジックの重複を解消するのがgenericで,変数の型に関係なく関数やstructを定義できる.
genericはすでにChap 6でOption<T>を, Chap. 8でVec<T>HashMap<K, V>を,Chap. 9でResult<T, E>を使った.これを一般化した用法をこの章では学ぶ.
まず,単純に同じロジックだが引数や返り値の型が違う二つの関数を見て,それをgenericによって一本化する.次に単純に一本化できない場合の解決法を学び,最後にlifetimeという,reference同士の関係性を記述するgenericの一種を導入し,リ方法を学ぶ.

Generic Data Types

Using Generic Data Types in Function Definitions

src/main.rs listing 10-4a

fn largest(list: &[i32]) -> i32 {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

という関数を考える.これはi32のリストのreferenceを取ってその最大値(i32)を返す関数で,['y', 'm', 'a', 'q']と言うようなリストを引数に取ることはできないので,型だけを(list: &[char]) -> charとしたような関数を更に定義しなければならない.これは明らかに無駄なので,genericによって一本化することを考える.
引数や返り値をgeneric型にするには,そのgeneric型の変数の型名と変数自体の名を関数宣言の際に定義し,関数の内部でその変数名を使ってロジックを書く.変数の型名にはほとんど必ずTを使う.具体的な記法は
fn largest<T>(list: &[T]) -> T {
のようになる.改めてlargestを書き直したのがlisting 10-5aである.しかしこれはコンパイルできない.

src/main.rs listing 10-5a

fn largest<T>(list: &[T]) -> T {
  let mut largest = list[0];

  for &item in list.iter() {
    if item > largest {
      largest = item;
    }
  }
  largest
}

shell

error[E0369]: binary operation `>` cannot be applied to type `T`
  |
5 |         if item > largest {
  |            ^^^^
  |
note: an implementation of `std::cmp::PartialOrd` might be missing for `T`

とエラーが出る.これは任意の型Tに不等号の演算が定義されていないことが原因で,Tの取りうる値をプログラマが制限しなければならない.そのため,標準ライブラリのもつtrait std::cmp::PartialOrdを使うようにする(後述).

Using Generic Data Types in Struct Definitions

structの定義にもgenericを使える.
src/main.rs listing 10-6a

struct Point<T> {
  x: T,
  y: T,
}

fn main() {
  let integer = Point {x: 5, y: 10};
  let float = Point {x: 1.0, y: .40};
}

listing 10-6では,generic型の型名をTしか決めておらず,x, yは1つのinstanceでは必ず同じTの型しか持てない.x, yがそれぞれ異なる型の値を持てるようにするには,generic型の名前を予め二つ用意する.
src/main.rs listing 10-8

struct Point<T, U> {
  x: T,
  y: U,
}

fn main() {
  let both_integer = Point {x: 5, y: 10};
  let both_float = Point {x: 1.0, y: 4.0};
  let integer_and_float = Point{x: 5, y: 4.0};
}

は正常にコンパイルできる.generic型の型名はいくつあってもいいが,コードを読んで把握しづらくなるほど多いようならロジック自体を考え直すべき.

Using Generic Data Types in Enum Definitions

structと同様に,enumもgeneric型をそのvariantsに持てる.Option<T>がこれを行っているのはすでに見た.Rustは変数を取らないときにはgeneric型をvariantに入れないことを許しているから

enum Option<T> {
  Some(T),
  None,
}

というふうにOption<T>を定義できる.また,あるvariantに入る型と別のvariantに入る型が異なっている場合にも

enum Result<T, E> {
  Ok(T),
  Err(E),
}

と記述できる.

Using Generic Data Types in Method Definitions

Chap.5 でやったように,struct やenumにmethodを定義できるが,これにもgenericが使える.例えば
src/main.rs listing 10-9

struct Point<T> {
  x: T,
  y: T,
}

impl<T> Point<T> {
  fn x(&self) -> &T {
    &self.x
  }
}

fn main() {
  let p = Point {x: 5, y: 10};
  println!("p.x = {}", p.x());
}

また例えば
src/main.rs listing10-10

struct Point<T, U> {
  x: T,
  y: U,
}

impl<T, U> Point<T, U> {
  fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
    Point {
      x: self.x,
      y: self.y,
    }
  }
}

fn main () {
  let p1 = Point {x: 5, y: 10.4} ;
  let p2 = Point {x: "Hello", y: 'C'};  
  let p3 = p1.pixup(p2);
}

は正常に実行できる.

Performance of Code using Generics

Rustはコンパイル時にgenericを具体的な型のコードたちに変換するので,genericが実行時のオーバーヘッドになることはない.Rustのこの働きをmonomorphizationという.
たとえば

let integer = Some(5);
let float = Some(5.0);

をコンパイルするとき

enum Option_i32 {
    Some(i32),
    None,
}

enum Option_f64 {
    Some(f64),
    None,
}

fn main() {
    let integer = Option_i32::Some(5);
    let float = Option_f64::Some(5.0);
}

のように内部で変換する.

Traits: Defining Shared Behavior

traitは型の振る舞いを抽象化する.つまり複数の型に同時にメソッドを定義できる.また関数の引数などにgeneric型を使っているときtraitによってその引数が取れる型の範囲を制限して,Using Generic Data Types in Function Definitionsでみたエラーに対処することができる.

Defining a Trait

型のふるまいは型に実装されているメソッドたちによって決まる.異なった型たちが同じ名前のメソッドを持っているとき,その型たちは振る舞いを共有していると考えることが出来る.traitによって複数の型に同じ名前のメソッドを同時に定義できる.例えばNewsArticle型とTweet型を考える.両者ともに,そのインスタンスの要約を返すメソッドsummaryを,summarizable traitによって持たせる.traitはmoduleのように定義するが,body blockにはsignatureだけ書く.
src/lib.rs listing 10-11

pub trait Summarizable {
  fn summary(&self) -> String;  // method signatureのみ書く
  fn author(&self) -> String;   // 複数のメソッドも書ける.
  fn content(&self) -> String;  // 1行に一つのmethod signatureを書き,セミコロンを打つ.
}

Implementing a Trait on a Type

Summarizable traitを定義したところで,型にtraitを実装する.通常のメソッド定義は
impl NewsArticle { fn summary...}と書くが,traitを実装するときは
impl Summarizable for Newsarticle { fn summary signature { }} と書く.fn summary signature { }の中に実際のロジックをコーディングする.

具体的な例:
lib.rs listing 10-12

pub struct NewsArticle {
  pub headline: String,
  pub location: String,
  pub author: String,
  pub content: String,
}

impl Summarizable for NewsArticle {
  fn summary(&self) -> String {
    format!("{}, by {} ({})", self.headline, self.author, self.location)
  }
}

pub struct Tweet {
  pub username: String,
  pub content: String,
  pub reply: bool,
  pub retweet: bool,
}

impl Summarizable for Tweet {
  fn summary(&self) -> String {
    format!("{}: {}", self.username, self.content)
  }
}

こうしてSummarizableNewsArticleTweetに実装できた.それぞれの型のinstanceにドット記法でSummarizableの中のメソッドを呼べる.

let tweet = Tweet {
    username: String::from("horse_ebooks"),
    content: String::from("of course, as you probably already know, people"),
    reply: false,
    retweet: false,
};

println!("1 new tweet: {}", tweet.summary());

1 new tweet: horse_ebooks: of course, as you probably already know, people.を出力する.

これまではすべてをlib.rsに書いてきた.これらをaggregatorというcrateにして,他の場所にあるWeatherForecast structにSummarizable traitを実装したい場合,Summarizableをまずインポートする.
lib.rs listing 10-13 例

extern crate aggregator;

use aggregatro::Summarizable;

struct WeatherForecast {
  high_temp: f64,
  low_temp: f64,
  chance_of_precipitation: f64
}

impl Summarizable for WeatherForecast {
  fn summary(&self) -> String {
    format!("The high will be {}, and the low will be {}. The chance of precipitation is{}%", self. high_temp, self.low_temp, self.chance_of_precipitation)
  }
}

traitとtypeがともにexternalであるとき,そのtypeにtraitを新たに実装することはできない.例えば,Vecはexternal traitでDisplayはexternal traitだから,VecDisplayを実装することはできない.こうしたルールをOrphan ruleという.

Default Implementations

traitを定義するとき,予めロジックを決めておいて,改めて型にtraitのメソッドを実装しない限りそのデフォルトのロジックをその型のメソッドとすることが出来る.Default implementationという.そのためには,listing 10-11ではセミコロンで止めていおいたメソッドのsignatureを,実際のロジックまで書くようにし,
lib.rs listing 10-14

pub trait Summarizable {
  fn summary(&self) -> String {
    String::from("(Read more...)");
  }
}

さらに型への実装で{ }を空白にする. impl Summarizable for NewsArticle {}仮にここでtraitの定義とは別のロジックを書いたら,新しいロジックが優先される.

default implementationはそのtraitの他のメソッドを,デフォルトが定義されていなくても,呼ぶことが出来る.例えば

pub trait Summarizable {
  fn author_summary(&self) -> String;

  fn summary(&self) -> String {
    format!("(Read more from {}...)", self.author_summary())
  }
}

このSummarizableを使うときは,author_summaryを型に実装する.

impl Summarizable for Tweet {
    fn author_summary(&self) -> String {
        format!("@{}", self.username)
    }
}

Trait Bounds

traitをgeneric type parameterと使うことも出来る.generic typeは野放図に使うとUsing Generic Data Types in Function Definitionsのようなエラーを生じることがあるので,そのgeneric typeを取れる型が特定のtraitを実装されている型であると制限して,その制限下のどの型でも動くとコンパイラが判断すれば,コンパイルしてくれる.こうしてgeneric typeの型を制限することを,”generic typeにtrait boundsを指定する”という

例えばlisting 10-12でsummarizableNewsArticleTweetに実装したので,NewsArticleTweetを引数に取るnotifyという関数をgenericを使って定義する.generic type parameter TSummarizable traitが実装されている型に制限するには,定義時に<T: Summarizable>とすれば良い.例えば

pub fn notify<T: Summarizable>(item: T) {
  println!("Breaking news! {}", item.summary())
}

また,SummarizableDisplayを同時に実装している型にgeneric typeを制限したいときには<T: Summarizable + Displayとする.
fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {
というふうに複数の引数にそれぞれのtrait boundsを設定することが可能だが,読みづらいのでwhereキーワードを使って

fn some_function<T, U>(t: T, u: U) -> i32
  where T: Display + Clone,
        U: Clone + Debug
{

というふうに定義することも可能である.

Fixing the largest Function with Trait Bounds

Using Generic Data Types in Function Definitionsで見たエラーを実際に修正しよう.

error[E0369]: binary operation `>` cannot be applied to type `T`
  |
5 |         if item > largest {
  |            ^^^^
  |
note: an implementation of `std::cmp::PartialOrd` might be missing for `T`

不等号演算子が定義されている型がTに来るかもしれないというのでエラーメッセージが出たので,不等号を定義する標準ライブラリのtrait, std::cmp::PartialOrdをtrait boundとしてみる.
fn largest<T: PartialOrd>(list: &[T]) -> T {
しかし,これでもエラーが出る.

error[E0508]: cannot move out of type `[T]`, a non-copy array
 --> src/main.rs:4:23
  |
4 |     let mut largest = list[0];
  |         -----------   ^^^^^^^ cannot move out of here
  |         |
  |         hint: to prevent move, use `ref largest` or `ref mut largest`

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:6:9
  |
6 |     for &item in list.iter() {
  |         ^----
  |         ||
  |         |hint: to prevent move, use `ref item` or `ref mut item`
  |         cannot move out of borrowed content

cannot move out of type [T], a non-copy array.に着目する.TCopy traitを実装していないため,largest = list[0]が実行できなかったことを示している.よってtrait boundにCopyを加えることで,コンパイルが可能になる.

src/main.rs listing 10-15

use std::cmp::PartialOrd;

fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
    let mut largest = list[0];

    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }

    largest
}

fn main() {
    let numbers = vec![34, 50, 25, 100, 65];

    let result = largest(&numbers);
    println!("The largest number is {}", result);

    let chars = vec!['y', 'm', 'a', 'q'];

    let result = largest(&chars);
    println!("The largest char is {}", result);
}

Copyをtrait boundに加えたくない場合,かわりにCloneをtrait boundsに加えても良いが,Cloneはheap構造を使うので,性能が落ちる可能性がある.

2017年7月18日火曜日

MIT OCW, Fundamentals of Probability 13日目 多次元の正規分布1

David Gamarnik, and John Tsitsiklis. 6.436J Fundamentals of Probability. Fall 2008. Massachusetts Institute of Technology: MIT OpenCourseWare, https://ocw.mit.edu. License: Creative Commons BY-NC-SA.

Lecture 14. MOMENT GENRATING FUNCTIONS

モーメント母関数.Laplace変換とか出てきたから飛ばす.そのうちやりたい(願望)

Lecture 15. MULTIVARIATE NORMAL DISTRIBUTIONS

1. Background On Positive Definate Matrices

Definition 15-1

の正方行列とする.
(a) positive definate(正定値) である
このときと書く.
(b) nonnegative definate(半正定値) である
このときと書く.

以下の事実は有名である.

(a) symmetric matrixは個の実eigenvalueを持つ.
(b) positive definate ならeigenvalueは個存在し全て正.
(c) nonnegative definateならeigenvalueは個存在し全て非負
(d) symmetri matrixの全てのeigenvalueにはそれぞれ実eigenvectorがあって,異なったeigenvalueに対応するeigenvectorは直行し,複数eigenvalueが重複しているときその重複度の分直行するeigenvectorがある.
(e) 以上から,symmetric definateなら基底変換によって対角化出来る.

上の事実から, spectral decomposition(スペクトル分解) が得られる.すなわち

任意の対称行列は,のeigenvalue, をそれぞれのeigenvalueに対応するeigenvectorとすると,

と書ける.

また,nonnegative definite matrixであるならだから平方根が実数で,

が定義できる.このとき

(a) はsymmetric
(b) である.symmetric square rootという.
(c) のeigenvalueたちはである.よって,がpositive(nonnegative) definite がpositive(nonnegative) definite.

特にがpositive definiteならばで,

が定義できて, ゆえ, である.

2. DEFINITION OF THE MULTIVARIATE NORMAL DISTRIBUTION

全ての要素がrandom variableであるベクトルをrandom vectorと呼び.全ての要素がrandom variableである行列をrandom matrixと呼ぶ.
multivariate normal distributionの表現方法3つを取り上げ,それらの同値性を確かめる.最初に,最もわかりやすいがいろいろな操作が面倒な表現を与える.

Definition 15-2

random vector nondegenerate (multivariate) normal distributionをもつ
joint PDF が,あるベクトルとpositive definite

と書ける.

さらに,操作が簡単な生成的な定義を与える.

Definition 15-3

random vector (multivariate) normal distributionをもつ
あるmatrix とベクトル, そして要素がに独立に従うランダムなベクトルによって,

と書ける.

最後に与える定義は最も難しいが,最も美しいと言う人もいる.

Definition 15-4

random vectro (multivariate) normal distributionをもつ
任意のベクトルにrandom variable がnormal.

Definition 15-2でnondegenerateという語を使ったが,これはという意味である.はNormalだが,これはDef. 15-2の方法では表現できないので,nondegenerateという制限を加えている.

3. MEANS AND COVARIANCES OF VECTOR RANDOM VARIABLES

Definition 15-5

random vector のexpectationを

とする.同様にrandom matrix についてもexpectationを

とする.

random vector があるとき,covariance matrix(分散行列, 分散共分散行列)を,

と定める.成分はである.

4. KEY PROPERTIES OF THE MULTIVARIATE NORMAL

Theorem 15-1 (証明略)

がmultivariate normalであるとする.は第要素の平均と考えることが出来る.このとき
(a) はnormalで,平均は
(b)
(c) 行列で,とする.はdef. 3の意味でmultivariate normalであって,平均は, covariance matrixはである.
(d) ならはnondegenerate multivariate normalであって,である.
(e) のjoint PDF の平均とcovarianceだけで決まる
(f) のそれぞれの要素がuncorrelatedすなわちが対角行列それぞれが独立
(g)
かつ ならば

(i)
(ii) とすると,と独立で,またと独立.
(iii)

2017年7月17日月曜日

MIT OCW, Fundamentals of Probability 12日目 積分の順序交換

David Gamarnik, and John Tsitsiklis. 6.436J Fundamentals of Probability. Fall 2008. Massachusetts Institute of Technology: MIT OpenCourseWare, https://ocw.mit.edu. License: Creative Commons BY-NC-SA.

Lecture 13 Product Measure and Fubini’s Theorem

1. Product Measure

と2つのprobability spaceを考える.ふたつのprobability spaceで独立にexperimentを行うとき,”joint experiment”とでも言うものを考え,それに対して新たなprobability spaceを与える.

1.1, 1.2, 1.3 The Sample Space, -Field and Measure of the Joint Experiment

明らかに新たなsample spaceは.
であれば,新しいprobability spaceでもという確率が知りたいので,新しい-fieldを以下のように定義する.

Definition 13-1


上の-fieldである.はデカルト積ではない.
さらに,上のprobability measureを定義する.独立性を仮定しているから,

が成り立たなければならない.

Theorem 13-1 (証明略)


を満たすは唯一つ存在する.このとも書き,product measureと呼ぶ.

1.4 Beyond Probability Measures

の可算個の分割で,そのすべての分割にmeasure が有限であるようにできるとき,-finiteという.たちが-finiteであるとき,Theorem 13-1は成立する.

1.5 The Product Measure on

を2つ考えて節1のように新しいmeasure space

を定義できる.ただしはLebesgue measureとする.は2次元Lebesgue measureという.
ところでの開集合全体から導からる-fieldとして定義しても同じことである.

2. Fubini’s Theorem

Lebesgue積分の順序交換ができる条件を論じる.Lebesgue積分の勉強をしたいわけではないので結論だけ見る.はmeasurableとする.これは任意のという条件に同値.
わかりやす measurable functionの例に

(a) 連続なはmeasurable
(b) measurable setのindicator functionはmeasurable
(c) measurable functionたちの加減乗算と極限操作はmeasurable

Theorem 13-2

は非負かつmeasurableで,はこの上のproduct measureとする.このとき

(a) の関数としてmeasurable
(b) の関数としてmeasurable
(c) の関数としてmeasurable
(d) の関数としてmeasurable
(e)

Theorem 13-2はが非負であると仮定していて,積分がであることを禁じていない.関数がintegrableとは,積分が未満の実数に確定することであった.関数の絶対値の二重積分がintegrableであるとき,順序交換できるというのがTheorem 13-3の主張である.

Theorem 13-3

がemasurableで,かつ

であるとする.このとき

(a) の関数としてintegrable
(b) の関数としてintegrable
(c) となるが存在する.
(d) となるが存在する.
(e)

4. An Application

基本的な確率論の定理をFubini’s Theoremを使って証明する.

を非負なrandom variableとする.このとき

を示す.

proof.

とする.このとき

Fubini’s theoremを適用して

というのはを固定しての関数と考えているので,
よって
以上より

(Fubini’s theoremが使える条件をみたしているかの判定は略した)

2017年7月16日日曜日

MIT OCW, Fundamentals of Probability 11日目 Lebesuge積分と収束定理

David Gamarnik, and John Tsitsiklis. 6.436J Fundamentals of Probability. Fall 2008. Massachusetts Institute of Technology: MIT OpenCourseWare, https://ocw.mit.edu. License: Creative Commons BY-NC-SA.

Lecture 11 Abstract Integration -I

Lebesgue 積分について論じる.

1. Preliminaries

measure space について,を定義する.の(での)Lebesgue integralというが,これをとかと書くことも有る.

Special cases:

(a) がprobability spaceでがmeasurableなら,
(b) において,がBorel sets, がBorel measureとするとき,と書くことが有る.これはRiemann積分の一般化である.

The Program:

を以下の段階に沿って定義する.

(a) が非負で値域が有限集合な関数(simple function, 単函数)について,単に重み付きの和として積分を定める.
(b) 非負なを,simple functionによって下から近似して,その極限で積分を定める.
(c) 一般のについて,と正部と負部にわけてそれぞれ積分し,とする.

上の積分についてのみ論じるが,あるにおける積分は単に

とすればよい.ただしとする.
以後,ある性質について,であるとき,”Pはa.e. (almost everywhere, ほとんどいたる所) に成立する”という.特にがprobability measureであるとき,a.s. (almost surely, ほとんど確かに)と呼ぶ.例えばとは,と同値である.
同様に,函数とはのことだが,とは,ということである.また””によって,任意のが広義単調増加数列で,に収束することを示し,がほとんどすべての点でに広義単調増加収束するということである.

2. The Main Result

The Programで挙げた(a), (b), (c)で,(c)においてである場合以外,かならず積分値がの元に確定する.以下は重要な定理であるが,証明は略す.左に一般のmeasureに成立する命題を,右に特に確率論の記法で書いたその命題を記す.

Theorem 11-1

9, 9’をMonotone Convergence Theorem(MCT, 単調収束定理)という.これにのみあとで証明を与える.

The Riemann Integral

Riemann積分の定義はすでにやった.http://37ma5ras.blogspot.jp/2017/06/basic-analysis-jiri-lebl-16.html.
Riemann積分はほとんど至るところ連続な函数でしか定義できない.Lebesgue積分はこの問題を解決する.

Example

とする.とする.の任意の分割を考える.は必ず有理数と無理数を含むから,Darboux和はが必ず成立.よっていかなる分割にもDarboux上下和は一致せず,Riemann積分不能.一方上のuniform distributionとrandom variable を考えると,で,.

4.The Integral of a Nonnegative Simple Function

Definition 11-2

simple function(単函数)

このとき

と書ける.このような表現はいくらでも作れるが,がすべて異なった値で,が互いに素である表現は唯一つで,このような表現をcanonicalという.canonical表現ではである.

Definition 11-3

がsimple functionであって上の様に表現するとき,その積分を

と定める.

がprobability measure であるとすると,simple function をsimple random variableとよび,その積分と書かれ,

である.仮にの元がそれぞれ異なるとき,つまりcanonicalであるとき

が成立する.

4.2 Proof of the Monotone Convergence Theorem

property 9の,probability measureの場合をsimple functionに示す.
と表現したsimple function を考える.
なるnonnegative measurable functionの列とする.が無限である場合と有限である場合に場合分けする.

(i) であるとき,あるということである.このについて

という集合列を考える.であって,measureの連続性から.またである.Theorem 11-1-4から

よって

(ii) とする.常にであって,とする.finite additivityからである.なる整数を固定する.

とするとで,連続性からから.
であって,

だから,.
したがって

極限を取って

は任意だから

一方から.
以上より

5. The Integral of a Nonnegative Function

非負関数の積分は,をsimple functionによって下から近似して定めることはすでに述べた.

Definition 11-4

measurable について,とする.

と積分を定める.

Lecture 12 Abstract Integration -II

この章では重要な定理が証明されているが,関数がsimple functionである場合以外は省略する.

1. Borel-Cantelli Revisited

Borel-Cantelliの補題はすでに述べたがもう一度定式化する.http://37ma5ras.blogspot.jp/2017/07/gamarnik-tsisiklis-fundamentals-of_8.html
特に第一の主張について論じる.
をevent のindicator functionとする.であって,を仮定する.というrandom variableは非負でによって増加列をなす.さらに

と各点収束する.Monotone Convergence Theoremとexpectationの線形性から

であって,である.が有限回起きる確率が1ということであって,すなわちが無限回起きる確率が0ということである.

2. Connections between Abstract Integration and Elementary Definitions of Integrals and Expectations

2.2 Evaluating Expectations by Integrating on Different Spaces

というprobability spaceを考える. をその上のrandom variableとすと,という新しいprobability spaceが現れる.ここでのBorel sets, のprobability law

である.measurableなを定義し,また新たなprobability space を定める. は3つの方法で計算できる.

Theorem 12-1

proof. がsimple functionである場合のみ示す.

とする.定義より

同様に

の定義より,

以上によって示せた.

2.3 The Case of Continuos Random Variables, Described by PDFs

がcontinuousであるとは,そのCDFが

というふうに,非負でmeasurableなで書けることであった.このとき

が成立する.がRiemann積分可能でが区間なら単にと書ける.

Theorem 12-2

はmeasurableで非負であるか,ならば

が成立する.

proof.

は定義であるから,を示す.
がsimple functionで,と書けるときのみ示す.

から,成立.

Fatou’s Lemma

という2つのrandom variableがあるとき,であって,expectationをとると.したがって
が成立する.
Fatouの補題はこれに無限個のrandom variableと極限操作を入れて出来る命題である.

Theorem 12-3

なるrandom variableとする.このとき
(a) であるなら
(b) であるなら

proof.

(a)のみ示す.を固定し,

expectationを取ってからを考えて

は非負であり,によって広義単調増加である.またに収束する.両辺の極限を取って,

左辺はMonotone convegence theoremからに収束し,

から

4. Dominated Convergence Theorem(DCT, 優収束定理)

Theorem 4. (DCT)

に各点収束するというrandom variableの列を考える.があるなら,

proof.

だから,両辺にFatou’s Lemmaを適用して

ゆえに

よってが存在して,に等しい.

DCTの特別な場合に,Bounded Covergence Theorem(BCT, 有界収束定理)がある.これはという定数としたとき,すなわちであるならを主張する.

Corollary 12-1

ならば

が成立する.

proof.

Monotone Convergence Theoremをに適用し

とすれば. で,これにDCTを適用する.