【MQL5】GeMM関数について

MQL5リファレンス
スポンサーリンク
スポンサーリンク

GeMM関数の働き・役割

GeMM関数は、行列ベクトルの乗算を効率的に実行するための関数です。

GeMMは、General Matrix Multiply(一般行列乗算)の略です。

通常の行列乗算では、2つの行列掛け算して新しい行列を作成しますが、GeMM関数は既存の行列を再利用しながら計算を行います。これにより、計算中に不要なメモリ割り当てを避けることができます。

GeMM関数の動作は、次のように数式で表されます。

C = α * (A * B) + β * C

ここで、

たとえば、ニューラルネットワークをトレーニングするときに、行列演算が頻繁に使われます。GeMM関数はこのような計算を効率化し、必要なメモリを最小限に抑えます。

GeMM関数は、行列同士の乗算だけでなく、行列ベクトルベクトル同士の掛け算もサポートしており、複数の形式で利用できます。

GeMM関数の引数について

行列と行列の乗算(第1書式)

bool  matrix::GeMM(
  const matrix &A,    // 1番目の行列
  const matrix &B,    // 2番目の行列
double alpha,      // 積ABのアルファ乗数
double beta,       // 行列Cのベータ乗数
uint  flags       // 行列A、B、Cが転置されるかどうかを決定するENUM_GEMM値の組み合わせ(ビットOR)
  );

この書式では、2つの行列掛け算し、その結果を別の行列に保存します。数式で表すと次のようになります。

数式
matrix C[M][N] = α * (matrix A[M][K] * matrix B[K][N]) + β * matrix C[M][N]

数式の説明

  • matrix C[M][N]
    計算結果を保存する行列です。Cの行数はAの行数(M)と一致し、Cの列数はBの列数(N)と一致します。
  • α * (matrix A[M][K] * matrix B[K][N])
    AとBの行列掛け算した結果に、スカラー値αを掛けたものです。この部分が計算の主な内容を表します。
    • A[M][K]: 行列AはM行K列のサイズを持つ行列です。
    • B[K][N]: 行列BはK行N列のサイズを持つ行列です。行列Aの列数(K)と行列Bの行数(K)が一致している必要があります。
    • AとBの乗算結果はM行N列の行列となり、Cに加算されます。
  • β * matrix C[M][N]
    もともとCに保存されている値に、スカラー値βを掛けたものです。この項を追加することで、Cの初期値を計算結果に反映することができます。
    • βが0の場合、Cの初期値は無視され、AとBの掛け算結果だけがCに保存されます。
    • βが1の場合、Cの初期値はそのまま反映され、AとBの掛け算結果と足し合わされます。

引数の説明

A (const matrix &A)
1番目の行列です。計算の左側に位置する行列を指定します。たとえば、行列A[M][K]という形で入力します。

B (const matrix &B)
2番目の行列です。計算の右側に位置する行列を指定します。たとえば、行列B[K][N]という形で入力します。

α (double alpha)
AとBを掛けた結果に掛け算されるスカラー値です。この値によって、計算結果の大きさを調整します。

β (double beta)
もともとの結果行列Cの値に掛けられるスカラー値です。これを使って、行列Cが最終的な結果にどれだけ影響を与えるかを調整します。

flags (uint flags)
行列A、B、Cをそのまま使用するか、転置するかを決定します。このフラグENUM_GEMMの列挙値を用いて指定します。複数の設定を組み合わせる場合はビットOR演算を使用します。

転置についてはこの記事の「ENUM_GEMMについて」セクションをご参照ください。


ベクトルと行列の乗算(第2書式)

bool  vector::GeMM(
  const vector &A,    // 水平ベクトル
  const matrix &B,    // 行列
double alpha,      // 積ABのアルファ乗数
double beta,       // ベクトルCのベータ乗数
uint  flags       // 行列Aが転置されるかどうかを決定するENUM_GEMM列挙値
  );

この書式では、1つの水平ベクトルと1つの行列掛け算し、その結果を別の水平ベクトルに保存します。数式で表すと次のようになります。

数式
vector C[N] = α * (vector A[K] * matrix B[K][N]) + β * vector C[N]


数式の説明

この数式は、水平ベクトル行列掛け算に加え、スカラー値で結果を調整したり、初期値を反映したりする仕組みを表しています。


引数の説明

A (const vector &A)
水平ベクトルです。計算の左側に位置するベクトルを指定します。要素数はKで、行列Bの行数(K)と一致している必要があります。

B (const matrix &B)
掛け算する行列です。行数はベクトルAの要素数(K)と一致し、列数は結果となるベクトルCの要素数(N)に対応します。

α (double alpha)
AとBを掛けた結果に掛け算されるスカラー値です。この値によって、計算結果の大きさを調整します。

β (double beta)
もともとの結果ベクトルCの値に掛けられるスカラー値です。これを使って、Cが最終的な結果にどれだけ影響を与えるかを調整します。

flags (uint flags)
ベクトルAをそのまま使用するか、転置するかを決定します。このフラグENUM_GEMMの列挙値を用いて指定します。


行列とベクトルの乗算(第3書式)

bool  vector::GeMM(
  const matrix &A,    // 行列
  const vector &B,    // 垂直ベクトル
double alpha,      // 積ABのアルファ乗数
double beta,       // ベクトルCのベータ乗数
uint  flags       // 行列Bが転置されるかどうかを決定するENUM_GEMM列挙値
  );

この書式では、1つの行列と1つの垂直ベクトル掛け算し、その結果を別の垂直ベクトルに保存します。数式で表すと次のようになります。

数式
vector C[M] = α * (matrix A[M][K] * vector B[K]) + β * vector C[M]


数式の説明

この数式は、行列と垂直ベクトル掛け算に加え、スカラー値で結果を調整したり、初期値を反映したりする仕組みを表しています。


引数の説明

A (const matrix &A)
掛け算する行列です。行数は結果ベクトルCの要素数(M)と一致し、列数はベクトルBの要素数(K)と一致している必要があります。

B (const vector &B)
垂直ベクトルです。計算の右側に位置するベクトルを指定します。要素数は行列Aの列数(K)と一致している必要があります。

α (double alpha)
AとBを掛けた結果に掛け算されるスカラー値です。この値によって、計算結果の大きさを調整します。

β (double beta)
もともとの結果ベクトルCの値に掛けられるスカラー値です。これを使って、Cが最終的な結果にどれだけ影響を与えるかを調整します。

flags (uint flags)
ベクトルBをそのまま使用するか、転置するかを決定します。このフラグENUM_GEMMの列挙値を用いて指定します。


この書式は、行列計算における標準的な処理であり、特に入力データが行列で構成されるアルゴリズムやシステムで頻繁に使用されます。

ベクトルとベクトルの乗算(第4書式)

この書式では、1つの垂直ベクトルと1つの水平ベクトル掛け算し、その結果を行列として保存します。数式で表すと次のようになります。

数式
matrix C[M][N] = α * (vector A[M] * vector B[N]) + β * matrix C[M][N]


数式の説明

この数式は、垂直ベクトルと水平ベクトルの乗算に加え、スカラー値で結果を調整したり、初期値を反映したりする仕組みを表しています。


引数の説明

A (const vector &A)
1つ目のベクトルです。計算の左側に位置する垂直ベクトルを指定します。要素数は行列Cの行数(M)に一致します。

B (const vector &B)
2つ目のベクトルです。計算の右側に位置する水平ベクトルを指定します。要素数は行列Cの列数(N)に一致します。

α (double alpha)
AとBを掛けた結果に掛け算されるスカラー値です。この値によって、計算結果の大きさを調整します。

β (double beta)
もともとの結果行列Cの値に掛けられるスカラー値です。これを使って、Cが最終的な結果にどれだけ影響を与えるかを調整します。

flags (uint flags)
結果行列Cをそのまま使用するか、転置するかを決定します。このフラグENUM_GEMMの列挙値を用いて指定します。


ENUM_GEMMについて

GeMM関数では、入力する行列ベクトルの形状を変更するために、ENUM_GEMMという列挙値を使用します。この列挙値を指定することで、計算時に行列ベクトルを「そのまま使用するか」「転置して使用するか」を柔軟に制御できます。


転置とは?

転置とは、行列ベクトルの「行」と「列」を入れ替える操作のことを指します。たとえば、次のような行列を考えます。

A = [[1, 2],
     [3, 4]]

この行列転置すると、次のようになります。

A^T = [[1, 3],
       [2, 4]]

転置後は、元の行列要素A[i][j] が新しい位置 A^T[j][i] に移動します。これにより、行列の形を変えることができます。

※ハット記号(^)は数学においてさまざまな意味を持つことがありますが、行列に関しては通常「転置」を示します。

具体的には、記号 A^T の意味は、行列Aの転置を表しています。

GeMM関数では、列挙値を使って転置を制御できます。次に、各列挙値とその効果を説明します。


ENUM_GEMMの列挙値とその効果

1. TRANSP_A(行列Aを転置)

このフラグを指定すると、行列Aが転置された形で計算に使用されます。たとえば、行列Aが次のような場合、

A = [[1, 2],
     [3, 4]]

フラグ TRANSP_Aを指定すると、次のように転置されて計算に使われます。

A^T = [[1, 3],
       [2, 4]]

2. TRANSP_B(行列Bを転置)

このフラグを指定すると、行列Bが転置された形で計算に使用されます。たとえば、行列Bが次のような場合、

B = [[5, 6],
     [7, 8]]

フラグ TRANSP_Bを指定すると、次のように転置されて計算に使われます。

B^T = [[5, 7],
       [6, 8]]

3. TRANSP_C(結果行列Cを転置)

このフラグを指定すると、計算結果を保存する行列Cが転置された形で保存されます。たとえば、通常の計算結果Cが次のような場合、

C = [[9, 10],
     [11, 12]]

フラグ TRANSP_Cを指定すると、次のように転置されて保存されます。

C^T = [[9, 11],
       [10, 12]]

フラグの組み合わせ

これらのフラグは、複数を同時に指定して使用することができます。たとえば、行列Aと行列Bを両方転置して計算したい場合は、以下のように組み合わせます。

uint flags = TRANSP_A | TRANSP_B;

この指定により、AとBの両方が転置されて計算に使用されます。


転置を使う目的

転置を指定する理由は、主に次のようなものです。

  1. 計算可能な形に整える
    行列ベクトルの形が一致しておらず、そのままでは掛け算できない場合に使用します。
  2. 計算結果の形式を調整する
    計算結果を特定の形にしたい場合や、結果を別の形で利用したい場合に役立ちます。
  3. 効率性の向上
    計算効率を高めるため、行列の形状を変更することで最適化を図ることがあります。

ENUM_GEMMを使用することで、計算の柔軟性と効率性を向上させることができます。転置操作を適切に活用することで、行列計算の幅が広がり、さまざまな場面で応用が可能になります。

GeMM関数の戻り値について

GeMM関数戻り値は、計算の成否を表します。以下に詳しく説明します。

成功した場合

関数が正常に動作し、指定した計算が実行された場合、戻り値はtrueになります。この場合、計算結果は行列またはベクトルCに保存されます。

失敗した場合

関数が失敗した場合、戻り値はfalseになります。失敗する原因として、以下のようなケースが考えられます。

GeMM関数を使う際の注意点

GeMM関数を使う際には、対応するデータ型や実装方法について理解する必要があります。この関数は、次のような特徴を持っています。


対応するデータ型

  1. float型
    小数を扱うデータ型です。計算精度が必要な場合に使用しますが、メモリの使用量が少ないため、大量のデータを扱う際にも適しています。
  2. double
    float型よりも精度が高い小数を扱うデータ型です。科学計算や高精度が求められる場面で使用されます。
  3. complex型
    複素数を扱うデータ型です。複素数とは、実数(普通の数)に加えて、虚数単位「i」を含む数です。たとえば、「3 + 4i」のような形式で表されます。複雑な数式計算や物理シミュレーションで必要になることがあります。

複素数についての詳細は下記の記事をご参照ください。


テンプレートについて

GeMM関数テンプレートとして実装されています。テンプレートとは、関数クラスを特定の型に依存させずに汎用的に使える仕組みのことです。GeMM関数では、float型、double型、complex型など、さまざまなデータ型に対応しています。テンプレートを使用することで、コードを繰り返し書く必要がなくなり、異なるデータ型での計算を柔軟に行うことができます。

テンプレートについての詳細は下記の記事をご参照ください。


GeMM関数の実装例とコードの見方

公式リファレンスには、GeMM関数がどのように使われるかを示す例がいくつかあります。以下は、その書式の意味について説明します。

行列同士の計算(例)

bool matrix<T>::GeMM(const matrix<T> &A, const matrix<T> &B, T alpha, T beta, ulong flags);

構成要素の意味

ベクトルと行列の計算(例)

bool vector<T>::GeMM(const vector<T> &A, const matrix<T> &B, T alpha, T beta, ulong flags);

構成要素の意味

このように、コードの書式からどのデータ型を使って計算するかがわかります。また、bool型戻り値が成功(true)か失敗(false)を示します。


GeMM関数を使ったサンプルコード

void OnStart()
{
  // ベクトルを定義 (vector_aは5つの要素を持つベクトル、vector_bは4つの要素を持つベクトル)
  vector vector_a = {1, 2, 3, 4, 5};  // ベクトルaの要素は1, 2, 3, 4, 5
  vector vector_b = {4, 3, 2, 1};      // ベクトルbの要素は4, 3, 2, 1

  // 結果を格納するための行列matrix_cを宣言
  matrix matrix_c;

  //--- 2つのベクトルを使ってGeMM(行列の一般的な積)を計算
  matrix_c.GeMM(vector_a, vector_b, 1, 0);  
  // 引数の意味:
  // vector_a: 行ベクトル、vector_b: 列ベクトルとして使用
  // 1: スケーリング係数、0: バイアス値(行列に加算されるオフセット)
  // 計算結果はmatrix_cに格納

  // 計算結果を出力
  Print("matrix_c:\n ", matrix_c, "\n");
  /*
  出力結果の例:
  matrix_c:
   [[4, 3, 2, 1]
    [8, 6, 4, 2]
    [12, 9, 6, 3]
    [16, 12, 8, 4]
    [20, 15, 10, 5]]
  */

  //--- 行列をベクトルから生成
  // 5行1列の行列matrix_aを定義
  matrix matrix_a(5, 1);
  // 1行4列の行列matrix_bを定義
  matrix matrix_b(1, 4);

  // vector_aの要素をmatrix_aの0列目(唯一の列)に格納
  matrix_a.Col(vector_a, 0);  // Colメソッドを使用して列として追加

  // vector_bの要素をmatrix_bの0行目(唯一の行)に格納
  matrix_b.Row(vector_b, 0);  // Rowメソッドを使用して行として追加

  // 行列matrix_aとmatrix_bを出力
  Print("matrix_a:\n ", matrix_a);
  Print("matrix_b:\n ", matrix_b);
  /*
  出力結果の例:
  matrix_a:
   [[1]
    [2]
    [3]
    [4]
    [5]]
  matrix_b:
   [[4, 3, 2, 1]]
  */

  //--- 2つの行列matrix_aとmatrix_bを使ってGeMMを計算
  matrix_c.GeMM(matrix_a, matrix_b, 1, 0);
  // 引数の意味:
  // matrix_a: 行列1、matrix_b: 行列2
  // 1: スケーリング係数、0: バイアス値(行列に加算されるオフセット)
  // 計算結果は再度matrix_cに格納

  // 計算結果を出力
  Print("matrix_c:\n ", matrix_c);
  /*
  出力結果の例:
  matrix_c:
   [[4, 3, 2, 1]
    [8, 6, 4, 2]
    [12, 9, 6, 3]
    [16, 12, 8, 4]
    [20, 15, 10, 5]]
  */
}

コード解説:ベクトルと行列を使った計算の流れ

このコードは、MQL5ベクトル行列を用いて計算を行い、その結果を出力するものです。具体的には、ベクトル同士の積(外積のような操作)を計算し、それを行列として出力します。また、別の方法でも同じ結果を得られることを確認しています。


1. ベクトル vector_a と vector_b の定義

最初に、2つのベクトルが定義されています。

2. GeMM メソッドによるベクトルの積

次に、GeMM メソッドを用いて vector_avector_b を使った計算が行われます。

matrix_c.GeMM(vector_a, vector_b, 1, 0);
  • GeMM関数引数の意味:
    • vector_a: 行方向の値(行ベクトル)。
    • vector_b: 列方向の値(列ベクトル)。
    • 1: 結果にかけるスケーリング係数(ここではそのまま使う)。
    • 0: 行列に加えるオフセット(ここでは加算しない)。

計算の内容:

  • vector_a の各要素と vector_b の各要素が掛け合わされ、結果として 行列 matrix_c が作られます。
  • 行列の各要素は次のように計算されます:
matrix_c[i][j] = vector_a[i] * vector_b[j]

ここで、iはvector_aのインデックス(行番号)、jはvector_bのインデックス(列番号)です。

スカラー値の適用
alphaが1なので、計算結果はそのまま保持されます。betaが0なので、既存のmatrix_cの値は無視されます。

計算例

vector_a = [1, 2, 3, 4, 5]vector_b = [4, 3, 2, 1]要素を計算します。

1行1列目: 1 * 4 = 4
1行2列目: 1 * 3 = 3
1行3列目: 1 * 2 = 2
1行4列目: 1 * 1 = 1

2行1列目: 2 * 4 = 8
2行2列目: 2 * 3 = 6

同様に計算を続けると、結果は次のようになります。

matrix_c:
[[4, 3, 2, 1]
 [8, 6, 4, 2]
 [12, 9, 6, 3]
 [16, 12, 8, 4]
 [20, 15, 10, 5]]

ベクトルを行列として定義

matrix matrix_a(5, 1);
matrix matrix_b(1, 4);
matrix_a.Col(vector_a, 0);
matrix_b.Row(vector_b, 0);

ここでは、matrix_amatrix_bという行列を定義し、それぞれvector_avector_b要素を使って行列を生成しています。

  • matrix_aは5行1列の行列で、vector_aをそのまま縦方向に配置します。
matrix_a:
[[1]
 [2]
 [3]
 [4]
 [5]]

matrix_bは1行4列の行列で、vector_bをそのまま横方向に配置します。

matrix_b:
[[4, 3, 2, 1]]

行列同士のGeMM計算

matrix_c.GeMM(matrix_a, matrix_b, 1, 0);

ここでは、matrix_amatrix_bを使って再度計算を行います。この場合、行列掛け算が行われます。

行列の計算
要素の計算は次のように行われます。

matrix_c[i][j] = sum(matrix_a[i][k] * matrix_b[k][j])

ここで、kmatrix_aの列番号(またはmatrix_bの行番号)を表します。

計算例

  • 1行1列目: (1 * 4) = 4
  • 1行2列目: (1 * 3) = 3
  • 2行1列目: (2 * 4) = 8

結果として、次の行列が得られます。

matrix_c:
[[4, 3, 2, 1]
 [8, 6, 4, 2]
 [12, 9, 6, 3]
 [16, 12, 8, 4]
 [20, 15, 10, 5]]

結果のまとめ

このコードでは、ベクトル同士、そして行列同士の掛け算を実行し、結果をmatrix_cに格納しています。計算結果はどちらの方法でも同じですが、matrix_aやmatrix_bのように行列形式を利用することで、より汎用的な計算が可能になります。

以下は、算式を1行で表現する形に修正した解説です。


外積とは何か?

外積は、2つのベクトルを使って新しいベクトル行列を作る計算方法です。以下のように場合によって結果が異なります。

1. ベクトルの外積(行列の作成)

もし2つのベクトルa と b があった場合、外積では次のような行列を作ります。

行列の各要素は以下のように計算されます: matrix[i][j] = a[i] * b[j]

具体例:

  • a = [1, 2, 3]
  • b = [4, 5]
計算結果: matrix = [ [14, 15], [24, 25], [34, 35] ]

[ [4, 5], [8, 10], [12, 15] ]

ポイント:


2. ベクトルの外積(3次元)

3次元ベクトルの場合、外積は新しいベクトルを作ります。この新しいベクトルは、元の2つのベクトルに対して垂直な方向を示します。

計算式: c[0] = a[1]*b[2] – a[2]*b[1],
c[1] = a[2]*b[0] – a[0]*b[2],
c[2] = a[0]*b[1] – a[1]*b[0]

具体例:

  • a = [1, 0, 0]
  • b = [0, 1, 0]

計算結果: c = [0, 0, 1]


内積とは何か?

内積は、2つのベクトルを掛け合わせて1つの数値(スカラー)を得る計算方法です。

計算式: dot_product = a[0]*b[0] + a[1]*b[1] + a[2]*b[2]

具体例:

  • a = [1, 2, 3]
  • b = [4, 5, 6]

計算結果: dot_product = 14 + 25 + 3*6 = 4 + 10 + 18 = 32


外積と内積の違い

外積は「形の変化」、内積は「大きさや向きの関係」を示します。

タイトルとURLをコピーしました