MATHGRAM

主に数学とプログラミング、時々趣味について。

[Rust] 練習で正規分布描いてみた [gnuplot]

Rust楽しいです.

自分はまだプログラミングをちゃんと勉強しはじめて1年ちょいしか経っておらず, しかもほぼpythonしか触れてこなかったので, トレイトとか寿命とか所有権とかの概念に対してハッキリとしたありがたみを感じることができてません.

Rustの強みであるらしい, “安全性、速度、並行性” を確かな意味で理解するためにこれからしっかり勉強していきたいと思います.

とりあえず, コンパイラのおかげで無駄なものがなくなっていく感じがすごい気に入ってる. (小並感)

環境

コード

コメントにも書いていますが, x軸の値を持つベクトルを作る時に,

let mut x: Vec<f64> = vec![];
    let mut n = -3.0_f64;
    for i in 0..60 {
        x.push(n);
        n += 0.1;
    }

こんな書き方しちゃってます. なんか1行で書ける気がしてならないのですが, 15分くらいggってもわからなかったのでこのままです. わかったら更新します.

以下全コード.

extern crate gnuplot;
extern crate nalgebra;

use std::f64;
use std::vec::Vec;

use gnuplot::{Figure, Color};

fn main() {
    // 平均 0, 分散 1 としてインスタンス化する.
    let mut norm = NormalDistribution::new(0.0_f64, 1.0_f64);
    let mut x: Vec<f64> = vec![];
    let mut n = -3.0_f64;

    // ここで "i を 使ってないけどいいの?" と warning が出る.
    // -3.0 から 3.0 の 0.1 刻みのベクトルを作りたかったのだがどうしたものか.
    // この書き方はすごいセンスがない気がする.
    for i in 0..60{
        x.push(n);
        n += 0.1;
    }

    // 一応使っておく.
    norm.show_info();

    // グラフの描画.
    norm.plot(&x);
}

struct NormalDistribution {
    mu : f64,
    sigma : f64,
}

impl NormalDistribution {
    fn new(mu: f64, sigma: f64) -> NormalDistribution {
        NormalDistribution{mu: mu, sigma: sigma,}
    }

    // 与えられた x(ベクトル) に対して, 正規分布に従った y(ベクトル) を返す関数.
    fn calc(&mut self, x: &Vec<f64>) -> Vec<f64> {
        let mut y: Vec<f64> = vec![];
        for e in x{
            let a = - (e - self.mu).powi(2) / (2.0_f64 * self.sigma.powi(2));
            let b = (2.0_f64 * f64::consts::PI).sqrt() * self.sigma;
            y.push( a.exp() / b );
        }

        y
    }

    // 平均と分散をみる関数.
    // 書き始めに練習として書いたものなので, 実際いらない.
    fn show_info(&mut self){
        println!("------- Information -------");
        println!("Average: {}, Variance: {}", self.mu, self.sigma);
        println!("---------------------------");
    }

    // 一番勉強したかった, メインのplot関数.
    fn plot(&mut self, x: &Vec<f64>) {
        let mut fg = Figure::new();
        let y: Vec<f64> = self.calc(&x);

        fg.axes2d().lines(x, &y, &[Color("blue")]); //xはポインタで受けてるので&がない.

        // "png" 設定で画像を保存する.
        fg.set_terminal("png", "NormalDistribution.png");
        fg.show();
    }
}

生成された画像がこちらです.
f:id:ket-30:20170201020630p:plain:w400:h400
問題なし. まだまだ全然ですが, なんとか一歩目は踏み出せたような気がします.

そういえば “nalgebra” 使ってなかった. 今度の練習で使っていこうと思います.

参考しているサイト

おそらくこれから何度も読むであろう参考元たち.

とりあえず本家のドキュメントと,

Qiitaの記事
Rustのポインタ(所有権・参照)・可変性についての簡単なまとめ - Qiita
Rustのstruct、traitの使い方 - Qiita

うさぎさん様のブログ
Rust で k-means クラスタリング - StatsFragments
(k-means以外もたくさん実装してます)

で勉強させてもらってます.

有意義な記事, ありがとうございます.

以上です.