MQL5の行列とベクトル

16 2月 2022, 08:30
MetaQuotes
0
588

すべての要素が同じ型である順序付きデータのコレクションは、通常、配列を介して操作されます。配列では、各要素にそのインデックスからアクセスできます。配列は、さまざまな線形代数の問題の解決、数学的モデリングのタスク、機械学習などで広く使用されています。一般的に言えば、このような問題の解決は行列とベクトルを使用した数学演算に基づいており、非常に複雑な変換を単純な数式の形式でコンパクトに記述できます。このような演算をプログラミングするには、複雑な入れ子ループを作成する能力に加えて、数学に関する十分な知識が必要です。このようなプログラムでのデバッグとバグ修正は、非常に困難になりえます。 

特別な「matrix」と「vectorデータ型を使用すると、計算で入れ子ループを作成したり、配列の正しいインデックス付けをしたりする必要をなくしながら、数学表記に非常に近いコードを作成できます。この記事では、MQL5でmatrixおよびvectorオブジェクトを作成、初期化、および使用する方法を説明します。


「vector」型

vectorは、1次元のdouble型配列です。ベクトルでは加算と乗算、およびベクトルの長さまたはモジュールを取得するためのノルムの演算が定義されています。プログラミングでは、ベクトルは通常、同種の要素の配列で表されますが、配列では通常のベクトル演算を定義できません。つまり、配列を追加または乗算することはできず、ノルムもありません。

数学では、ベクトルは行ベクトル(1行とn列で構成される配列)および列ベクトル(1列とn行の行列)として表すことができます。列ベクトルMQL5の「vector」型には行と列のサブタイプがないため、プログラマーは特定の操作で使用されるベクトルタイプを理解する必要があります。

ベクトルを作成および初期化するには、次の組み込みメソッドを使用します。

メソッド
NumPy対応
説明
void vector.Init( ulong size);   指定された長さのベクトルを作成(値は未定義)
static vector vector::Ones(ulong size);
 ones
指定された長さのベクトルを作成(値は1)
static vector vector::Zeros(ulong size);
 zeros
指定された長さのベクトルを作成(値は0)
static vector vector::Full(ulong size,double value);
 full
指定された長さのベクトルを作成(値を指定)
operator =

ベクトルのコピーを返す
void vector.Resize(const vector v);
  末尾に新しい値を追加して、ベクトルをサイズ変更 


以下は、ベクトル作成の例です。

void OnStart()
 {
//--- vector initialization examples
  vector v;
  v.Init(7);
  Print("v = ", v); 

  vector v1=vector::Ones(5);
  Print("v1 = ", v1);

  vector v2=vector::Zeros(3);
  Print("v2 = ", v2);

  vector v3=vector::Full(6, 2.5);
  Print("v3 = ", v3);

  vector v4{1, 2, 3};
  Print("v4 = ", v4);  
  v4.Resize(5);
  Print("after Resize(5) v4 = ", v4);  
  
  vector v5=v4;
  Print("v5 = ", v5);  
  v4.Fill(7);
  Print("v4 = ", v4, "   v5 =",v5);  
   
 }
 

/*
Execution result

v = [4,5,6,8,10,12,12]
v1 = [1,1,1,1,1]
v2 = [0,0,0]
v3 = [2.5,2.5,2.5,2.5,2.5,2.5]
v4 = [1,2,3]
after Resize(5) v4 = [1,2,3,7,7]
v5 = [1,2,3,7,7]
v4 = [7,7,7,7,7]   v5 =[1,2,3,7,7]

*/ 

Init()メソッドは、ベクトルにメモリを割り当てるだけでなく、関数を使用してベクトル要素を値で初期化するためにも使用できます。この場合、ベクトルサイズは最初のパラメータとして渡され、関数名は2番目のパラメータとして渡されます。関数にパラメータが含まれている場合、これらのパラメータは、関数名の直後にコンマで区切って指定されます。

関数自体には、最初のパラメータとして渡されるベクトルへの参照が含まれている必要があります。Init呼び出し中にベクトルを渡さないでください。例として、Arange関数を使用したメソッド操作を見てみましょう。この関数はnumpy.arangeを模倣しています。

void OnStart()
  {
//---
   vector v;
   v.Init(7,Arange,10,0,0.5); // 3 parameters are passed with Arange call
   Print("v = ", v);
   Print("v.size = ",v.Size());
  }
//+------------------------------------------------------------------+
//|  Values are generated within the half-open interval [start, stop)|
//+------------------------------------------------------------------+
void Arange(vector& v, double stop, double start = 0, double step = 1) // the function has 4 parameters
  {
   if(start >= stop)
     {
      PrintFormat("%s wrong parameters! start=%G  stop=%G", __FILE__,start, stop);
      return;
     }
//---
   int size = (int)((stop - start) / step);
   v.Resize(size);
   double value = start;
   for(ulong i = 0; i < v.Size(); i++)
     {
      v[i] = value;
      value += step;
     }
  }
  
/*
Execution result

v = [0,0.5,1,1.5,2,2.5,3,3.5,4,4.5,5,5.5,6,6.5,7,7.5,8,8.5,9,9.5]
v.size = 20

*/

Arange関数には、「start」と「stop」の2つのオプションパラメータがあります。Init(7,Arange,10)の別の可能な呼び出しと関連する結果は、次のとおりです。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   vector v;
   v.Init(7,Arange,10);
   Print("v = ", v);
   Print("v.size = ",v.Size());
  }
...

/*

v = [0,1,2,3,4,5,6,7,8,9]
v.size = 10

*/


ベクトル操作

スカラーを使用した加算、減算、乗算、除算の通常の演算は、ベクトルに対しても実行できます。

//+------------------------------------------------------------------+
//|                                              vector2_article.mq5 |
//|                                  Copyright 2021, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
 {
//---
  vector v= {1, 2, 3, 4, 5};
  Print("Examples without saving vector changes");
  Print("v = ", v);
  Print("v+5 = ", v+5);
  Print("v-Pi= ", v-M_PI);
  Print("v*2.0= ", v*2);
  Print("v/3.0= ", v/3.0);

  Print("Save all vector changes");
  Print("v = ", v);
  Print("v+5 = ", v=v+5);
  Print("v-Pi= ", v=v-M_PI);
  Print("v*2.0= ", v= v*2);
  Print("v/3.0= ", v= v/3.0);
 }
/*
Execution result
   
Examples without saving vector changes
v = [1,2,3,4,5]
v+5 = [6,7,8,9,10]
v-Pi= [-2.141592653589793,-1.141592653589793,-0.1415926535897931,0.8584073464102069,1.858407346410207]
v*2.0= [2,4,6,8,10]
v/3.0= [0.3333333333333333,0.6666666666666666,1,1.333333333333333,1.666666666666667]
Save all vector changes
v = [1,2,3,4,5]
v+5 = [6,7,8,9,10]
v-Pi= [2.858407346410207,3.858407346410207,4.858407346410207,5.858407346410207,6.858407346410207]
v*2.0= [5.716814692820414,7.716814692820414,9.716814692820414,11.71681469282041,13.71681469282041]
v/3.0= [1.905604897606805,2.572271564273471,3.238938230940138,3.905604897606805,4.572271564273471]

*/
//+------------------------------------------------------------------+

2つの同じサイズのベクトルでは、要素ごとの加算、減算、乗算、除算の演算が可能です。

void OnStart()
  {
//---
   vector a = {1, 2, 3};
   vector b = {2, 4, 6};
   Print("a + b = ", a + b);
   Print("a - b = ", a - b);
   Print("a * b = ", a * b);
   Print("b / a = ", b / a);
  }

/*
Execution result

a + b = [3,6,9]
a - b = [-1,-2,-3]
a * b = [2,8,18]
b / a = [2,2,2]

*/

このデータ型には、4つの乗算操作が定義されています。

void OnStart()
 {
//---
  vector a={1, 2, 3};
  vector b={4, 5, 6};
  Print("a = ", a);
  Print("b = ", b);
  Print("1) a.Dot(b) = ", a.Dot(b));
  Print("2) a.MatMul(b) = ", a.MatMul(b));
  Print("3) a.Kron(b) = ", a.Kron(b));
  Print("4) a.Outer(b) = \n", a.Outer(b));
 }
/*
Execution result

a = [1,2,3]
b = [4,5,6]
1) a.Dot(b) = 32.0
2) a.MatMul(b) = 32.0
3) a.Kron(b) = [[4,5,6,8,10,12,12,15,18]]
4) a.Outer(b) = 
[[4,5,6]
 [8,10,12]
 [12,15,18]]

*/

例からわかるように、Outerメソッドは、行と列の数が乗算されたベクトルのサイズに対応する行列を返します。DotとMatMulは同じように動作します。


ベクトルのノルム

ベクトルと行列のノルムは、ベクトルの長さ(大きさ)と絶対値を表します。ベクトルのノルムを計算するための3つの可能な方法は、ENUM_VECTOR_NORMにリストされています。
void OnStart()
 {
//---
  struct str_vector_norm
   {
    ENUM_VECTOR_NORM  norm;
    int               value;
   };
  str_vector_norm vector_norm[]=
   {
     {VECTOR_NORM_INF,       0},
     {VECTOR_NORM_MINUS_INF, 0},
     {VECTOR_NORM_P,         0},
     {VECTOR_NORM_P,         1},
     {VECTOR_NORM_P,         2},
     {VECTOR_NORM_P,         3},
     {VECTOR_NORM_P,         4},
     {VECTOR_NORM_P,         5},
     {VECTOR_NORM_P,         6},
     {VECTOR_NORM_P,         7},
     {VECTOR_NORM_P,        -1},
     {VECTOR_NORM_P,        -2},
     {VECTOR_NORM_P,        -3},
     {VECTOR_NORM_P,        -4},
     {VECTOR_NORM_P,        -5},
     {VECTOR_NORM_P,        -6},
     {VECTOR_NORM_P,        -7}
   };
  vector v{1, 2, 3, 4, 5, 6, 7};
  double norm;
  Print("v = ", v);
//---
  for(int i=0; i<ArraySize(vector_norm); i++)
   {
    switch(vector_norm[i].norm)
     {
      case VECTOR_NORM_INF :
        norm=v.Norm(VECTOR_NORM_INF);
        Print("v.Norm(VECTOR_NORM_INF) = ", norm);
        break;
      case VECTOR_NORM_MINUS_INF :
        norm=v.Norm(VECTOR_NORM_MINUS_INF);
        Print("v.Norm(VECTOR_NORM_MINUS_INF) = ", norm);
        break;
      case VECTOR_NORM_P :
        norm=v.Norm(VECTOR_NORM_P, vector_norm[i].value);
        PrintFormat("v.Norm(VECTOR_NORM_P,%d) = %G", vector_norm[i].value, norm);
     }
   }
 }
/*

v = [1,2,3,4,5,6,7]
v.Norm(VECTOR_NORM_INF) = 7.0
v.Norm(VECTOR_NORM_MINUS_INF) = 1.0
v.Norm(VECTOR_NORM_P,0) = 7
v.Norm(VECTOR_NORM_P,1) = 28
v.Norm(VECTOR_NORM_P,2) = 11.8322
v.Norm(VECTOR_NORM_P,3) = 9.22087
v.Norm(VECTOR_NORM_P,4) = 8.2693
v.Norm(VECTOR_NORM_P,5) = 7.80735
v.Norm(VECTOR_NORM_P,6) = 7.5473
v.Norm(VECTOR_NORM_P,7) = 7.38704
v.Norm(VECTOR_NORM_P,-1) = 0.385675
v.Norm(VECTOR_NORM_P,-2) = 0.813305
v.Norm(VECTOR_NORM_P,-3) = 0.942818
v.Norm(VECTOR_NORM_P,-4) = 0.980594
v.Norm(VECTOR_NORM_P,-5) = 0.992789
v.Norm(VECTOR_NORM_P,-6) = 0.99714
v.Norm(VECTOR_NORM_P,-7) = 0.998813

*/

ノルムを使用すると、2つのベクトル間の距離を測定できます。

void OnStart()
 {
//---
   vector a{1,2,3};
   vector b{2,3,4};
   double distance=(b-a).Norm(VECTOR_NORM_P,2);
   Print("a = ",a);
   Print("b = ",b);
   Print("|a-b| = ",distance);   
 }
/*
Execution result

a = [1,2,3]
b = [2,3,4]
|a-b| = 1.7320508075688772

*/


「matrix」型

ベクトルは行列の特殊なケースであり、実際にはdouble型の2次元配列です。したがって、行列は同じサイズのベクトルの配列と見なすことができます。行列の行数はベクトルの数に対応し、列の数はベクトルの長さに等しくなります。 

加算と乗算の演算は、行列にも使用できます。従来のプログラミング言語は配列を使用して行列を表しますが、通常の配列は相互に加算または乗算することはできず、ノームもありません。 数学では多くの異なる行列タイプを考慮します。例は、単位行列、対称行列、交代行列、上三角行列と下三角行列、およびその他のタイプです。

行列は、ベクトルメソッドと同様の組み込みメソッドを使用して作成および初期化できます。

メソッド

NumPyの対応メソッド

説明

void static matrix.Eye(const int rows, const int cols, const int ndiag=0)

eye

指定された対角線上に1、その他の場所に0を持つ行列を作成

void matrix.Identity()

identity

行列の主対角線上に1、他の場所に0を入力

void static matrix.Ones(const int rows, const int cols)

ones

行と列の数で新しい行列を作成し、1を入力

void static matrix.Zeros(const int rows, const int cols)

zeros

行と列の数で新しい行列を作成し、0を入力

void static matrix.Tri(const int rows, const int cols, const int ndiag=0)
tri  指定された対角線以下に1、その他の場所に0を持つ行列を作成 
void matrix.Diag(const vector v, const int ndiag=0)  diag  対角線を抽出または対角行列を作成 

void matrix.Full(const int rows, const int cols, const scalar value)

full

行と列の数で新しい行列を作成し、1を入力

void matrix.Fill(const scalar value)     指定された値で行列に入力


以下は、行列の構築とデータ入力の例です。

void OnStart()
 {
//---
  matrix m{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
  Print("m = \n", m);
  matrix ones=matrix::Ones(4, 4);
  Print("ones = \n", ones);
  matrix zeros=matrix::Zeros(4, 4);
  Print("zeros = \n", zeros);
  matrix eye=matrix::Eye(4, 4);
  Print("eye = \n", eye);

  matrix identity(4, 5);
  Print("matrix_identity\n", identity);
  identity.Identity();
  Print("matrix_identity\n", identity);

  matrix tri=matrix::Tri(3, 4);
  Print("tri = \n", tri);
  Print("tri.Transpose() = \n", tri.Transpose()); // transpose the matrix

  matrix diag(5, 5);
  Print("diag = \n", diag);
  vector d{1, 2, 3, 4, 5};
  diag.Diag(d);
  Print("diag = \n", diag); // insert values from the vector into the matrix diagonal

  matrix fill(5, 5);
  fill.Fill(10);
  Print("fill = \n", fill);

  matrix full =matrix::Full(5, 5, 100);
  Print("full = \n", full);


  matrix init(5, 7);
  Print("init = \n", init);
  m.Init(4, 6);
  Print("init = \n", init);
  
  matrix resize=matrix::Full(2, 2, 5);  
  resize.Resize(5,5);
  Print("resize = \n", resize);  
 }
/*
Execution result

m =
[[1,2,3]
[4,5,6]
[7,8,9]]
ones =
[[1,1,1,1]
[1,1,1,1]
[1,1,1,1]
[1,1,1,1]]
zeros =
[[0,0,0,0]
[0,0,0,0]
[0,0,0,0]
[0,0,0,0]]
eye =
[[1,0,0,0]
[0,1,0,0]
[0,0,1,0]
[0,0,0,1]]
matrix_identity
[[1,0,0,0,0]
[0,1,0,0,0]
[0,0,1,0,0]
[0,0,0,1,0]]
matrix_identity
[[1,0,0,0,0]
[0,1,0,0,0]
[0,0,1,0,0]
[0,0,0,1,0]]
tri =
[[1,0,0,0]
[1,1,0,0]
[1,1,1,0]]
tri.Transpose() =
[[1,1,1]
[0,1,1]
[0,0,1]
[0,0,0]]
diag =
[[0,0,0,0,0]
[0,0,0,0,0]
[0,0,0,0,0]
[0,0,0,0,0]
[0,0,0,0,0]]
diag =
[[1,0,0,0,0]
[0,2,0,0,0]
[0,0,3,0,0]
[0,0,0,4,0]
[0,0,0,0,5]]
fill =
[[10,10,10,10,10]
[10,10,10,10,10]
[10,10,10,10,10]
[10,10,10,10,10]
[10,10,10,10,10]]
full =
[[100,100,100,100,100]
[100,100,100,100,100]
[100,100,100,100,100]
[100,100,100,100,100]
[100,100,100,100,100]]
resize = 
[[5,5,0,0,0]
 [5,5,0,0,0]
 [0,0,0,0,0]
 [0,0,0,0,0]
 [0,0,0,0,0]]

*/

次の例は、カスタム関数を使用して行列に入力する方法を示しています。

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
 {
//---
  matrix random(4, 5, MatrixRandom);
  Print("random = \n",random);
  
  matrix init(3, 6, MatrixSetValues);  
  Print("init = \n", init);
  
 }
//+------------------------------------------------------------------+
//| Fills the matrix with random values                              |
//+------------------------------------------------------------------+
void MatrixRandom(matrix& m)
 {
  for(ulong r=0; r<m.Rows(); r++)
   {
    for(ulong c=0; c<m.Cols(); c++)
     {
      m[r][c]=double(MathRand())/32767.;
     }
   }
 }
//+------------------------------------------------------------------+
//| Fills the matrix with powers of a number                         |
//+------------------------------------------------------------------+
void MatrixSetValues(matrix& m, double initial=1)
 {
  double value=initial;
  for(ulong r=0; r<m.Rows(); r++)
   {
    for(ulong c=0; c<m.Cols(); c++)
     {
      m[r][c]=value;
      value*=2;
     }
   }
 }
 
/*
Execution result

random = 
[[0.4200262459181494,0.5014496292001098,0.7520371105075229,0.652058473464156,0.08783227027191992]
 [0.5991088595233008,0.4311960203863643,0.8718832972197638,0.1350138859218116,0.901882992034669]
 [0.4964445936460463,0.8354747154148991,0.5258339182714317,0.6055482650227363,0.5952940458388012]
 [0.3959166234321116,0.8146916104617451,0.2053590502639851,0.2657551805169835,0.3672292245246742]]
init = 
[[1,2,4,8,16,32]
 [64,128,256,512,1024,2048]
 [4096,8192,16384,32768,65536,131072]]

*/ 

行列は、値の初期化なしで次の2つの方法で作成できます。 

//--- create a matrix of a given 'rows x cols' size
  matrix m(3, 3);

// ------ equivalent
  matrix m;
  m.Resize(3, 3);


行列のノルム

行列のノルムを計算する9つの方法は、ENUM_MATRIX_NORMにリストされています。

void OnStart()
  {
//---
   ENUM_MATRIX_NORM matrix_norm[]= {MATRIX_NORM_FROBENIUS,
                                    MATRIX_NORM_SPECTRAL,
                                    MATRIX_NORM_NUCLEAR,
                                    MATRIX_NORM_INF,
                                    MATRIX_NORM_MINUS_INF,
                                    MATRIX_NORM_P1,
                                    MATRIX_NORM_MINUS_P1,
                                    MATRIX_NORM_P2,
                                    MATRIX_NORM_MINUS_P2
                                   };
   matrix m{{1,2,3},{4,5,6},{7,8,9}};
   Print("matrix m:\n",m);
//--- compute the norm using all ways
   double norm;
   for(int i=0; i<ArraySize(matrix_norm); i++)
     {
      norm=m.Norm(matrix_norm[i]);
      PrintFormat("%d. Norm(%s) = %.6f",i+1, EnumToString(matrix_norm[i]),norm);
     }
//---
   return;
  }

/*
Execution result

matrix m:
[[1,2,3]
[4,5,6]
[7,8,9]]
1. Norm(MATRIX_NORM_FROBENIUS) = 16.881943
2. Norm(MATRIX_NORM_SPECTRAL) = 14.790157
3. Norm(MATRIX_NORM_NUCLEAR) = 17.916473
4. Norm(MATRIX_NORM_INF) = 24.000000
5. Norm(MATRIX_NORM_MINUS_INF) = 6.000000
6. Norm(MATRIX_NORM_P1) = 18.000000
7. Norm(MATRIX_NORM_MINUS_P1) = 12.000000
8. Norm(MATRIX_NORM_P2) = 16.848103
9. Norm(MATRIX_NORM_MINUS_P2) = 0.000000

*/


行列とベクトルを使用した演算

行列は、数学の問題を解くための特別なメソッドを備えています。

  • 転置
  • 要素ごとの行列の加算、減算、乗算、除算
  • スカラーによる行列要素の加算、減算、乗算、除算
  • MatMul法による行列とベクトルの積(行列積)
  • Inner()
  • Outer()
  • Kron()
  • Inv() — 逆行列
  • Solve() — 連立一次方程式を解く
  • LstSq() — 線形代数方程式の最小二乗解を返す(非二乗または縮退行列の場合)
  • PInv() — 疑似逆最小二乗行列
  • 列、行、および対角線を使用した操作

行列分解:

メソッド

NumPyの対応メソッド

説明
bool matrix.Cholesky(matrix& L) cholesky コレスキー分解を算出
bool matrix.QR(matrix& Q, matrix& R) qr

QR分解を算出

bool matrix.SVD(matrix& U, matrix& V, vector& singular_values)

svd

SVD分解を算出

bool matrix.Eig(matrix& eigen_vectors, vector& eigen_values)

eig

正方行列の固有値と右固有ベクトルを算出

bool matrix.EigVals(vector& eigen_values)

eigvals

一般的な行列の固有値を算出

bool matrix.LU(matrix& L, matrix& U)

 

行列のLU分解(下三角行列と上三角行列の積)を実装

bool matrix.LUP(matrix& L, matrix& U, matrix& P)

 

部分ピボット選択を使用してLUP分解を実装(行の順列を使用したLU分解: PA= LU)


行列とベクトルの積

MatMul()は、行列とベクトルの行列積を計算するために定義されており、さまざまな数学問題を解く際によく使用されます。行列とベクトルを乗算する場合、次の2つのオプションが可能です。

  • 左側の水平ベクトルに右側の行列を乗算する(ベクトルの長さは行列の列の数と同じ)
  • 左側の行列に右側の垂直ベクトルを乗算する(行列の列の数はベクトルの長さと同じ)

ベクトルの長さが行列の列数と等しくない場合、重大な実行エラーが生成されます。

2つの行列を乗算するには、その形式はA[M,N] * B[N,K] = C[M,K]のようになります。つまり、左側の行列の列数は、右側の行列の行数と等しくなければなりません。次元が一貫していない場合、結果は空行列になります。例を使用して、行列の積のすべてのバリエーションを見てみましょう。

void OnStart()
  {
//--- initialize matrices
   matrix m35, m52;
   m35.Init(3,5,Arange);
   m52.Init(5,2,Arange);
//---
   Print("1. Product of horizontal vector v[3] and matrix m[3,5]");
   vector v3 = {1,2,3};
   Print("On the left v3 = ",v3);
   Print("On the right m35 = \n",m35);
   Print("v3.MatMul(m35) = horizontal vector v[5] \n",v3.MatMul(m35));
//--- show that this is really a horizontal vector
   Print("\n2. Product of matrix m[1,3] and matrix m[3,5]");
   matrix m13;
   m13.Init(1,3,Arange,1);
   Print("On the left m13 = \n",m13);
   Print("On the right m35 = \n",m35);
   Print("m13.MatMul(m35) = matrix m[1,5] \n",m13.MatMul(m35));

   Print("\n3. Product of matrix m[3,5] and vertical vector v[5]");
   vector v5 = {1,2,3,4,5};
   Print("On the left m35 = \n",m35);
   Print("On the right v5 = ",v5);
   Print("m35.MatMul(v5) = vertical vector v[3] \n",m35.MatMul(v5));
//--- show that this is really a vertical vector
   Print("\n4. Product of matrix m[3,5] and matrix m[5,1]");
   matrix m51;
   m51.Init(5,1,Arange,1);
   Print("On the left m35 = \n",m35);
   Print("On the right m51 = \n",m51);
   Print("m35.MatMul(m51) = matrix v[3] \n",m35.MatMul(m51));

   Print("\n5. Product of matrix m[3,5] and matrix m[5,2]");
   Print("On the left m35 = \n",m35);
   Print("On the right m52 = \n",m52);
   Print("m35.MatMul(m52) = matrix m[3,2] \n",m35.MatMul(m52));

   Print("\n6. Product of horizontal vector v[5] and matrix m[5,2]");
   Print("On the left v5 = \n",v5);
   Print("On the right m52 = \n",m52);
   Print("v5.MatMul(m52) = horizontal vector v[2] \n",v5.MatMul(m52));

   Print("\n7. Outer() product of horizontal vector v[5] and vertical vector v[3]");
   Print("On the left v5 = \n",v5);
   Print("On the right v3 = \n",v3);
   Print("v5.Outer(v3) = matrix m[5,3] \n",v5.Outer(v3));
//--- show that the product of matrices generates the same result
   Print("\n8. Outer() product of the matrix m[1,5] and matrix m[3,1]");
   matrix m15,m31;
   m15.Init(1,5,Arange,1);
   m31.Init(3,1,Arange,1);
   Print("On the left m[1,5] = \n",m15);
   Print("On the right m31 = \n",m31);
   Print("m15.Outer(m31) = matrix m[5,3] \n",m15.Outer(m31));
  }
//+------------------------------------------------------------------+
//|  Fill the matrix with increasing values                          |
//+------------------------------------------------------------------+
void Arange(matrix & m, double start = 0, double step = 1) // the function has three parameters
  {
//---
   ulong cols = m.Cols();
   ulong rows = m.Rows();
   double value = start;
   for(ulong r = 0; r < rows; r++)
     {
      for(ulong c = 0; c < cols; c++)
        {
         m[r][c] = value;
         value += step;
        }
     }
//---     
  }
/*
Execution result

1. Product of horizontal vector v[3] and matrix m[3,5]
On the left v3 = [1,2,3]
On the right m35 =
[[0,1,2,3,4]
 [5,6,7,8,9]
 [10,11,12,13,14]]
v3.MatMul(m35) = horizontal vector v[5]
[40,46,52,58,64]

2. Product of matrix m[1,3] and matrix m[3,5]
On the left m13 =
[[1,2,3]]
On the right m35 =
[[0,1,2,3,4]
 [5,6,7,8,9]
 [10,11,12,13,14]]
m13.MatMul(m35) = matrix m[1,5]
[[40,46,52,58,64]]

3. Product of matrix m[3,5] and vertical vector v[5]
On the left m35 =
[[0,1,2,3,4]
 [5,6,7,8,9]
 [10,11,12,13,14]]
On the right v5 = [1,2,3,4,5]
m35.MatMul(v5) = vertical vector v[3]
[40,115,190]

4. Product of matrix m[3,5] and matrix m[5,1]
On the left m35 =
[[0,1,2,3,4]
 [5,6,7,8,9]
 [10,11,12,13,14]]
On the right m51 =
[[1]
 [2]
 [3]
 [4]
 [5]]
m35.MatMul(m51) = matrix v[3]
[[40]
 [115]
 [190]]

5. Product of matrix m[3,5] and matrix m[5,2]
On the left m35 =
[[0,1,2,3,4]
 [5,6,7,8,9]
 [10,11,12,13,14]]
On the right m52 =
[[0,1]
 [2,3]
 [4,5]
 [6,7]
 [8,9]]
m35.MatMul(m52) = matrix m[3,2]
[[60,70]
 [160,195]
 [260,320]]

6. The product of horizontal vector v[5] and matrix m[5,2]
On the left v5 =
[1,2,3,4,5]
On the right m52 =
[[0,1]
 [2,3]
 [4,5]
 [6,7]
 [8,9]]
v5.MatMul(m52) = horizontal vector v[2]
[80,95]

7. Outer() product of horizontal vector v[5] and vertical vector v[3]
On the left v5 =
[1,2,3,4,5]
On the right v3 =
[1,2,3]
v5.Outer(v3) = matrix m[5,3]
[[1,2,3]
 [2,4,6]
 [3,6,9]
 [4,8,12]
 [5,10,15]]

8. Outer() product of the matrix m[1,5] and matrix m[3,1]
On the left m[1,5] =
[[1,2,3,4,5]]
On the right m31 =
[[1]
 [2]
 [3]]
m15.Outer(m31) = matrix m[5,3]
[[1,2,3]
 [2,4,6]
 [3,6,9]
 [4,8,12]
 [5,10,15]]

*/

行列とベクトルのタイプがどのように配置されているかをよりよく理解するために、これらの例は、ベクトルの代わりに行列を使用する方法を示しています。これは、ベクトルを行列として表すことができることを意味します。


「complex」型の複素数

一部の数学の問題では、新しい「complex」データ型を使用する必要があります。complex型は構造体です。
struct complex
  {
   double             real;   // real part
   double             imag;   // imaginary part
  };
complex型は、MQL5関数のパラメータとして値で渡すことができます(参照によってのみ渡される通常の構造体とは対照的です)。DLLからインポートされた関数の場合、「complex」型は参照によってのみ渡す必要があります。
「i」接尾辞は、複雑な定数を説明するために使用されます。
complex square(complex c)
  {
   return(c*c);
  }
  
void OnStart()
  {
   Print(square(1+2i));  // a constant is passed as a parameter
  }

// will print "(-3,4)" - a string representation of a complex number
複素数では単純な演算(=、+、-、*、/、+ =、-=、* =、/ =、==、!=)のみを使用できます。

まもなく、数学関数のサポートが追加されて、絶対値、正弦、余弦などの計算が可能になります。

MetaQuotes Software Corp.によってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/9805

同事線の例で示されているローソク足パターン認識の改善 同事線の例で示されているローソク足パターン認識の改善
通常より多くのローソク足パターンを見つけるにはどうしたらよいでしょうか。ローソク足パターンの単純さの背後には、深刻な欠点もあります。これは、最新の取引自動化ツールの大幅に強化された機能を使用することで解消できます。
MQL5でのAutoItの使用 MQL5でのAutoItの使用
簡単に説明すると、この記事では、MQL5をAutoItと統合することによってMetraTrader5ターミナルのスクリプトを作成します。その中で、ターミナルのユーザーインターフェイスを操作することによってさまざまなタスクを自動化する方法を説明し、AutoItXライブラリを使用するクラスも紹介します。
DoEasyライブラリのグラフィックス(第91部): 標準グラフィカルオブジェクトのイベントオブジェクト名変更履歴 DoEasyライブラリのグラフィックス(第91部): 標準グラフィカルオブジェクトのイベントオブジェクト名変更履歴
本稿では、ライブラリベースのプログラムからグラフィカルオブジェクトイベントを制御するための基本的な機能を洗練します。例として、「オブジェクト名」プロパティを使用してグラフィカルオブジェクトの変更履歴を保存する機能の実装から始めます。
取引のための組合せ論と確率論(第V部): 曲線分析 取引のための組合せ論と確率論(第V部): 曲線分析
本稿では、複数の状態を持つシステムを2つの状態を持つシステムに単純化する可能性に関する調査を行うことにしました。主な目的は、分析によって確率論に基づくスケーラブルな取引アルゴリズムのさらなる開発に役立つ可能性のある有用な結論を導き出すことです。もちろん、このトピックには数学が関係してきますが、以前の記事での経験から、一般化された情報の方が詳細よりも役立つことがわかっています。