スキップしてメイン コンテンツに移動

Rustで科学計算 (2) Vec型

1. 配列とVec型

Rustの配列は, その長さがコンパイル時に既に固定されている必要があります. 従って, 最初から長さのわかっているベクトルを扱う場合には, 例えばその長さNを const N: usize = 128; とコンパイル時定数として導入することで, 素直に配列をつくることができます.
const N: usize = 128;
fn main() {
    let x: [ f64; N ] = [ 0.; N ];
}
一方, コンパイル時には長さが決まっておらず実行時に動的に決定される場合, または実行時にコマンドライン引数として長さを与えたい場合, コンパイル時には配列の長さが決まっていない訳なので, それを配列として実現することはできません. そのような状況ではVec型 (Vectorとも) を利用しましょう.

2. Vec型の宣言と要素の追加, 参照, 削除

例えば要素が既知のi32型を要素とするVec型変数a
let a: Vec<i32> = vec![ 0, 1, 2, 3, 4 ];
により宣言できます. あるいは, f64型を要素として持つことのできる空のVec型変数vを宣言するには
let mut v: Vec<f64> = Vec::new();
とします. いま変数vには何も要素がないので, そこに要素を追加するには
v.push(0.0)
とすればよいです. 要素をpushするためには変数がmutableであることが必要です. また, Vectorの要素の型はすべて共通でなければなりません. なお, あらかじめvectorの要素数が, 例えば上限128と見当がついているのならば
let mut v: Vec<f64> = Vec::with_capacity(128);
とした方が高速に動作します. もちろんこの場合でも128を超えて要素を追加することは可能です.
Vector vの要素の値は配列と同じくv[i]によりアクセスできます. 要素数がNのとき, 引数iは0からN-1までの値を取り, その範囲外の要素にアクセスしようとするとpanicが引き起こされます.
vector vi番目の要素を削除したい場合, 削除後に要素を左詰めで繰り上げる場合は
v.remove(i);
を, 削除後空いた場所にvの最後の要素を詰める場合は
v.swap_remove(i);
とします. 後者の方が高速に動作します.

3. Vectorを引数とする関数

例えばVector vを定義し, それを表示する関数outputに代入する次のコードは問題なくコンパイルを通ります.
fn main() {
    let n: usize = 16;
    let v: Vec<f64> = Vec::new();
    for i in 0..n {
        v.push(i as f64);
    }
    output( n, v );
}
fn output( n: usize, v: Vec<f64> ) {
    for i in 0..n {
        print!("{} ", v[i] );
    }
}
ところが, main関数の中で, output( n, v );に続いてvector vを利用すると, コンパイルエラーとなりバイナリファイルが生成されません. これは, 関数outputにvectorを代入する際に所有権が移行 (move) し, 関数outputのスコープから出た時点でvがメモリから消去されるからです. これを回避するにはもちろん借用を利用すればよい訳です.
fn main() {
    let n: usize = 16;
    let v: Vec<f64> = Vec::new();
    for i in 0..n {
        v.push(i as f64);
    }
    output( n, &v );
}
fn output( n: usize, v: &Vec<f64> ) {
    for i in 0..n {
        print!("{} ", v[i] );
    }
}
関数の中でvectorの値を変更したい場合は, mutableな借用を利用することになります.
fn main() {
    let n: usize = 16;
    let v: Vec<f64> = Vec::new();
    for i in 0..n {
        v.push(i as f64);
    }
    times2( n, &mut v );
    output( n, &v );
}
fn times2( n: usize, v: &mut Vec<f64> ) {
    for i in 0..n {
        v[i] = v[i] * 2.;
    }
}
fn output( n: usize, v: &Vec<f64> ) {
    for i in 0..n {
        print!("{} ", v[i] );
    }
}

4. その他の操作

Vec型xの長さはx.len()で取得できます.
その他の操作に関しては公式 (英語), またはQiita記事がよくまとまっています.

コメント

このブログの人気の投稿

matplotlib.histのnormedが変

以下の内容はPython 3.5.2 + matplotlib 1.5.1およびPython 3.6.2 + matplotlib 2.0.2で検証した. 作業日は2017年10月22日, 前者はUbuntu 16.04 on Win10 (WSL), 後者はDebian 8.9 (Anaconda). 規格化したいのにできない なにか数値の列 data があったとして, そのヒストグラムをmatplotlibでプロットしたいとする. 普通に plt.hist( data ) とすると, これは縦軸が各bin内に入るデータ点が何個あるかを表すことになる. これをデータ総数 len(data) で規格化したプロットにしようと思って plt.hist( data, normed=True ) または normed=1 とかやっちゃうと, 思った通りのアウトプットにならずに頭を傾げることになる. 例えば: import numpy as np import matplotlib.pyplot as plt data = np.random.normal(0,0.1,1000) weights = np.ones(len(data))/len(data) plt.hist( data, weights=weights ) plt.show() アウトプットは で, 縦軸が1を超えるとか, 意味がわからない. 原因 matplotlibのドキュメント を見ても何も書いてない. これは numpyのドキュメント に答えが書いてあるからで, 要するに normed オプションは事実上 density オプションと等しく, これは縦軸を確率分布関数と思って規格化するオプションである, と. 従って, normed=True オプションを指定すると, binの 面積 が1に規格化されることになる. いま欲しいものは値の 総和 が1に規格化されたアウトプットなのだから, binの幅が1でない限り, 欲しい結果は得られない. 対策 代わりに weights オプションを指定すればこの問題は解決できる. これは data の1つの値の重みを指定するパラメー

UbuntuのPDF編集ツールの使い方まとめ

PDFtkやpoppler-utilsに含まれるツールを使ってPDFを編集するコマンドのまとめです. 0. インストール sudo apt install pdftk sudo apt install poppler-utils UbuntuあるいはBash on Windowsならaptコマンドで一発. 1. PDFの文書情報の表示 pdfinfo (ファイル名) 2. PDFの分割と結合 pdftk (入力ファイル) cat (ページの指定) output (出力ファイル) ページ数の指定は1-12 14-endみたいな形で書けばよい. 入力ファイルを複数指定してページ数の指定を省略すればPDFの結合ができる. 3. PDFをJPEG/PNGに変換 pdftoppm [オプション] (入力ファイル名) (出力ファイル名の接頭辞) JPEGが欲しい場合-jpegを, PNGが欲しい場合-pngをオプションに指定する. デフォルトの解像度はDPI150で粗すぎるのでオプションで-r 300ないし-r 600を指定すべき. 白黒画像にしたい場合は-monoないし-grayを指定 (個人的には-grayのが好み). 複数ページのPDFを変換すると, 出力ファイルは (出力ファイル名の接頭辞)-1.jpg (出力ファイル名の接頭辞)-2.jpg みたいな形で生成される. 4. PDFからテキストを抽出 pdftotext (入力ファイル名) (出力ファイル名) 出力ファイルの文字コードはUTF-8, 改行コードはLF. 出力ファイル名は省略可能. 5. PDFから画像を抽出 pdfimages [オプション] (入力ファイル名) (出力ファイル名の接頭辞) オプションについて: -pngでPNG, -jでJPEG, -tiffでTIFF形式で出力される (オプションなしだとPPM形式) 6. PDFを回転 pdftk (入力ファイル名) cat 1-end(向き) output (出力ファイル名) 向きとしてはleft, right, downまたはnorth, east, west, southが使用可能. ※向きを指定する前にスペースを入れるとエラーになる. 関連ページ

源ノ明朝/源ノ角ゴシックをLuaLaTeXで使用する (Windows)

源ノ明朝 (Source Han Serif), 源ノ角ゴシック (Source Han Sans) はAdobeとGoogleが作成したCJKフォントで, オープンソースフォントとして公開されています (ライセンスはSIL Open Source License 1.1). 以下では, LuaTeXエンジンでこのフォントを (日本語で) 使用する方法を説明します. あるいは, otfファイルがダウンロードできれば, どのようなフォントにも適用可能です (PDFにフォント埋め込みすることに関してライセンスに注意が必要ですが). Windows10を前提としますが, 他の環境 (Linux/Mac) でもほぼ同じ方法で導入できるんじゃないでしょうか. 使用したのはTeX Live 2016 (LuaTeX-0.95) です.