Convolve関数の働き・役割
Convolve関数は、2つのベクトルの離散線形畳み込みを計算するために使用されます。
離散線形畳み込みとは
離散線形畳み込みとは、2つのデータ(ベクトル)の「形」を組み合わせる処理です。この処理を使うと、2つのデータがどのように重なり合うかを計算することができます。
たとえば、次のような2つのデータがあるとします。
- データA: [1, 2, 3]
- データB: [0, 1, 0.5]
畳み込みでは、データBをデータAに少しずつずらしながら重ね、重なった部分の数値を掛け算して足し合わせます。この計算を繰り返して、新しいデータを作ります。
畳み込みの計算の結果
畳み込みの結果として、2つのデータがどれくらい似ているか、あるいはどの部分で影響を与え合っているかがわかります。この結果は、新しいデータ(ベクトル)として出力されます。
この「畳み込み」という処理は、数学や信号処理の分野で使われる重要な操作です。畳み込みを使うことで、2つのベクトルの組み合わせによって、特定のパターンや傾向を抽出することができます。
具体的には、1つ目のベクトルに2つ目のベクトルを滑らせるように適用し、それぞれの位置での要素同士の積を合計して新しいベクトルを作成します。この処理により、元のデータの特徴を強調したり、データの変化を捉えたりすることが可能です。
Convolve関数では、計算モードとしてENUM_VECTOR_CONVOLVEから3つの種類を選ぶことができます。
ENUM_VECTOR_CONVOLVEについて
VECTOR_CONVOLVE_FULL:
VECTOR_CONVOLVE_FULLは完全な畳み込みを計算し、結果として最も長いベクトルを返します。
VECTOR_CONVOLVE_SAME:
VECTOR_CONVOLVE_SAMEは入力ベクトルと同じ長さになるように結果を調整します。
VECTOR_CONVOLVE_VALID:
VECTOR_CONVOLVE_VALIDは畳み込みが完全に成立する部分のみを計算します。
この関数を使うことで、複雑な数値計算を簡潔に実行でき、金融分析やインジケータ作成など幅広い用途で役立ちます。
Convolve関数の引数について
vector vector::Convolve(
const vector& v, // ベクトル
ENUM_VECTOR_CONVOLVE mode // モード
);
Convolve関数の引数は以下の通りです。この関数を使うことで、2つのベクトルの離散線形畳み込みを計算できます。
第一引数: v
この引数は、畳み込みを行う2つ目のベクトルを指定します。
指定するベクトルは、最初のベクトル(Convolve関数を呼び出す側のベクトル)と組み合わせて計算されます。
- 種類: ベクトル型
- 役割: 畳み込み処理で滑らせる側のデータを指定します。
第二引数: mode
この引数は、畳み込みの計算モードを指定します。モードにより、出力される結果の長さや計算方法が異なります。指定できるモードは以下の通りです。
- VECTOR_CONVOLVE_FULL
入力ベクトルを完全に畳み込むモードです。このモードでは、畳み込みの全範囲を計算し、結果として最も長いベクトルを返します。 - VECTOR_CONVOLVE_SAME
入力ベクトルと同じ長さになるように結果を調整するモードです。この場合、畳み込みの中央部分だけを計算します。 - VECTOR_CONVOLVE_VALID
畳み込みが完全に成立する部分(重なりが完全な範囲)だけを計算するモードです。結果のベクトルは他のモードに比べて短くなります。
- 種類: ENUM_VECTOR_CONVOLVE(列挙型)
- 役割: 計算結果の範囲や出力形式を指定します。
Convolve関数を使用する際は、第一引数で操作対象の2番目のベクトルを指定し、第二引数で計算モードを適切に選ぶことが重要です。モードを変更することで、得られる結果が異なるため、用途に応じた選択が求められます。
Convolve関数の戻り値について
Convolve関数の戻り値は、指定された2つのベクトルの離散線形畳み込みの結果です。畳み込み結果のベクトルは、引数で指定したモードに応じて異なる形で生成されます。
戻り値の型
モード別の戻り値
モードによって、計算される結果の長さや範囲が異なります。
戻り値の利用例
Convolve関数の戻り値は、数値データの特徴を分析したり、データのパターンを強調するために利用されます。
たとえば、金融市場の価格データに対する移動平均や信号処理でのフィルタリングなど、さまざまな用途に活用できます。用途に応じて適切なモードを選択し、戻り値を利用することがポイントです。
Convolve関数のVECTOR_CONVOLVE_FULLモードの仕組み
下記のオリジナル関数は、Convolve関数のVECTOR_CONVOLVE_FULLモードを使用した時と同じ結果が得られる関数となっています。VECTOR_CONVOLVE_FULLモードの計算がどのように行われているかを知る事ができます。
//+------------------------------------------------------------------+
//| VectorConvolutionFull関数 |
//| 2つのベクトルを入力として受け取り、完全な線形畳み込みを計算します |
//+------------------------------------------------------------------+
vector VectorConvolutionFull(const vector& a, const vector& b)
{
// ベクトルaがベクトルbより短い場合、順序を入れ替えて再帰的に呼び出します
// これは、計算を簡単にするための工夫です
if (a.Size() < b.Size())
return (VectorConvolutionFull(b, a));
// ベクトルaとbの長さを取得します
int m = (int)a.Size(); // ベクトルaの長さ
int n = (int)b.Size(); // ベクトルbの長さ
// 畳み込み結果のベクトルの長さを計算します
// 畳み込みの結果のサイズは、2つのベクトルの長さを足して1を引いたものになります
int size = m + n - 1;
// 畳み込み結果を格納するためのベクトルを初期化します
// vector::Zeros関数を使用して、すべての要素を0に設定します
vector c = vector::Zeros(size);
// 畳み込みの計算を実行します
// ベクトルbの各要素を順番に処理します
for (int i = 0; i < n; i++)
{
// ベクトルaの各要素と掛け算し、その結果を結果ベクトルcに足し合わせます
for (int i_ = i; i_ < i + m; i_++)
{
// i_は現在の位置を示します。b[i]とa[i_-i]を掛け算します
// 計算結果を結果ベクトルcの対応する位置に加算します
c[i_] += b[i] * a[i_ - i];
}
}
// 計算が完了した結果ベクトルcを返します
return (c);
}
VectorConvolutionFull関数の解説
VectorConvolutionFull関数は、2つのベクトル(a
とb
)を入力として受け取り、それらの完全な線形畳み込みを計算するものです。この関数では、掛け算と足し算を繰り返し、結果を新しいベクトルとして返します。以下に詳しく解説します。
関数の動作の流れ
- ベクトルの順序をチェックする 関数の冒頭では、
a
とb
の長さを比較しています。もしa
がb
より短い場合、引数の順序を入れ替えて再度VectorConvolutionFull関数を呼び出します。この仕組みにより、以降の処理では常にa
の方が長い状態で計算を進められます。これにより、コードが簡潔になり、エラーが減ります。 - 畳み込み結果のサイズを決定する 畳み込みの結果の長さは、a.Size()(
a
の長さ)とb.Size()
(b
の長さ)の合計から1を引いた値で決まります。これは、畳み込みの数学的特性によるものです。ここで得られた長さをsize
に格納します。 - 結果ベクトルを初期化する vector::Zeros(size)を使い、長さsizeのすべての要素が0のベクトル
c
を作成します。ここに畳み込み結果を格納していきます。
畳み込み計算の仕組み
畳み込みは、2つのネストされた(入れ子状の)ループを使って計算されます。
外側のループ
内側のループ
実際の計算の例
仮に以下のようなベクトルを考えます。
- a = [1, 2, 3]
- b = [0, 1, 0.5]
畳み込みの計算過程:
b[0]
(値は0
)をa
の全要素に掛け算します。すべて0なので、結果はc
に加算されません。- 次に
b[1]
(値は1
)を使います。このとき、c[1]
からc[3]
が更新されます。c[1] += b[1] * a[0] = 1 * 1 = 1
c[2] += b[1] * a[1] = 1 * 2 = 2
c[3] += b[1] * a[2] = 1 * 3 = 3
- 最後に
b[2]
(値は0.5
)を使います。このとき、c[2]
からc[4]
が更新されます。c[2] += b[2] * a[0] = 0.5 * 1 = 0.5
c[3] += b[2] * a[1] = 0.5 * 2 = 1
c[4] += b[2] * a[2] = 0.5 * 3 = 1.5
最終的な結果はc = [0, 1, 2.5, 4, 1.5]
となります。
インデックスの推移
外側のループでは、b
の要素を1つずつ順番に取り出します(i
が0, 1, 2と進む)。その中で、内側のループが実行され、i_
がi
からi + m
まで動きます。このi_
は結果ベクトルc
の中で現在操作している位置を表します。
例えば、b[1]
(値は1
)を計算する際、i = 1
なので、i_
は1から3まで動きます。この間、c[1]
、c[2]
、c[3]
が更新されます。
まとめ
VectorConvolutionFull関数では、a
の各要素とb
の各要素を掛け算して、結果をc
に加算しています。内側のループで掛け算と加算を実行し、外側のループでb
のすべての要素に対する処理を進めています。この構造により、2つのベクトルの完全な畳み込み結果を効率的に計算することができます。
Convolve関数のVECTOR_CONVOLVE_SAMEモードの仕組み
//+------------------------------------------------------------------+
//| VectorConvolutionSame関数 |
//| 2つのベクトルを入力として受け取り、入力ベクトルと同じ長さの |
//| 線形畳み込み結果を計算します。 |
//+------------------------------------------------------------------+
vector VectorConvolutionSame(const vector& a, const vector& b)
{
// ベクトルaがベクトルbより短い場合、順序を入れ替えて再帰的に呼び出します
// これにより、コード全体が簡潔で一貫性を持つようになります
if (a.Size() < b.Size())
return (VectorConvolutionSame(b, a));
// ベクトルaとbの長さを取得します
int m = (int)a.Size(); // ベクトルaの長さ
int n = (int)b.Size(); // ベクトルbの長さ
// 畳み込み結果のベクトルの長さを計算します
// 同じ長さモードでは、結果ベクトルの長さはaとbのどちらか長い方(MathMax)となります
int size = MathMax(m, n);
// 結果ベクトルを初期化します
// vector::Zeros関数を使用して、結果ベクトルcのすべての要素を0で初期化します
vector c = vector::Zeros(size);
// 畳み込みの計算を開始します
// 外側のループで、ベクトルbの各要素を順に処理します
for (int i = 0; i < n; i++)
{
// 内側のループで、ベクトルaの各要素と掛け算し、その結果をcに加算します
for (int i_ = i; i_ < i + m; i_++)
{
// 結果ベクトルcの対応位置kを計算します
// kは中央寄せを考慮した結果ベクトルのインデックスを示します
int k = i_ - size / 2 + 1;
// kが結果ベクトルcの範囲内(0以上で、size未満)である場合のみ計算を行います
if (k >= 0 && k < size)
{
// ベクトルb[i]とベクトルa[i_-i]を掛け算し、その結果をc[k]に加算します
c[k] += b[i] * a[i_ - i];
}
}
}
// 計算が完了した結果ベクトルcを返します
return (c);
}
VectorConvolutionSame関数の解説
VectorConvolutionSame関数は、2つのベクトル(a
とb
)を入力として受け取り、元のベクトルの長さに一致するような畳み込み結果を計算するための関数です。この「Sameモード」では、計算結果が中央寄せされるため、入力ベクトルの情報をバランスよく保持した結果が得られます。
1. 入力ベクトルの順序を確認する
関数の最初では、a.Size()
(ベクトルa
の長さ)とb.Size()
(ベクトルb
の長さ)を比較し、もしa
がb
より短い場合は、VectorConvolutionSame関数を再帰的に呼び出します。このとき引数の順序を入れ替え、長いベクトルを常にa
として扱います。これにより、以降の処理を簡単にすることができます。
2. 結果ベクトルのサイズを計算する
次に、MathMax(a.Size(), b.Size())を使用して、入力ベクトルのうち長い方のサイズを計算します。このサイズは、結果ベクトルc
の長さとして使用されます。
3. 結果ベクトルの初期化
vector::Zeros(size)を用いて、結果ベクトルc
をすべての要素が0の状態で初期化します。このc
に畳み込み計算の結果を順次格納していきます。
畳み込み計算の仕組み
畳み込みの計算は、2つの入れ子状のループを使って行います。
外側のループ
外側のループはfor(int i = 0; i < b.Size(); i++)という形で、ベクトルb
の各要素(b[i]
)を1つずつ処理します。
内側のループ
内側のループはfor(int i_ = i; i_ < i + a.Size(); i_++)という形で、a
の要素とb[i]
を掛け算します。このとき、掛け算の結果をc
の対応する位置に加算します。
インデックスの計算
k = i_ - size / 2 + 1
ここでi_
は内側のループ内で現在の位置を表し、size / 2
は中央寄せを行うための調整値です。k
が0以上かつsize
未満の場合のみ、c[k]
に値を加算します。
具体的な計算例
入力
a = [1, 2, 3, 4, 5]
b = [0, 1, 0.5]
計算手順
b[0]
(値は0)を処理b[0]
を使用する場合、c
には何も加算されません(値が0のため)。
b[1]
(値は1)を処理b[2]
(値は0.5)を処理
結果
最終的な結果ベクトルは以下のようになります。
c = [1, 2.5, 4, 5.5, 7]
同じ長さモードの特性
この計算モードでは、結果ベクトルc
の長さが入力ベクトルの長さと一致します。また、畳み込み計算が中央寄せで行われるため、c
には入力データの特徴がバランスよく反映されます。
まとめ
VectorConvolutionSame関数では、外側のループでb
の各要素を順番に処理し、内側のループでa
の対応する要素と掛け算して結果をc
に格納します。この関数の特長は、結果ベクトルが入力ベクトルの長さと同じになる点と、中央寄せで計算される点です。インデックス計算やループ構造を正確に理解することで、畳み込み処理の動作を把握できます。
Convolve関数のVECTOR_CONVOLVE_VALIDモードの仕組み
//+------------------------------------------------------------------+
//| VectorConvolutionValid関数 |
//| 2つのベクトルを入力として受け取り、畳み込みが完全に成立する部分 |
//| のみを計算して結果を返します。 |
//+------------------------------------------------------------------+
vector VectorConvolutionValid(const vector& a, const vector& b)
{
// ベクトルaがベクトルbより短い場合、順序を入れ替えて再帰的に呼び出します
// これにより、常に長いベクトルをaとして扱うことができます
if (a.Size() < b.Size())
return (VectorConvolutionValid(b, a));
// ベクトルaとbの長さを取得します
int m = (int)a.Size(); // ベクトルaの長さ
int n = (int)b.Size(); // ベクトルbの長さ
// 畳み込み結果のサイズを計算します
// "Valid"モードでは、完全に重なる範囲のみを考慮するため、
// 結果ベクトルの長さは |m - n| + 1 となります
int size = MathMax(m, n) - MathMin(m, n) + 1;
// 結果を格納するためのベクトルcを初期化します
// vector::Zeros(size)を使用して、結果ベクトルのすべての要素を0で初期化します
vector c = vector::Zeros(size);
// 畳み込みの計算を開始します
// 外側のループで、ベクトルbの各要素を順に処理します
for (int i = 0; i < n; i++)
{
// 内側のループで、ベクトルaの対応する要素と掛け算します
for (int i_ = i; i_ < i + m; i_++)
{
// 結果ベクトルcのインデックスkを計算します
// kは"Valid"範囲のインデックスを示します
int k = i_ - n + 1;
// kが結果ベクトルcの範囲内(0以上、size未満)の場合のみ計算を行います
if (k >= 0 && k < size)
{
// ベクトルb[i]とベクトルa[i_-i]を掛け算し、その結果をc[k]に加算します
c[k] += b[i] * a[i_ - i];
}
}
}
// 計算が完了した結果ベクトルcを返します
return (c);
}
VectorConvolutionValid関数の解説
VectorConvolutionValid関数は、2つのベクトル(a
とb
)を入力として受け取り、その完全に重なる部分だけを計算した線形畳み込みの結果を返す関数です。この「Validモード」は、畳み込みが成立する範囲を制限することで、効率的な結果を得るために使われます。
1. 入力ベクトルの順序を確認する
関数の冒頭で、a.Size()
(ベクトルa
の長さ)とb.Size()
(ベクトルb
の長さ)を比較します。もしa
の方がb
より短い場合には、VectorConvolutionValid関数を再帰的に呼び出し、引数の順序を入れ替えます。これにより、常に長いベクトルをa
として処理を進めることができ、コードの複雑さを軽減できます。
2. 結果ベクトルのサイズを計算する
size = MathMax(m, n) - MathMin(m, n) + 1
この式の意味は、2つのベクトルが完全に重なる範囲だけを考慮するということです。短い方のベクトルをスライドさせながら計算するため、結果の長さは短い方の長さに依存します。
3. 結果ベクトルの初期化
次に、vector::Zeros(size)を使い、長さsizeのすべての要素が0のベクトルc
を初期化します。このベクトルに畳み込みの計算結果を格納していきます。
4. 畳み込み計算の仕組み
畳み込みは、2つのループを使って計算します。
- 外側のループ (
i
)
for(int i = 0; i < n; i++)
ベクトルb
の各要素(b[i]
)を順番に処理します。このi
は、現在計算対象のb
のインデックスを表します。 - 内側のループ (
i_
)
for(int i_ = i; i_ < i + m; i_++)
ベクトルa
の各要素をb[i]
と掛け算し、その結果を結果ベクトルc
の対応する位置に加算します。
5. インデックスkの計算
k = i_ - n + 1
ここで、i_
は内側のループで現在処理中の位置を示します。この式は、a
とb
が完全に重なる範囲を結果ベクトルのインデックスに対応付けるための計算です。
もしk
が0
以上かつs
ize
未満の場合のみ、計算結果がc[k]
に加算されます。この条件は、結果ベクトルの範囲外の計算を防ぐために重要です。
計算例
入力ベクトル
a = [1, 2, 3, 4, 5]
b = [0, 1, 0.5]
計算過程
b[0]
(値は0)の処理
この場合、b[0]
が0のため、c
には何も加算されません。b[1]
(値は1)の処理
次にb[1]
が処理されます。以下のように計算が進みます。c[0] += 1 * 1 = 1
c[1] += 1 * 2 = 2
c[2] += 1 * 3 = 3
b[2]
(値は0.5)の処理
最後にb[2]
が処理されます。c[1] += 0.5 * 1 = 0.5
c[2] += 0.5 * 2 = 1
c[3] += 0.5 * 3 = 1.5
結果
最終的に、結果ベクトルは以下のようになります。
c = [2.5, 4, 5.5]
まとめ
VectorConvolutionValid関数では、ベクトルa
とb
の完全に重なる部分だけを計算して結果を返します。このモードは、畳み込み計算の範囲を厳密に制限するため、計算効率が高くなります。インデックスの計算や範囲チェックを正確に行うことで、入力データの特徴を正しく抽出することができます。
この関数を使うことで、金融データの分析や信号処理など、さまざまな分野で特定の範囲の情報に焦点を当てた処理が可能になります。
Convolve関数を使ったサンプルコード
//+------------------------------------------------------------------+
//| 畳み込み操作の例 |
//| ベクトルaとベクトルbを使用して3種類の畳み込み結果を計算し、 |
//| エキスパートログに出力します。 |
//+------------------------------------------------------------------+
// ベクトルaとbを定義します
vector a = {1, 2, 3, 4, 5}; // ベクトルa: 1から5の連続した整数を持つベクトル
vector b = {0, 1, 0.5}; // ベクトルb: 畳み込み用の小さなベクトル
// "full"モードの畳み込みを計算し、エキスパートログに出力します
// "full"モードでは、2つのベクトルの完全な畳み込み結果を計算します
Print("full\n", a.Convolve(b, VECTOR_CONVOLVE_FULL));
// 期待される結果: [0, 1, 2.5, 4, 5.5, 7, 2.5]
// 計算範囲が広く、最も長い結果を得られます
// "same"モードの畳み込みを計算し、エキスパートログに出力します
// "same"モードでは、元のベクトルと同じ長さの畳み込み結果を計算します
Print("same\n", a.Convolve(b, VECTOR_CONVOLVE_SAME));
// 期待される結果: [1, 2.5, 4, 5.5, 7]
// 中央部分の畳み込み結果に絞られており、入力ベクトルの長さに対応します
// "valid"モードの畳み込みを計算し、エキスパートログに出力します
// "valid"モードでは、2つのベクトルが完全に重なる範囲だけを計算します
Print("valid\n", a.Convolve(b, VECTOR_CONVOLVE_VALID));
// 期待される結果: [2.5, 4, 5.5]
// 畳み込みが成立する最小範囲の結果のみを得られます
/*
出力例:
full
[0, 1, 2.5, 4, 5.5, 7, 2.5]
same
[1, 2.5, 4, 5.5, 7]
valid
[2.5, 4, 5.5]
各モードの出力は、畳み込み結果の取り方が異なることを示しています。
*/
サンプルコード解説
このコードでは、2つのベクトルa
とb
を使い、Convolve関数を用いて3種類の畳み込み(VECTOR_CONVOLVE_FULL、VECTOR_CONVOLVE_SAME、VECTOR_CONVOLVE_VALID)を計算し、エキスパートログに出力しています。それぞれのモードは、畳み込み結果をどのように計算するかが異なります。
1. ベクトルの定義
最初に、畳み込みの対象となるベクトルa
とb
を定義しています。
これらを使用して、以下の3種類の畳み込みを計算します。
2. “full”モードの畳み込み
Print("full\n", a.Convolve(b, VECTOR_CONVOLVE_FULL));
- VECTOR_CONVOLVE_FULLモードを使用した畳み込みでは、2つのベクトルがすべての範囲で重なった場合の結果を計算します。
- このモードの計算結果は、最も長いベクトルとなります。
- 期待される出力は[0, 1, 2.5, 4, 5.5, 7, 2.5]です。
計算過程の詳細
計算過程については、「Convolve関数のVECTOR_CONVOLVE_FULLモードの仕組み」セクションを参照してください。このセクションでは、どのように要素が掛け算され、結果が加算されるかを丁寧に説明しています。
3. “same”モードの畳み込み
Print("same\n", a.Convolve(b, VECTOR_CONVOLVE_SAME));
- VECTOR_CONVOLVE_SAMEモードでは、結果の長さがベクトル
a
と同じになります。 - 畳み込み計算の中心部分を切り出して、元のデータの長さを維持した結果を返します。
- 期待される出力は[1, 2.5, 4, 5.5, 7]です。
計算過程の詳細
計算の仕組みについては、「Convolve関数のVECTOR_CONVOLVE_SAMEモードの仕組み」セクションを参照してください。このセクションでは、どのように中央寄せが行われるかを詳しく解説しています。
4. “valid”モードの畳み込み
Print("valid\n", a.Convolve(b, VECTOR_CONVOLVE_VALID));
- VECTOR_CONVOLVE_VALIDモードでは、畳み込みが完全に成立する範囲のみを計算します。
- そのため、結果の長さは他のモードに比べて短くなります。
- 期待される出力は
[2.5, 4, 5.5]
です。
計算過程の詳細
このモードの計算過程は、「Convolve関数のVECTOR_CONVOLVE_VALIDモードの仕組み」セクションを参照してください。このセクションでは、完全に重なる範囲のみに注目する仕組みが説明されています。
3種類のモードの違いと用途
- VECTOR_CONVOLVE_FULLモード
最も広い範囲を計算し、元のデータ全体にフィルタを適用した効果を観察する場合に便利です。 - VECTOR_CONVOLVE_SAMEモード
元のベクトルと同じ長さの結果が必要な場合や、データの中心部分に焦点を当てたい場合に役立ちます。 - VECTOR_CONVOLVE_VALIDモード
畳み込みが完全に成立する部分だけを計算するため、効率よく結果を得たい場合に使用します。
まとめ
このコードは、a.Convolve(b, mode)を使って、3つの異なるモードでの畳み込み結果を計算する例を示しています。それぞれのモードの詳細な計算過程については、オリジナル関数(VectorConvolutionFull、VectorConvolutionSame、VectorConvolutionValid)のセクションを参照すると、どの要素がどのように計算されているかを具体的に理解できます。
このように、モードの選択に応じて異なる結果が得られるため、用途に応じた使い分けが重要です。エキスパートログに出力された結果を観察することで、モードごとの違いを確認してください。