【MQL5】Outer関数について

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

Outer関数の働き・役割

Outer関数は、2つのベクトルまたは2つの行列外積を計算し、新しい行列を生成するために使用されます。
この関数は、指定されたデータ同士を特定の法則に従って掛け合わせることで、新しいデータ構造を作成します。
Outer関数は、数値データの分析や操作を効率的に行うために重要な役割を果たします。

MQL5では、Outer関数を用いて、ベクトル同士や行列同士の外積を計算し、クロネッカー積などの応用的な計算を簡単に行うことができます。

外積とは

外積とは、数学で使われる計算の一つで、2つのベクトル行列を掛け合わせて新しい行列を生成する方法です。
例えば、2つのベクトルがあるとき、それぞれの要素を互いに掛け合わせて、掛け算の表のような構造を持つ行列を作ります。これが外積です。

行列の場合も同様で、1つ目の行列の各要素を2つ目の行列の各要素に掛け合わせて新しい行列を作成します。
この計算方法は、数値データの分析や物理学の計算、統計など幅広い分野で利用されています。

日常生活での例としては、掛け算の九九が近いイメージです。1つ目の数字と2つ目の数字を掛けて表を作るように、外積も2つのデータの間にあるすべての掛け算結果を組み合わせて構造を作るものです。

Outer関数を使うことで、この外積の計算を手軽に行うことができます。

Outer関数の引数について

Outer関数には、2つのバリアント(異なる書式)が用意されています。それぞれ行列外積ベクトル外積を計算します。

行列の外積を計算する形式

matrix matrix::Outer(
  const matrix&  b      // 2番目の行列
  );

この形式では、呼び出し元の行列引数で指定された2番目の行列外積を計算します。
引数の詳細は以下の通りです。

戻り値としては、外積の結果である新しい行列が返されます。

ベクトルの外積を計算する形式

matrix vector::Outer(
  const vector&  b      // 2番目のベクトル
  );
 

この形式では、呼び出し元のベクトル引数で指定された2番目のベクトル外積を計算します。
引数の詳細は以下の通りです。

戻り値としては、外積の結果である新しい行列が返されます。

このように、Outer関数では、計算対象となる行列またはベクトル引数として指定することで、それに基づいた外積を計算できます。

Outer関数の戻り値について

Outer関数戻り値は、外積の結果として生成された新しい行列です。戻り値は、関数を呼び出したオブジェクト(行列またはベクトル)と引数として指定したオブジェクト(行列またはベクトル)との外積計算によって生成されます。

行列の外積を計算する場合

行列同士の外積を計算する場合、戻り値は以下の特性を持ちます。

ベクトルの外積を計算する場合

ベクトル同士の外積を計算する場合、戻り値は以下の特性を持ちます。

戻り値の活用

戻り値として得られる新しい行列は、その後の数値計算や解析、データの可視化などに利用することができます。たとえば、クロネッカー積やテンソル解析など、応用的な計算に役立てることが可能です。

Outer関数は、計算対象の外積結果を直接的に行列として返すため、別途計算結果を格納するための構造を用意する必要はありません。これにより、効率的に外積計算を活用することができます。

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

//+------------------------------------------------------------------+
//| スクリプトの開始ポイント                                        |
//+------------------------------------------------------------------+
void OnStart()
  {
   // ベクトルの定義
   // vector_aは0から5までの要素を持つベクトル
   vector vector_a = {0, 1, 2, 3, 4, 5};
   
   // vector_bは0から6までの要素を持つベクトル
   vector vector_b = {0, 1, 2, 3, 4, 5, 6};
   
   // ベクトルの外積を計算
   // Outer関数を使用して、vector_aとvector_bの外積を計算し、結果をエキスパートログに出力
   Print("vector_a.Outer\n", vector_a.Outer(vector_b));
   
   // ベクトルのクロネッカー積を計算
   // Kron関数を使用して、vector_aとvector_bのクロネッカー積を計算し、結果をエキスパートログに出力
   Print("vector_a.Kron\n", vector_a.Kron(vector_b));

   // 行列の定義
   // matrix_aは2行3列の行列
   matrix matrix_a = {{0, 1, 2}, {3, 4, 5}};
   
   // matrix_bは3行3列の行列
   matrix matrix_b = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}};
   
   // 行列の外積を計算
   // Outer関数を使用して、matrix_aとmatrix_bの外積を計算し、結果をエキスパートログに出力
   Print("matrix_a.Outer\n", matrix_a.Outer(matrix_b));
   
   // 行列のクロネッカー積を計算
   // Kron関数を使用して、matrix_aとmatrix_bのクロネッカー積を計算し、結果をエキスパートログに出力
   Print("matrix_a.Kron\n", matrix_a.Kron(matrix_b));
  }

/* サンプル結果の期待値
vector_a.Outer
[[0, 0, 0, 0, 0, 0, 0]
 [0, 1, 2, 3, 4, 5, 6]
 [0, 2, 4, 6, 8, 10, 12]
 [0, 3, 6, 9, 12, 15, 18]
 [0, 4, 8, 12, 16, 20, 24]
 [0, 5, 10, 15, 20, 25, 30]]

vector_a.Kron
[[0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 0, 2, 4, 6, 8, 10, 12, 0, 3, 6, 9, 12, 15, 18, 0, 4, 8, 12, 16, 20, 24, 0, 5, 10, 15, 20, 25, 30]]

matrix_a.Outer
[[0, 0, 0, 0, 0, 0, 0, 0, 0]
 [0, 1, 2, 3, 4, 5, 6, 7, 8]
 [0, 2, 4, 6, 8, 10, 12, 14, 16]
 [0, 3, 6, 9, 12, 15, 18, 21, 24]
 [0, 4, 8, 12, 16, 20, 24, 28, 32]
 [0, 5, 10, 15, 20, 25, 30, 35, 40]]

matrix_a.Kron
[[0, 0, 0, 0, 1, 2, 0, 2, 4]
 [0, 0, 0, 3, 4, 5, 6, 8, 10]
 [0, 0, 0, 6, 7, 8, 12, 14, 16]
 [0, 3, 6, 0, 4, 8, 0, 5, 10]
 [9, 12, 15, 12, 16, 20, 15, 20, 25]
 [18, 21, 24, 24, 28, 32, 30, 35, 40]]
*/

// これにより、MQL5でOuter関数を使った計算の結果をエキスパートログに出力できます。

サンプルコードの解説

上記のコードは、Outer関数Kron関数を使用し、ベクトルおよび行列外積クロネッカー積を計算する例です。実行結果をエキスパートログに出力する内容となっています。各関数や変数、計算の意味について順を追って解説します。

ベクトルの定義

コードの冒頭で2つのベクトルが定義されています。

これらのベクトルは、外積クロネッカー積の計算対象となります。


ベクトルの外積を計算

Print("vector_a.Outer\n", vector_a.Outer(vector_b));

vector_a.Outer(vector_b) という記述で、ベクトル vector_a と vector_b の外積が計算されます。

外積の計算ルールは次の通りです。
vector_a の各要素を縦に、vector_b の各要素を横に並べて掛け合わせます。たとえば、外積の結果の要素(i, j) は以下の式で計算されます。

result[i][j] = vector_a[i] * vector_b[j]

計算結果は次のような行列になります。

[[0*0, 0*1, 0*2, 0*3, 0*4, 0*5, 0*6],
 [1*0, 1*1, 1*2, 1*3, 1*4, 1*5, 1*6],
 [2*0, 2*1, 2*2, 2*3, 2*4, 2*5, 2*6],
 [3*0, 3*1, 3*2, 3*3, 3*4, 3*5, 3*6],
 [4*0, 4*1, 4*2, 4*3, 4*4, 4*5, 4*6],
 [5*0, 5*1, 5*2, 5*3, 5*4, 5*5, 5*6]]

これを計算すると以下の行列になります。

[[0, 0, 0, 0, 0, 0, 0],
 [0, 1, 2, 3, 4, 5, 6],
 [0, 2, 4, 6, 8, 10, 12],
 [0, 3, 6, 9, 12, 15, 18],
 [0, 4, 8, 12, 16, 20, 24],
 [0, 5, 10, 15, 20, 25, 30]]

ベクトルのクロネッカー積を計算

Print("vector_a.Kron\n", vector_a.Kron(vector_b));

vector_a.Kron(vector_b) で、ベクトルクロネッカー積が計算されます。クロネッカー積の計算は、vector_a の各要素を vector_b 全体に掛け合わせて長いベクトルを生成します。

たとえば、最初の部分は vector_a[0] * vector_b、次は vector_a[1] * vector_b というように繰り返されます。計算結果は次のようなベクトルになります。

[0*0, 0*1, 0*2, ..., 0*6, 1*0, 1*1, ..., 1*6, ..., 5*0, 5*1, ..., 5*6]

これを展開すると次の通りです。

[0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 0, 2, 4, 6, 8, 10, 12, ..., 30]

行列の定義

次に行列が定義されています。

matrix_a は次のような2行3列の行列です。

[[0, 1, 2],
 [3, 4, 5]]

matrix_b は次のような3行3列の行列です

[[0, 1, 2],
 [3, 4, 5],
 [6, 7, 8]]

行列の外積を計算

Print("matrix_a.Outer\n", matrix_a.Outer(matrix_b));

matrix_a.Outer(matrix_b) により、2つの行列外積が計算されます。

外積の計算は、matrix_a の各要素を基準に、matrix_b 全体を掛け合わせます。結果の行列の各要素(i, j) は次の式で計算されます。

result[i][j] = matrix_a[row_a][col_a] * matrix_b[row_b][col_b]

ここで、

  • row_acol_amatrix_a要素の行と列の位置です。
  • row_bcol_bmatrix_b要素の行と列の位置です。

具体的に、result[i][j] の計算は以下のように行われます。

最初の行 (i = 0):

  • この行は matrix_a[0][0](値は0)を基準に計算されます。
  • すべての要素が 0 × matrix_b要素になるため、結果はすべて 0 です。
    [0, 0, 0, 0, 0, 0, 0, 0, 0]
    

    2番目の行 (i = 1):

    • この行は matrix_a[0][1](値は1)を基準に計算されます。
    • 要素は 1 × matrix_b要素として計算されます。
    [1*0, 1*1, 1*2, 1*3, 1*4, 1*5, 1*6, 1*7, 1*8]
    = [0, 1, 2, 3, 4, 5, 6, 7, 8]
    

    3番目の行 (i = 2):

    • この行は matrix_a[0][2](値は2)を基準に計算されます
    • 要素は 2 × matrix_b要素として計算されます。
    [2*0, 2*1, 2*2, 2*3, 2*4, 2*5, 2*6, 2*7, 2*8]
    = [0, 2, 4, 6, 8, 10, 12, 14, 16]
    

    4番目の行 (i = 3):

    • この行は matrix_a[1][0](値は3)を基準に計算されます。
    • 要素は 3 × matrix_b要素として計算されます。
    [3*0, 3*1, 3*2, 3*3, 3*4, 3*5, 3*6, 3*7, 3*8]
    = [0, 3, 6, 9, 12, 15, 18, 21, 24]
    

    5番目の行 (i = 4):

    • この行は matrix_a[1][1](値は4)を基準に計算されます。
    • 要素は 4 × matrix_b要素として計算されます。
    [4*0, 4*1, 4*2, 4*3, 4*4, 4*5, 4*6, 4*7, 4*8]
    = [0, 4, 8, 12, 16, 20, 24, 28, 32]
    

    6番目の行 (i = 5):

    • この行は matrix_a[1][2](値は5)を基準に計算されます。
    • 要素は 5 × matrix_b要素として計算されます。
    [5*0, 5*1, 5*2, 5*3, 5*4, 5*5, 5*6, 5*7, 5*8]
    = [0, 5, 10, 15, 20, 25, 30, 35, 40]
    

    これにより得られる行列の結果は以下の通りです。

    [[0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 1, 2, 3, 4, 5, 6, 7, 8],
     [0, 2, 4, 6, 8, 10, 12, 14, 16],
     [0, 3, 6, 9, 12, 15, 18, 21, 24],
     [0, 4, 8, 12, 16, 20, 24, 28, 32],
     [0, 5, 10, 15, 20, 25, 30, 35, 40]]
    

    クロネッカー積の計算

     Print("matrix_a.Kron\n",matrix_a.Kron(matrix_b));
    1. 結果行列のサイズ
      結果行列の行数は matrix_a の行数 × matrix_b の行数(2 × 3 = 6)。
      列数は matrix_a の列数 × matrix_b の列数(3 × 3 = 9)。サイズは 6行×9列の行列

    matrix_a[0][0] = 0 を基準に計算
    • matrix_a[0][0](値は0)を基準に matrix_b を掛けます。
    • 要素0 * matrix_b になるため、結果の部分行列は次の通りです。
    [0, 0, 0,
     0, 0, 0,
     0, 0, 0]
    
    matrix_a[0][1] = 1 を基準に計算
    • matrix_a[0][1](値は1)を基準に matrix_b を掛けます。
    • 要素1 * matrix_b になるため、結果の部分行列は次の通りです。
    [0, 1, 2,
     3, 4, 5,
     6, 7, 8]
    
    matrix_a[0][2] = 2 を基準に計算
    • matrix_a[0][2](値は2)を基準に matrix_b を掛けます。
    • 要素2 * matrix_b になるため、結果の部分行列は次の通りです。
    [0, 3, 6,
     9, 12, 15,
     18, 21, 24]
    
    matrix_a[1][1] = 4 を基準に計算
    • matrix_a[1][1](値は4)を基準に matrix_b を掛けます。
    • 要素4 * matrix_b になるため、結果の部分行列は次の通りです。
    [0, 4, 8,
     12, 16, 20,
     24, 28, 32]
    
    matrix_a[1][2] = 5 を基準に計算
    • matrix_a[1][2](値は5)を基準に matrix_b を掛けます。
    • 要素5 * matrix_b になるため、結果の部分行列は次の通りです。
    [0, 5, 10,
     15, 20, 25,
     30, 35, 40]
    
    最終的な結果

    それぞれのブロック行列を横に並べて配置し、matrix_a の構造を反映します。

    最終的な行列は次の通りです:

    [[0, 0, 0, 0, 1, 2, 0, 2, 4],
     [0, 0, 0, 3, 4, 5, 6, 8, 10],
     [0, 0, 0, 6, 7, 8, 12, 14, 16],
     [0, 3, 6, 0, 4, 8, 0, 5, 10],
     [9, 12, 15, 12, 16, 20, 15, 20, 25],
     [18, 21, 24, 24, 28, 32, 30, 35, 40]]
    

    matrix_a の各要素は、小さな行列matrix_b)をスケーリングします。

    • 例えば、matrix_a[0][1] = 1 なら、matrix_b のすべての要素に「1」を掛けます。

    小さな行列を「配置していく」イメージです。

    • 左上から順番に、matrix_a の各要素が計算結果として反映される位置に対応します。

    参考:スケーリングとは

    スケーリング」とは、「行列ベクトルのすべての要素に、同じ数(つまり特定の値)を掛けること」を指します。

    例えば:

    行列

    [[1, 2],
     [3, 4]]

    の場合に、「2を掛ける」と、すべての要素が「2倍」されて、次のような行列になります。

    [[1×2, 2×2],
     [3×2, 4×2]] = [[2, 4],
                     [6, 8]]
    

    これが「スケーリング」という操作の具体的な意味です。行列ベクトルを「掛け算によって拡大・縮小する」と考えるとわかりやすいかもしれません。

    クロネッカー積における「スケーリング」の役割

    クロネッカー積では、matrix_a の各要素matrix_b に対してこの「スケーリング」の役割を果たします。

    例えば:

    • matrix_a[0][0] = 0 の場合、matrix_b のすべての要素に「0」を掛けます。結果は、matrix_b 全体が「ゼロの行列」になります。
    [[0×0, 0×1, 0×2],
     [0×3, 0×4, 0×5],
     [0×6, 0×7, 0×8]] = [[0, 0, 0],
                          [0, 0, 0],
                          [0, 0, 0]]
    

    matrix_a[0][1] = 1 の場合、matrix_b のすべての要素に「1」を掛けます。結果は、matrix_b の値そのものになります。

    [[1×0, 1×1, 1×2],
     [1×3, 1×4, 1×5],
     [1×6, 1×7, 1×8]] = [[0, 1, 2],
                          [3, 4, 5],
                          [6, 7, 8]]
    

    matrix_a[1][0] = 3 の場合、matrix_b のすべての要素に「3」を掛けます。結果は、matrix_b要素が3倍された行列になります。

    [[3×0, 3×1, 3×2],
     [3×3, 3×4, 3×5],
     [3×6, 3×7, 3×8]] = [[0, 3, 6],
                          [9, 12, 15],
                          [18, 21, 24]]
    

    クロネッカー積では、「matrix_a の各要素matrix_b をどう変えるか」を計算する作業の連続です。

    1. matrix_a の各要素を1つずつ取り出し、その値を matrix_b のすべての要素に掛けます。
    2. こうして得られた「小さな行列」を、それぞれの位置に並べて配置していきます。

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