English Русский 中文 Español 日本語 Português 한국어 Français Italiano Türkçe
preview
Matrizen und Vektoren in MQL5

Matrizen und Vektoren in MQL5

MetaTrader 5Handel | 14 Februar 2022, 15:51
601 0
MetaQuotes
MetaQuotes

Kollektionen von geordneten Daten, bei denen alle Elemente den gleichen Typ haben, werden normalerweise über Arrays verwaltet, bei denen auf jedes Element über seinen Index zugegriffen werden kann. Arrays werden häufig bei der Lösung verschiedener Probleme der linearen Algebra, bei mathematischen Modellierungsaufgaben, beim maschinellen Lernen usw. verwendet. Im Allgemeinen basiert die Lösung solcher Probleme auf mathematischen Operationen mit Matrizen und Vektoren, mit denen sehr komplexe Transformationen kompakt in Form einfacher Formeln geschrieben werden können. Die Programmierung solcher Operationen erfordert gute mathematische Kenntnisse und die Fähigkeit, komplexe verschachtelte Schleifen zu schreiben. Die Fehlersuche und -behebung in solchen Programmen kann recht anspruchsvoll sein. 

Durch die Verwendung der speziellen Datentypen 'matrix' und 'vector' ist es möglich, einen Code zu erstellen, der der mathematischen Notation sehr nahe kommt, ohne dass man verschachtelte Schleifen erstellen oder auf die korrekte Indizierung von Arrays in Berechnungen achten muss. In diesem Artikel werden wir sehen, wie man Matrix- und Vektor-Objekte in MQL5 erstellt, initialisiert und verwendet.


Typ 'vector'

vector ist ein eindimensionales Array des Typs double. Für Vektoren sind folgende Operationen definiert: Addition und Multiplikation, sowie die Norm zur Ermittlung der Vektorlänge oder des Moduls. In der Programmierung werden Vektoren in der Regel durch Arrays homogener Elemente dargestellt, für die keine regulären Vektoroperationen definiert werden können, d. h. Arrays können nicht addiert oder multipliziert werden, und sie haben keine Norm.

In der Mathematik können Vektoren als Zeilenvektoren, d. h. als ein Array mit einer Zeile und n Spalten, und als Stringvektoren, d. h. als eine Matrix mit einer Spalte und n Zeilen, dargestellt werden. In MQL5 hat der Typ 'vector' keine Zeilen- und Spalten-Subtypen, so dass der Programmierer wissen muss, welcher Vektortyp in einer bestimmten Operation verwendet wird.

Verwenden Sie die folgenden eingebauten Methoden, um Vektoren zu erzeugen und zu initialisieren.

Methoden
NumPy Analogon
Beschreibung
void vector.Init( ulong size);   Erzeugt einen Vektor der angegebenen Länge mit undefinierten Werten
static vector vector::Ones(ulong size);
 ones
Erzeugt einen Vektor der angegebenen Länge, der mit Einsen gefüllt ist.
static vector vector::Zeros(ulong size);
 zeros
Erzeugt einen Vektor der angegebenen Länge, der mit Nullen gefüllt ist.
static vector vector::Full(ulong size,double value);
 full
Erzeugt einen Vektor der angegebenen Länge, gefüllt mit dem angegebenen Wert.
Operator =

Gibt eine Kopie des Vektors zurück
void vector.Resize(const vector v);
  Ändert die Größe eines Vektors, indem neue Werte am Ende hinzugefügt werden. 


Beispiele für die Erstellung von Vektoren:

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]

*/ 

Die Methode Init() kann nicht nur verwendet werden, um Speicher für den Vektor zuzuweisen, sondern auch, um Vektorelemente mithilfe einer Funktion mit Werten zu initialisieren. In diesem Fall wird die Vektorgröße als erster Parameter und der Funktionsname als zweiter Parameter an Init übergeben. Wenn die Funktion Parameter enthält, sollten diese unmittelbar nach dem Funktionsnamen angegeben werden, getrennt durch ein Komma.

Die Funktion selbst muss einen Verweis auf den Vektor enthalten, der als erster Parameter an die Funktion übergeben wird. Der Vektor sollte beim Aufruf von Init nicht übergeben werden. Schauen wir uns die Arbeitsweise der Methode am Beispiel der Funktion Arange an. Diese Funktion ahmt numpy.arange nach.

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

*/

Die Funktion Arange hat zwei optionale Parameter, "start" und "stop". Daher wären ein weiterer, möglicher Aufruf von Init(7,Arange,10) und das entsprechende Ergebnis wie folgt:

//+------------------------------------------------------------------+
//| 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

*/


Operationen mit Vektoren

Die üblichen Operationen wie Addition, Subtraktion, Multiplikation und Division mit einem Skalar können mit Vektoren durchgeführt werden.

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

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

Vektoren unterstützen elementweise Operationen wie Addition, Subtraktion, Multiplikation und Division von zwei gleich großen Vektoren.

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]

*/

Für diesen Datentyp sind vier Produktoperationen definiert.

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

*/

Wie Sie aus dem Beispiel ersehen können, gibt die Methode Outer eine Matrix zurück, bei der die Anzahl der Zeilen und Spalten den Größen der multiplizierten Vektoren entspricht. Die Methoden Dot und MatMul arbeiten auf die gleiche Weise.


Vektornorm

Die Norm von Vektoren und Matrizen gibt die Länge (Größe) und den absoluten Wert des Vektors an. Drei mögliche Wege zur Berechnung der Norm eines Vektors sind in ENUM_VECTOR_NORM aufgeführt.
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

*/

Mit Hilfe der Norm kann man den Abstand zwischen zwei Vektoren messen:

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

*/


Typ 'Matrix'

Der Vektor ist ein Spezialfall einer Matrix, die eigentlich ein zweidimensionales Feld vom Typ double ist. Eine Matrix kann also als ein Array von gleich großen Vektoren betrachtet werden. Die Anzahl der Zeilen der Matrix entspricht der Anzahl der Vektoren, während die Anzahl der Spalten der Länge der Vektoren entspricht. 

Die Operationen der Addition und Multiplikation sind auch für Matrizen verfügbar. Herkömmliche Programmiersprachen verwenden Arrays zur Darstellung von Matrizen. Reguläre Arrays können jedoch nicht miteinander addiert oder multipliziert werden, und sie haben keine Norm. Die Mathematik kennt viele verschiedene Matrixtypen. Zum Beispiel die Identitätsmatrix, symmetrische, schiefsymmetrische, obere und untere Dreiecksmatrizen und andere Typen.

Eine Matrix kann mit integrierten Methoden erstellt und initialisiert werden, ähnlich wie bei Vektormethoden.

Methode

Analoge Methode in NumPy

Beschreibung

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

eye

Konstruiert eine Matrix mit Einsen auf der angegebenen Diagonale und Nullen an allen anderen Stellen.

void matrix.Identity()

identity

Füllt eine Matrix mit Einsen auf der Hauptdiagonale und Nullen an allen anderen Stellen.

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

ones

Konstruiert eine neue Matrix mit der Anzahl der Zeilen und Spalten, gefüllt mit Einsen.

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

zeros

Konstruiert eine neue Matrix mit der Anzahl der Zeilen und Spalten, die mit Nullen gefüllt ist.

void static matrix.Tri(const int rows, const int cols, const int ndiag=0)
tri  Erzeugt eine Matrix mit Einsen auf der angegebenen Diagonale und darunter und Nullen an allen anderen Stellen. 
void matrix.Diag(const vector v, const int ndiag=0)  diag  Extrahiert eine Diagonale oder konstruiert eine Diagonalmatrix. 

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

full

Konstruiert eine neue Matrix mit der Anzahl der Zeilen und Spalten, gefüllt mit einem Skalarwert.

void matrix.Fill(const scalar value)     Füllt die Matrix mit dem angegebenen Wert.


Beispiele für den Aufbau und das Füllen einer Matrix:

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

*/

Das folgende Beispiel zeigt, wie Sie beim Füllen von Matrizen nutzerdefinierte Funktionen verwenden können:

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

*/ 

Eine Matrix kann ohne Wertinitialisierung auf zwei Arten konstruiert werden: 

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

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


Matrixnorm

Die neun Möglichkeiten zur Berechnung der Norm einer Matrix sind in ENUM_MATRIX_NORM aufgeführt.

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

*/


Operationen mit Matrizen und Vektoren

Matrizen bieten spezielle Methoden zum Lösen mathematischer Probleme:

  • Transposition
  • Elementweise Matrixaddition, -subtraktion, -multiplikation und -division
  • Addition, Subtraktion, Multiplikation und Division von Matrixelementen durch einen Skalar
  • Produkt von Matrizen und Vektoren mit der MatMul-Methode (Matrixprodukt)
  • Inner()
  • Outer()
  • Kron()
  • Inv() —Inverse einer Matrix
  • Solve() — löst ein System linearer Gleichungen
  • LstSq() — gibt die Lösung der kleinsten Quadrate von linearen algebraischen Gleichungen zurück (für nicht quadratische oder entartete Matrizen)
  • PInv() — Pseudo-Inverse Kleinste-Quadrate-Matrix
  • Operationen mit Spalten, Zeilen und Diagonalen

Matrix-Zerlegung:

Methode

Analoge Methode in NumPy

Beschreibung
bool matrix.Cholesky(matrix& L) cholesky Berechnet die Cholesky-Zerlegung
bool matrix.QR(matrix& Q, matrix& R) qr

Berechnet die QR-Zerlegung

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

svd

Berechnet die SVD-Zerlegung

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

eig

Berechnet die Eigenwerte und rechten Eigenvektoren einer quadratischen Matrix

bool matrix.EigVals(vector& eigen_values)

eigvals

Berechnet die Eigenwerte einer allgemeinen Matrix

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

 

Führt eine LU-Zerlegung einer Matrix durch: das Produkt aus einer unteren Dreiecksmatrix und einer oberen Dreiecksmatrix

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

 

Implementiert eine LUP-Zerlegung mit partieller Pivotisierung, d.h. eine LU-Faktorisierung mit einer Permutation der Zeilen: PA = LU


Produkt von Matrizen und Vektoren

MatMul() ist definiert, um das Matrixprodukt von Matrizen und Vektoren zu berechnen. Diese Methode wird häufig bei der Lösung verschiedener mathematischer Probleme verwendet. Bei der Multiplikation einer Matrix und eines Vektors sind die folgenden zwei Optionen möglich:

  • Der horizontale Vektor auf der linken Seite wird mit der Matrix auf der rechten Seite multipliziert; die Länge des Vektors ist gleich der Anzahl der Spalten der Matrix;
  • Die Matrix auf der linken Seite wird mit dem vertikalen Vektor auf der rechten Seite multipliziert; die Anzahl der Spalten der Matrix ist gleich der Länge des Vektors.

Wenn die Vektorlänge nicht gleich der Anzahl der Spalten der Matrix ist, wird ein kritischer Ausführungsfehler erzeugt.

Um zwei Matrizen zu multiplizieren, sollte ihre Form wie folgt sein: A[M,N] * B[N,K] = C[M,K], d.h. die Anzahl der Spalten in der Matrix auf der linken Seite muss gleich der Anzahl der Zeilen in der Matrix auf der rechten Seite sein. Wenn die Dimensionen nicht konsistent sind, ist das Ergebnis eine leere Matrix. Schauen wir uns alle Varianten des Matrixprodukts anhand von Beispielen an.

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

*/

Zum besseren Verständnis, wie Matrix- und Vektortypen angeordnet sind, zeigen diese Beispiele, wie Matrizen anstelle von Vektoren verwendet werden können. Das bedeutet, dass Vektoren als Matrizen dargestellt werden können.


Komplexe Zahlen vom Typ 'komplex'

Einige mathematische Probleme erfordern die Verwendung des neuen Datentyps 'komplexe Zahlen'. Der Typ complex ist eine Struktur:
struct complex
  {
   double             real;   // real part
   double             imag;   // imaginary part
  };
Der Typ 'complex' kann der Parameter als Wert für MQL5-Funktionen übergeben werden (im Gegensatz zu gewöhnlichen Strukturen, die nur als Referenz übergeben werden). Bei Funktionen, die aus DLLs importiert werden, muss der 'komplexe' Typ als Referenz übergeben werden.

Das Suffix 'i' wird verwendet, um komplexe Werte zu beschreiben:
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
Für komplexe Zahlen gibt es nur einfache Operationen: =, +, -, *, /, +=, -=, *=, /=, ==, !=.

Unterstützung für weitere mathematische Funktionen wird demnächst hinzugefügt, sodass die Berechnung von Absolutwert, Sinus, Kosinus und anderen möglich ist.

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/9805

Verbesserte Erkennung von Kerzenmustern am Beispiel des Doji Verbesserte Erkennung von Kerzenmustern am Beispiel des Doji
Wie kann man mehr Kerzenmuster als üblich finden? Hinter der Einfachheit von Kerzenmustern verbirgt sich auch ein schwerwiegender Nachteil, der durch die Nutzung der erheblich erweiterten Möglichkeiten moderner Handelsautomatisierungs-Tools beseitigt werden kann.
Kombinatorik und Wahrscheinlichkeitsrechnung für den Handel (Teil V): Kurvenanalyse Kombinatorik und Wahrscheinlichkeitsrechnung für den Handel (Teil V): Kurvenanalyse
In diesem Artikel habe ich mich entschlossen, eine Studie über die Möglichkeit der Reduzierung mehrerer Zustände auf Systeme mit zwei Zuständen durchzuführen. Der Hauptzweck des Artikels besteht darin, zu analysieren und zu nützlichen Schlussfolgerungen zu gelangen, die bei der weiteren Entwicklung skalierbarer Handelsalgorithmen auf der Grundlage der Wahrscheinlichkeitstheorie hilfreich sein können. Natürlich ist dieses Thema mit Mathematik verbunden. Angesichts der Erfahrungen aus früheren Artikeln sehe ich jedoch, dass allgemeine Informationen nützlicher sind als Details.
Grafiken in der DoEasy-Bibliothek (Teil 91): Standard-Ereignisse für grafische Objekte. Geschichte der Objektnamensänderung Grafiken in der DoEasy-Bibliothek (Teil 91): Standard-Ereignisse für grafische Objekte. Geschichte der Objektnamensänderung
In diesem Artikel werde ich die Grundfunktionalität für die Kontrolle über grafische Objektereignisse in einem bibliotheksbasierten Programm verfeinern. Ich beginne mit der Implementierung der Funktionalität zur Speicherung der Änderungshistorie grafischer Objekte am Beispiel der Eigenschaft "Objektname".
Grafiken in der DoEasy-Bibliothek (Teil 90): Standard-Ereignisse für grafische Objekte. grundlegende Funktionsweise Grafiken in der DoEasy-Bibliothek (Teil 90): Standard-Ereignisse für grafische Objekte. grundlegende Funktionsweise
In diesem Artikel werde ich die grundlegenden Funktionen für die Verfolgung von Standardereignissen für grafische Objekte implementieren. Ich werde von einem Doppelklick-Ereignis auf ein grafisches Objekt ausgehen.