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]
ここで、
具体的に、result[i][j]
の計算は以下のように行われます。
最初の行 (i = 0):
[0, 0, 0, 0, 0, 0, 0, 0, 0]
2番目の行 (i = 1):
[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):
[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):
[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):
[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):
[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));
- 結果行列のサイズ
結果行列の行数はmatrix_a
の行数 ×matrix_b
の行数(2 × 3 = 6)。
列数はmatrix_a
の列数 ×matrix_b
の列数(3 × 3 = 9)。サイズは 6行×9列の行列。
matrix_a[0][0] = 0 を基準に計算
[0, 0, 0,
0, 0, 0,
0, 0, 0]
matrix_a[0][1] = 1 を基準に計算
[0, 1, 2,
3, 4, 5,
6, 7, 8]
matrix_a[0][2] = 2 を基準に計算
[0, 3, 6,
9, 12, 15,
18, 21, 24]
matrix_a[1][1] = 4 を基準に計算
[0, 4, 8,
12, 16, 20,
24, 28, 32]
matrix_a[1][2] = 5 を基準に計算
[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
に対してこの「スケーリング」の役割を果たします。
例えば:
[[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]]