English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
preview
Matrices et vecteurs en MQL5

Matrices et vecteurs en MQL5

MetaTrader 5Trading | 13 février 2023, 14:42
1 205 0
MetaQuotes
MetaQuotes

Les collections de données ordonnées, dans lesquelles tous les éléments ont le même type, sont généralement gérées avec des tableaux, dans lesquels chaque élément est accessible par son index. Les tableaux sont largement utilisés dans la résolution de divers problèmes d'algèbre linéaire, dans les tâches de modélisation mathématique ou dans l'apprentissage automatique. D'une manière générale, la solution de ces problèmes repose sur des opérations mathématiques utilisant des matrices et des vecteurs, grâce auxquelles des transformations très complexes peuvent être écrites de manière compacte sous la forme de formules simples. La programmation de ce genre d’opérations nécessite de bonnes connaissances en mathématiques ainsi que la capacité d'écrire des boucles imbriquées complexes. Le débogage et la correction des bugs dans ce genre de programmes peuvent être assez difficiles. 

En utilisant les types de données spéciaux ’matrix’ et ’vector’, il est possible de créer un code très proche de la notation mathématique tout en évitant de devoir créer des boucles imbriquées ou de tenir compte de l'indexation correcte des tableaux dans les calculs. Dans cet article, nous verrons comment créer, initialiser et utiliser les objets matrix et vector avec MQL5.


Type 'vector' (vecteur)

Le vecteur est un tableau unidimensionnel d’éléments de type double. Les opérations suivantes sont définies sur les vecteurs : addition, multiplication, norme pour obtenir la longueur ou le module du vecteur. En programmation, les vecteurs sont généralement représentés avec des tableaux d'éléments homogènes, sur lesquels aucune opération vectorielle régulière ne peut être définie, c'est-à-dire que les tableaux ne peuvent pas être additionnés ou multipliés, et qu'ils n'ont pas de norme.

En mathématiques, les vecteurs peuvent être représentés comme des vecteurs de ligne, c'est-à-dire un tableau composé d'1 ligne et de n colonnes, et des vecteurs de chaîne, c'est-à-dire une matrice d'1 colonne et de n lignes. En MQL5, le type 'vector' n'a pas de sous-types ligne et colonne. Le développeur doit donc comprendre quel type de vecteur est utilisé dans une opération particulière.

Utilisez les méthodes intégrées suivantes pour créer et initialiser des vecteurs :

Méthodes
Méthodes équivalentes dans NumPy
Description
void vector.Init(ulong size);   Crée un vecteur de la longueur spécifiée, dans lequel les valeurs sont indéfinies.
static vector vector::Ones(ulong size);
 ones
Crée un vecteur de la longueur spécifiée, rempli avec des 1
static vector vector::Zeros(ulong size);
 zeros
Crée un vecteur de la longueur spécifiée, rempli avec des 0
static vector vector::Full(ulong size,double value);
 full
Crée un vecteur de la longueur spécifiée, rempli avec la valeur spécifiée
opérateur =

Retourne une copie du vecteur
void vector.Resize(const vector v);
  Redimensionne un vecteur en ajoutant de nouvelles valeurs à la fin 


Exemples de création de vecteurs :

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]

*/ 

La méthode Init() peut être utilisée pour allouer de la mémoire pour le vecteur, mais aussi pour initialiser ses éléments avec des valeurs en utilisant une fonction. Dans ce cas, la taille du vecteur est transmise à la méthode Init dans le premier paramètre et le nom de la fonction est transmis dans le deuxième paramètre. Si la fonction contient des paramètres, ceux-ci doivent être spécifiés immédiatement après le nom de la fonction, séparés par une virgule.

La fonction elle-même doit contenir une référence au vecteur qui lui est transmis dans le premier paramètre. Le vecteur ne doit pas être passé à l'appel à la méthode Init. Voyons le fonctionnement de la méthode avec la fonction Arange comme exemple. Cette fonction imite 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

*/

La fonction Arange possède 2 paramètres optionnels : "start" et "step". Ainsi, un autre appel possible de Init(7,Arange,10) et son résultat correspondant sont les suivants :

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

*/


Opérations sur les vecteurs

Les opérations habituelles d'addition, de soustraction, de multiplication et de division avec un scalaire peuvent être effectuées sur des vecteurs.

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

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

Les vecteurs prennent en charge les opérations d'addition, de soustraction, de multiplication et de division sur les éléments de 2 vecteurs de même taille.

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]

*/

Quatre opérations de multiplication sont définies pour ce type de données :

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

*/

Comme vous pouvez le voir dans l'exemple, la méthode Outer renvoie une matrice dans laquelle le nombre de lignes et de colonnes correspond aux tailles des vecteurs multipliés. Les méthodes Dot et MatMul fonctionnent de la même manière.


Norme d’un vecteur

La norme d’un vecteur et d’une matrice représente la longueur du vecteur (magnitude) et sa valeur absolue. 3 façons possibles de calculer la norme d'un vecteur sont listées dans 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

*/

En utilisant la norme, vous pouvez mesurer la distance entre 2 vecteurs :

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

*/


Type 'matrix'

Le vecteur est un cas particulier de matrice, qui est en fait un tableau à 2 dimensions d’éléments de type double. Ainsi, une matrice peut être vue comme un tableau de vecteurs de même taille. Le nombre de lignes de la matrice correspond au nombre de vecteurs, et le nombre de colonnes est égal à la longueur des vecteurs. 

L’addition et la multiplication sont également disponibles pour les matrices. Les langages de programmation conventionnels utilisent des tableaux pour représenter les matrices. Mais les tableaux réguliers ne peuvent pas être ajoutés ou multipliés les uns par les autres, et ils n'ont pas de norme. Il existe de nombreux types de matrices différentes en mathématiques. Par exemple, la matrice d'identité, les matrices symétriques, symétriques de biais, triangulaires supérieures ou inférieures.

Une matrice peut être créée et initialisée avec des méthodes intégrées similaires aux méthodes vectorielles.

Méthode

Méthode équivalente dans NumPy

Description

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

eye

Construit une matrice avec des 1 sur la diagonale spécifiée et des 0 ailleurs.

void matrix.Identity()

identity

Remplit une matrice avec des 1 sur la diagonale principale et des 0 ailleurs

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

ones

Construit une nouvelle matrice, du nombre de lignes et de colonnes spécifiés, remplie de 1.

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

zeros

Construit une nouvelle matrice, du nombre de lignes et de colonnes spécifiés, remplie de 0.

void static matrix.Tri(const int rows, const int cols, const int ndiag=0)
tri  Construit une matrice avec des 1 sur la diagonale spécifiée et en dessous et des 0 ailleurs. 
void matrix.Diag(const vector v, const int ndiag=0)  diag  Extrait une diagonale ou construit une matrice diagonale 

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

full

Construit une nouvelle matrice, du nombre de lignes et de colonnes spécifiés, remplie d'une valeur scalaire.

void matrix.Fill(const scalar value)     Remplit la matrice avec la valeur spécifiée


Construction de matrices et exemples de remplissage :

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

*/

L'exemple suivant montre comment vous pouvez utiliser des fonctions personnalisées pour remplir des matrices :

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

*/ 

Une matrice peut être construite sans initialisation de valeur de 2 manières : 

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

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


Norme d’une matrice

Les 9 façons de calculer la norme d'une matrice sont listées dans 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

*/


Opérations sur les matrices et les vecteurs

Il existe des méthodes spéciales sur les matrices pour résoudre les problèmes mathématiques :

  • Transposition
  • Addition, soustraction, multiplication et division de matrices élément par élément
  • Addition, soustraction, multiplication et division des éléments de la matrice par un scalaire.
  • Produit de matrices et de vecteurs par la méthode MatMul (produit matriciel)
  • Inner()
  • Outer()
  • Kron()
  • Inv() — inverse de la matrice
  • Solve() — résout un système d'équations linéaires
  • LstSq() — renvoie la solution des moindres carrés des équations algébriques linéaires (pour les matrices non carrées ou dégénérées).
  • PInv() — matrice des moindres carrés pseudo-inverse
  • Opérations sur les colonnes, les lignes et les diagonales

Décomposition de matrices :

Méthode

Méthode équivalente dans NumPy

Description
bool matrix.Cholesky(matrix& L) cholesky Calcule la décomposition de Cholesky
bool matrix.QR(matrix& Q, matrix& R) qr

Calcule la décomposition QR

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

svd

Calcule la décomposition SVD

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

eig

Calcule les valeurs propres et les vecteurs propres droits d'une matrice carrée.

bool matrix.EigVals(vector& eigen_values)

eigvals

Calcule les valeurs propres d'une matrice générale

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

 

Implémente la décomposition LU d'une matrice : le produit d'une matrice triangulaire inférieure et d'une matrice triangulaire supérieure.

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

 

Implémente la décomposition LUP avec pivotement partiel, qui est une factorisation LU avec une permutation des rangées : PA = LU


Produit de matrices et de vecteurs

La fonction MatMul() est définie pour calculer le produit matriciel de matrices et de vecteurs. Cette méthode est souvent utilisée pour résoudre différents problèmes mathématiques. Les 2 options suivantes sont possibles lors de la multiplication d'une matrice et d'un vecteur :

  • Le vecteur horizontal de gauche est multiplié par la matrice de droite : la longueur du vecteur est égale au nombre de colonnes de la matrice ;
  • La matrice de gauche est multipliée par le vecteur vertical de droite : le nombre de colonnes de la matrice est égal à la longueur du vecteur.

Si la longueur du vecteur n'est pas égale au nombre de colonnes de la matrice, une erreur d'exécution critique est générée.

Pour multiplier 2 matrices, leur forme doit être la suivante : A[M,N] * B[N,K] = C[M,K], c'est-à-dire que le nombre de colonnes de la matrice de gauche doit être égal au nombre de lignes de la matrice de droite. Si les dimensions ne sont pas cohérentes, le résultat est une matrice vide. Voyons toutes les variantes de produits matriciels avec des exemples :

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

*/

Pour une meilleure compréhension de la disposition des types de matrices et de vecteurs, ces exemples montrent comment les matrices peuvent être utilisées à la place des vecteurs. Cela signifie que les vecteurs peuvent être représentés sous forme de matrices.


Nombres complexes de type "complex".

Certains problèmes mathématiques nécessitent l'utilisation du nouveau type de données ’nombres complexes’. Le type complex est une structure :
struct complex
  {
   double             real;   // real part
   double             imag;   // imaginary part
  };
Le type ’complex’ peut être transmis par valeur comme paramètre pour les fonctions MQL5 (contrairement aux structures ordinaires, qui ne sont transmises que par référence). Pour les fonctions importées de DLL, le type ’complex’ doit être transmis uniquement par référence.

Le suffixe ’i’ est utilisé pour décrire les constantes complexes :
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
Seules les opérations simples sont disponibles pour les nombres complexes : =, +, -, *, /, +=, -=, *=, /=, ==, !=.

De nouvelles fonctions mathématiques seront bientôt ajoutées, permettant le calcul de la valeur absolue, du sinus, du cosinus et autres.

Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/9805

Apprendre à concevoir un système de trading basé sur l’Ichimoku Apprendre à concevoir un système de trading basé sur l’Ichimoku
Voici un nouvel article dans notre série sur la façon de concevoir un système de trading avec les indicateurs les plus populaires. Nous allons parler de l'indicateur Ichimoku en détail et de comment concevoir un système de trading basé sur cet indicateur.
Développer un Expert Advisor à partir de zéro (partie 15) : Accéder aux données du web (I) Développer un Expert Advisor à partir de zéro (partie 15) : Accéder aux données du web (I)
Comment accéder aux données disponibles en ligne via MetaTrader 5 ? Il existe un grand nombre de sites et d'endroits sur le web qui contiennent une grande quantité d'informations. Ce que vous devez savoir, c'est où chercher et comment utiliser au mieux ces informations.
Apprenez à concevoir un système de trading basé sur l’indicateur Williams PR Apprenez à concevoir un système de trading basé sur l’indicateur Williams PR
Un nouvel article dans notre série sur l'apprentissage de la conception d'un système de trading par les indicateurs techniques les plus populaires de MQL5 à utiliser dans le MetaTrader 5. Dans cet article, nous allons apprendre à concevoir un système de trading basé sur l'indicateur %R de Williams.
Développer un Expert Advisor de trading à partir de zéro (partie 14) : Ajout du Volume Au Prix (II) Développer un Expert Advisor de trading à partir de zéro (partie 14) : Ajout du Volume Au Prix (II)
Aujourd'hui, nous allons ajouter quelques ressources supplémentaires à notre EA. Ce nouvel article peut apporter de nouvelles idées et des méthodes de présentation des informations. Et il peut vous aider à corriger des défauts mineurs dans vos projets.