Mol (Math Object Library) for .Net 概要
Mol (Math Object Library) for .Net とは?
Microsoft Windows 上でのプログラミング環境は (.Net Framework)と Visual Studioで劇的に楽になりました。 プログラマーは本来の目的とは直接関係のないプログラミング特有の約束事に振り回されることなく創造活動に専念できます。 しかしながら、全く新規開発の場合を除けば、過去の資産を有効利用するという点ではまだ未整備な部分が多くあるのも事実です。 その一つが数値計算の分野です。 Mol (Math Object Library) for .Net はBigDecimal といった、.Net の不足した機能を追加すると同時に、 CPU に最適化されたインテル社の インテル® MKL - (代理店) をベースに必要な機能を追加して .Net から簡単にオブジェクト指向に基づいた各種計算が実行できるクラスライブラリーです。
注意事項: |
---|
※本説明の読者は Microsoft .Net と、少なくとも C# を使用したプログラミングの知識を有しているものとします。 ※本説明ではプログラム例等に C# を使用します。 ※オブジェクト指向プログラミングでは「クラス」と「インスタンス」を明確に区別します。しかし、本説明では両者を「オブジェクト」として(特に必要な場合を除いて) 区別せずに同じ用語を用います。 |
注意事項: |
---|
※メールアドレス表記は SPAM 対策として名前部分が「半角に→mol」となっています。送信の際は半角小文字の「mol」に変更してください。 |
Mol でサポートされるもの
オブジェクト名 | 説明 |
---|---|
軽量・高速な簡易型データベース処理クラス。 Mol(Math Object Library) for .Net は巨大な行列や大量の数値データの効率的な計算手法を提供します。 LightDB は、これら計算手法を側面から支援するために組み込まれた、 大量データを簡単に素早く格納・検索可能な簡易型データベース処理クラスです。 LightDB の概要や処理例等は Let's 'C#で数値計算' with Mol & Dsl を参照してください。 | |
任意桁の10進数を扱うクラスです。 double の数値と全く同様に + - * / 等の四則演算や任意桁位置での丸め操作が用意されています。 | |
密(Dense)なベクトル。 スカラー、ベクトル、行列間の四則演算等が用意されています。 | |
密(Dense)なベクトル。 スカラー、ベクトル、行列間の四則演算等が用意されています。 | |
密(Dense)な一般行列(行数と列数は個別に指定します)。スカラー、ベクトル、行列間の四則演算等が用意されています。 | |
疎(Sparse)な一般行列(行数と列数は個別に指定します)。スカラー、ベクトル、行列間の四則演算等が用意されています。 | |
対称行列(正方行列です)。スカラー、ベクトル、行列間の四則演算等が用意されています。 行列を A とすると A[i,j] = v は A[j,i] = v と同じことになります。 対称ですので対角要素を含む上半分の要素のみがメモリーに確保されます。 | |
MatrixDenseUpperTriangleDouble MatrixDenseUpperTriangleComplex | 上三角行列(正方行列です)。スカラー、ベクトル、行列間の四則演算等が用意されています。 対角要素を含む上半分の要素のみがメモリーに確保されます。A[i,j]の i>j 部分はゼロが仮定されます(メモリー領域は確保されません)。 |
MatrixDenseLowerTriangleDouble MatrixDenseLowerTriangleComplex | 下三角行列(正方行列です)。スカラー、ベクトル、行列間の四則演算等が用意されています。 対角要素を含む下半分の要素のみがメモリーに確保されます。A[i,j]の i<j 部分はゼロが仮定されます(メモリー領域は確保されません)。 |
一般帯行列(正方行列とは限りません)。スカラー、ベクトル、行列間の四則演算等が用意されています。 対角要素を中心に上下の幅(指定します)を持った帯状の行列です。帯の外側要素はゼロが仮定されます(メモリー領域は確保されません)。 | |
エルミート行列です(正方行列です)。スカラー、ベクトル、行列間の四則演算等が用意されています。 対称行列と同様に対角要素を含む上半分の要素のみがメモリーに確保されます。対称行列とは違い A[i,j] は A[j,i] の複素共役値が仮定されます。 | |
離散フーリェ変換(DFT)を扱うクラスです。 変換は多次元データを扱うことができます。高速フーリェ変換(FFT)ロジックにより、最大のパフォーマンスを得ることができます。 | |
ベクトル要素の数学演算クラスです。 各種数学演算をベクトル要素単位に同時並行的(マルチスレッド機能)に実行するメソッド群が用意されています。 | |
基本統計量を計算するクラスです。巨大データを分割して計算、ロバスト推定、外れ値の検出、欠測値の置き換え、部分分散等の計算を実装しています。 | |
各種の行列を係数に持つ線形連立一次方程式を解きます。 | |
行列の特異値分解 (SVD:Singular Value Decomposition)を実行します。 | |
行列の固有値(Eigenvalue)・固有ベクトル (Eigenvector)を計算します。 | |
非線形連立方程式、 Fj(x1,x2,...,xn) j=1,2,...,m 、を処理するクラスです。 各方程式値のユークリッドノルム値、(ΣFj(x)2)1/2、を最小化する非線形最小二乗(最適)化問題やヤコビ行列の計算などができます。 | |
C や C++ で作成された(.Net のマネージドDLLではない)ネイティブなDLLをダイナミックにロードして、定義されている関数を呼び出すためのクラスです。 |
注意事項: |
---|
ベクトルと行列は上記のように要素配列の違いで「密と疎」、要素のタイプとして 「double と Complex」、 さらに行列は「構造」の違いがあり、それらの組み合わせにより様々な形があります。しかし、利用方法に違いはありません。 ※ただし、帯行列は「密」のみ、エルミート行列は複素数専用です。 |
行列の種類が沢山あります。これは、行列を単なる2次元の配列で扱うと、要素数が多くなるにつれて途端に計算時間とメモリー容量が増えてスーパーコンピュータの登場となり得るからです。 そこで、Mkl では各種(三角行列、対称行列、帯行列等)の特殊な格納方式を駆使して計算時間とメモリー容量を節約するようになっています。 ただ、格納方式特有の複雑なデータ構造は、技術者(Mklに精通したプログラマーであるとは限りません)が必要なときに直ぐ利用できる物ではありません。 Mol は、このようなデータ構造などの違いを隠蔽し共通のインターフェースを提供します。 詳細は後述するとして、以下の例では対称行列を利用していますが、一般行列 MatrixDenseGeneralDouble を使用してもソースコードは先頭の一行以外同じです。
コードをコピー | |
---|---|
int n = 100; MatrixDenseSymmetricDouble A = new MatrixDenseSymmetricDouble(n); // 係数行列(対称行列)の作成 // MatrixDenseGeneralDouble A = new MatrixDenseGeneralDouble(n,n); 一般行列でも、以下は同じ(計算時間などは当然異なってきます)。 VectorDenseDouble b = new VectorDenseDouble(n); // 定数ベクトル // 係数行列と定数ベクトル要素の値設定 for(int i = 1;i<=n;++i) { b[i] = 1.0; for(int j=1;j<=n;++j) { A[i,j] = 1.0/(i+j-1); // Hilbert Matrix } } LuSolver lu = LuSolver.Create(A); // 連立方程式を解く前に行列 A を因子分解する。 VectorDenseDouble x = lu.Solve(b);// A*x = b を解く。 VectorDenseDouble c = A * x; // 検算のため c = A * x を計算する。 Debug.Assert(_Mol.EQ(c, b)); // b と c の全要素値が同じかどうか確かめる。 |
上記は簡単なソースコード例ですが、
A と b がどんな行列やベクトルでも A[i,j] や b[i] で所望の要素にアクセスできます
A がどんな行列でもLuSolver lu = LuSolver.Create(A); VectorDenseDouble x = lu.Solve(b);で簡単に連立方程式を解くことができます
VectorDenseDouble c = A * x;で任意の行列と任意のベクトルの掛け算を実行できます
_Mol.EQ(c, b);で任意のベクトル同士の全要素が等しいかどうか確かめることができます
といったことが分かります。もちろん、掛け算以外にも可能な四則演算が任意の行列やベクトル同士で定義されています
行列の構造
前章で若干記述しましたが、Mol でサポートされている行列構造は以下の通りです。
行列構造 | 説明 | ||||
---|---|---|---|---|---|
一般行列(General) | 2次元配列と考えて問題ありません。行数と列数が異なっても構いません。また、どの行列要素にも任意の値を自由に設定することができます。 | ||||
対称行列(Symmetric) | 行列要素の対称性が強制される構造です。対称なので対角要素を含む上三角部分の要素のみを格納します。従って、格納するメモリー領域を節約することができます。 行列を A とすると、常に A[i,j]==A[j,i] が成立します。 例えば A[i,j]=1.0 を実行すると A[j,i]=1.0 も同時に実行したことになります。 ※注意: A[i,j] += 1.0 のような実行文は注意が必要です。
| ||||
エルミート行列(Hermite) | 対称行列と同様に対角要素を含む上三角部分の要素のみを格納する、複素数専用の構造です。 行列を A とすると、常に A[i,j]==Complex.Conjugate(A[j,i]) が成立します。 (Conjugate()()()() は任意の複素数の複素共役を求めます。) 対角要素の虚数部は性質上ゼロでなければなりません(ゼロ以外を設定しようとするとエラーになります)。 ※値がゼロかどうかの判定はEQ(Double, Double)のメソッド群が使用されます。 ※要素が実数の場合は対称行列と全く同じですので、エルミート行列は複素数専用です。 | ||||
上三角行列(UpperTriangle) | 行列を A とすると、常に A[i,j]==0 (i>jの場合)が成立する行列構造です。 対角要素を含む上三角部分の要素のみを格納するので、格納するメモリー領域を節約することができます。 上三角部分の行列要素には任意の値を設定できますが、(対角成分を含まない)下三角部分にはゼロ以外設定できません(エラーになります)。 | ||||
下三角行列(LowerTriangle) | 行列を A とすると、常に A[i,j]==0 (i<jの場合)が成立する行列構造です。 対角要素を含む下半分の要素のみを格納するので、格納するメモリー領域を節約することができます。 下三角部分の行列要素には任意の値を設定できますが、(対角成分を含まない)上三角部分にはゼロ以外設定できません(エラーになります)。 | ||||
帯行列(Band) | 全非ゼロ要素が対角要素(を含まない)より上と下の決められた範囲内(帯)に収まる行列です。一般行列と同様に行数と列数が異なっても構いません。 帯行列の作成には行列のサイズ(行と列の数)と帯の幅(対角要素より上の最大要素数と下の最大要素数)の4つの情報を指定する必要があります。 帯の範囲内の要素のみを格納するので、格納するメモリー領域を節約することができます。 帯の範囲内には任意の値を設定できますが、範囲外の要素にはゼロ以外設定できません(エラーになります)。 ※三重対角行列は上下の幅が 1 の帯行列の例です。対角行列は上下の幅がゼロ(対角要素のみ)の帯行列の例です。 ※帯行列は「密」だけで「疎」なタイプはありません。 |
チップ: |
---|
一般行列と帯行列は結果的に上記全ての構造を保持できることに注意してください。 例えば一般行列でも要素が対称になっているならUserTypeプロパティに USER_TYPE.USER_MATRIX_SYMMETRIC (_Mol..::..USER_TYPE)を設定すれば、 連立方程式を解く場合などに最適な解法が選択されます。 一般行列以外でも「正定値」であることがはっきりしていれば UserTypeプロパティに USER_TYPE.USER_MATRIX_POSITIVE (_Mol..::..USER_TYPE)等を設定して最適な解法を選択することができます。 (当然ながら間違った設定は間違った答えを得ることになります。) |
「密(Dense)」と「疎(Sparse)」の違い
配列(ベクトルと行列)には「密」と「疎」の違いがあります。 プログラミングレベルで両者に違いはありません。しかし、例えば係数行列の要素がほとんどゼロの連立方程式を解く場合、疎な行列を用いることで少ないメモリー領域で計算時間を大幅に短縮することができます。
密な配列は宣言時にメモリー領域(初期値はゼロです)が全て確保されます。
疎な配列は宣言時に領域は確保されず、要素に値を最初に代入した時点で一つの要素分の領域が動的に確保されます(実際は若干の余裕分が追加で確保されます)。
疎な配列要素の領域が確保されていなくても参照することは可能です。値ゼロが仮定されます。
疎な行列(ベクトルでも同じです)を A とすれば、A[i,j] 要素の値と共にインデックス情報(i と j)も保存されます。
密な行列(ベクトルでも同じです)を A とすれば、行列要素 A[i,j]のメモリー位置は i と j だけから簡単に計算できます。
疎な行列では位置を計算できません。メモリー中のインデックス情報を指定された i と j で検索する必要があります。
密な配列要素は全て同じ時間でランダムにアクセスできます。
疎な配列要素に対するアクセス時間は密な行列に比べて遅くなります。特に代入時は領域確保の時間も追加されます。
密な配列要素に値ゼロが多いときは無駄な計算が多くなります。
疎な配列では値ゼロの要素領域を確保しないことで結果的にメモリー領域と計算時間を大幅に節約することができます。
チップ: |
---|
疎な行列(ベクトル)の非ゼロ要素:値がメモリー領域に格納されている要素。実際の値が非ゼロであるとは限りません。 疎な行列の対角要素:処理の都合上、疎な行列の対角要素は宣言時に領域が確保されます。 |