English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
preview
MQL5에서 행렬 및 벡터

MQL5에서 행렬 및 벡터

MetaTrader 5트레이딩 | 9 1월 2023, 15:59
388 0
MetaQuotes
MetaQuotes

모든 요소가 동일한 유형을 갖는 정렬된 데이터 모음의 경우 일반적으로 각 요소가 해당 인덱스로 액세스할 수 있는Arrays를 통해 작동됩니다. 배열은 다양한 선형 대수 문제 해결, 수학적 모델링 작업, 머신 러닝 등에서 널리 사용됩니다. 일반적으로 이러한 문제의 해결은 행렬과 벡터를 사용하는 수학적 연산을 기반으로 하며 매우 복잡한 변환을 간단한 공식의 형태로 간결하게 작성할 수 있습니다. 이러한 작업을 프로그래밍 하려면 복잡한 중첩 루프를 작성할 수 있는 능력과 함께 수학에 대한 많은 지식이 필요합니다. 이러한 프로그램에서 디버깅을 하고 버그를 수정하는 작업은 상당히 어려울 수 있습니다. 

특수 데이터 유형 'matrix' 및 'vector'를 사용하면 중첩된 루프를 만들거나 계산에서 배열의 올바른 인덱싱을 염두에 둘 필요 없이 수학적 표기법에 매우 가까운 코드를 만들 수 있습니다. 이 기사에서는 MQL5에서 행렬벡터 객체를 생성하고 초기화 하고 사용하는 방법을 살펴봅니다.


'vector'를 입력합니다.

vector는 1차원 double형 배열입니다. 다음 작업은 벡터에서 정의됩니다: 더하기 및 곱하기 그리고 벡터의 길이 또는 모듈을 얻기 위한 Norm. 프로그래밍에서 벡터는 일반적으로 정규 벡터 연산이 정의되지 않은 동종 요소의 배열로 표현됩니다. 즉 배열을 더하거나 곱할 수 없으며 노름이 없습니다.

수학에서 벡터는 행 벡터, 즉 1행과 n열로 구성된 배열과 문자열 벡터, 즉 1열과 n행으로 구성된 행렬로 나타낼 수 있습니다. MQL5에서 'vector' 유형에는 행 및 열 하위 유형이 없으므로 프로그래머는 특정 작업에서 어떤 벡터 유형이 사용되는지를 이해해야 합니다.

다음의 기본으로 제공되는 메서드를 사용하여 벡터를 만들고 초기화합니다.

메서드
넘파이 아날로그
설명
void vector.Init(ulong size);   값이 정의되지 않은 지정된 길이의 벡터를 만듭니다.
static vector vector::Ones(ulong size);
 
1로 채워진 지정된 길이의 벡터를 만듭니다.
static vector vector::Zeros(ulong size);
 0
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() 메서드는 벡터에 대한 메모리를 할당하는 데 사용할 수 있을 뿐만 아니라 함수를 사용하여 벡터 요소를 값으로 초기화하는 데에도 사용할 수 있습니다. 이 경우 벡터 크기가 첫 번째 매개변수로 Init에 전달되고 함수 이름이 두 번째 매개변수로 전달됩니다. 함수에 매개변수가 포함된 경우 이러한 매개변수는 함수 이름 바로 뒤에 쉼표로 구분하여 지정되어야 합니다.

함수 자체에 첫 번째 매개변수로 전달되는 벡터에 대한 참조를 포함해야 합니다. 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"이라는 두 개의 선택적 매개변수가 있습니다. 따라서 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]

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

벡터는 두 개의 동일한 크기 벡터의 덧셈, 뺄셈, 곱셈 및 나눗셈의 요소별 연산을 지원합니다.

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]

*/

이 데이터 유형에 대해 네 가지의 곱셈 작업이 정의됩니다.

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도 같은 방식으로 작동합니다.


벡터 노름

벡터 및 행렬 노름은 벡터 길이(크기)와 절대값을 나타냅니다. 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

*/

노름을 사용하여 두 벡터 사이의 거리를 측정할 수 있습니다:

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

*/


'매트릭스' 유형

벡터는 double 유형의 2차원 배열인 행렬의 특수한 경우입니다. 따라서 행렬을 동일한 크기의 벡터의 배열로 간주할 수 있습니다. 행렬의 행의 수는 벡터의 수에 해당하고 열의 수는 벡터 길이와 같습니다. 

덧셈과 곱셈 연산도 행렬에 사용할 수 있습니다. 기존의 프로그래밍 언어는 배열을 사용하여 행렬을 나타냅니다. 그러나 일반 배열은 서로 더하거나 곱할 수 없으며 노름이 없습니다. 수학에서는 다양한 행렬 유형이 있습니다. 예를 들어 항등 행렬, 대칭, 비대칭 대칭, 상부 및 하부 삼각 행렬 및 기타 유형 등이 있습니다.

벡터 메서드와 유사한 기본 내장된 메서드를 사용하여 행렬을 만들고 초기화할 수 있습니다.

메서드

NumPy의 유사한 메서드

설명

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

eye

지정된 대각선에 1이 있고 다른 위치에 0이 있는 행렬을 구성합니다.

void matrix.Identity()

id두샤쇼

주 대각선은 1로, 나머지는 0으로 행렬을 채웁니다.

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

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

스칼라 수로 채워진 행과 열의 수로 새 행렬을 구성합니다.

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]]

*/ 

두 가지 방법으로 값 초기화 없이 행렬을 구성할 수 있습니다: 

//--- 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() - 선형 대수 방정식의 최소 제곱 해를 반환합니다(비제곱 또는 degenerate matrices의 경우).
  • 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)

 

행 순열을 사용하는 LU 분해인 부분 피벗을 사용하여 LUP 분해를 구현합니다. PA = LU


행렬과 벡터의 곱

MatMul()은 행렬과 벡터의 행렬 곱을 계산하기 위해 정의됩니다. 이 방법은 종종 다양한 수학 문제를 푸는 데 사용됩니다. 행렬과 벡터를 곱할 때 다음과 같은 두 가지 옵션이 가능합니다.

  • 왼쪽의 수평 벡터에 오른쪽의 행렬을 곱합니다; 벡터 길이는 행렬의 열 수와 같습니다;
  • 왼쪽의 행렬에 오른쪽의 수직 벡터를 곱합니다; 행렬 열의 수는 벡터 길이와 같습니다.

벡터의 길이가 행렬의 열 수와 같지 않으면 심각한 실행 오류가 생성됩니다.

두 행렬을 곱하려면 다음과 같은 형식이어야 합니다: 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는 구조입니다:
struct complex
  {
   double             real;   // real part
   double             imag;   // imaginary part
  };
'complex' 유형은 값으로 MQL5 함수의 매개변수로 전달될 수 있습니다(참조로만 전달되는 일반 구조와 달리). DLL에서 가져온 함수의 경우 'complex' 유형은 참조로만 전달되어야 합니다.

'i' 접미사는 complex constants를 설명하는 데 사용됩니다:
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 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/9805

데이터 과학 및 머신 러닝(파트 04): 현재 주식 시장 붕괴 예측 데이터 과학 및 머신 러닝(파트 04): 현재 주식 시장 붕괴 예측
이 기사에서는 로지스틱 모델을 사용하여 미국 경제의 펀더멘털을 기반으로 주식 시장 폭락을 예측하려고 합니다. NETFLIX와 APPLE은 우리가 집중해서 볼 주식입니다. 이전의 2019년과 2020년의 시장 폭락을 통해 우리 모델이 현재의 암울한 상황에서 어떻게 작동하는지를 알아 봅시다.
Expert Advisor 개발 기초부터 (파트 12): 시간과 거래(I) Expert Advisor 개발 기초부터 (파트 12): 시간과 거래(I)
오늘은 주문의 흐름을 알아보기 위해 Times & Trade를 만들 것입니다. 이는 우리가 앞으로 구축할 시스템의 첫 번째 부분입니다. 다음 글에서는 추가적인 내용을 더해 시스템을 완성하도록 하겠습니다. 이 새로운 기능을 구현하려면 Expert Advisor 코드에 몇 가지의 새로운 항목을 추가해야 합니다.
데이터 과학 및 머신 러닝(파트 05): 의사 결정 트리 데이터 과학 및 머신 러닝(파트 05): 의사 결정 트리
의사 결정 트리는 인간이 데이터를 분류하기 위해 생각하는 방식을 모방합니다. 트리를 구축하고 트리를 사용하여 데이터를 분류하고 예측하는 방법에 대해 알아보겠습니다. 의사 결정 트리 알고리즘의 주요 목표는 불순물이 있는 데이터를 순수한 것으로 분리하거나 노드에 가깝게 분리하는 것입니다.
MQL5에서 행렬 및 벡터 연산 MQL5에서 행렬 및 벡터 연산
효율적인 연산을 위해 수학적인 솔루션과 함께 행렬과 벡터가 MQL5에 도입되었습니다. 새로운 유형은 수학적인 표기법에 가까운 간결하고 이해하기 쉬운 코드를 생성하도록 하는 기본 메서드를 제공합니다. 배열은 광범위한 기능을 제공하지만 행렬이 훨씬 더 효율적인 경우가 많습니다.