Matrizes e vetores em MQL5
Para manusear dados ordenados e homogêneos, é comum o uso de matrizes que permitem que cada elemento seja acessado por um índice. As matrizes são amplamente utilizadas para resolver muitos problemas de álgebra linear, modelagem matemática, aprendizagem de máquinas, etc. A solução para estes problemas é, em termos gerais, baseada em operações matemáticas que utilizam matrizes e vetores, que permitem que conversões muito complexas sejam escritas de forma compacta como uma fórmula simples. Programar estas operações não só requer um bom nível de matemática, mas também saber escrever laços aninhados complexos. A depuração e a detecção de bugs neste tipo de programas pode ser muito cansativa.
Os tipos de dados especiais matrix e vector permite escrever um código próximo a uma notação matemática e evita a necessidade de criar laços aninhados. O programador não precisa mais se lembrar de indexar corretamente as matrizes que estão envolvidas no cálculo. Neste artigo mostramos como criar, iniciar e aplicar os objetos matrix e vector em MQL5.
O tipo vector
vector é uma matriz unidimensional do tipo double. As operações de adição e multiplicação são definidas sobre vetores, e o conceito de "Norma" é introduzido para obter o comprimento ou módulo de um vetor. Na programação, os vetores são normalmente representados por matrizes de elementos homogêneos sobre os quais as operações vetoriais usuais podem não ser especificadas, ou seja, as matrizes não podem ser adicionadas umas às outras, multiplicadas umas pelas outras, e não existe o conceito de norma.
Em matemática, os vetores podem ser representados como uma fila vetorial, isto é, como uma matriz de uma fila e n colunas, ou como uma coluna vetorial como uma matriz de uma coluna e n filas. Como em MQL5 o tipo "vector" não é dividido em linhas e colunas vetoriais, o programador deve entender ele mesmo qual tipo de vetor é usado ao realizar uma determinada operação.
É possível criar e iniciar um vetor usando métodos embutidos.
Métodos | Análogo NumPy | Descrição |
---|---|---|
void vector.Init( ulong size); | Cria um vetor de comprimento especificado, cujos valores são indefinidos | |
static vector vector::Ones(ulong size); | ones | Cria um vetor de comprimento especificado e o preenche com uns |
static vector vector::Zeros(ulong size); | zeros | Cria um vetor de comprimento especificado e o preenche com zeros |
static vector vector::Full(ulong size,double value); | full | Cria um vetor de comprimento especificado e o preenche com os valores definidos |
operador = | Devolve a cópia do vetor | |
void vector.Resize(const vector v); | Muda o tamanho do vetor adicionando novos valores a partir do final |
Exemplos de criação vetorial:
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] */
O método Init pode ser usado não apenas para alocar memória para um vetor, mas também para inicializar elementos vetoriais com valores usando uma função. Neste caso, o primeiro parâmetro em Init é o tamanho do vetor e o segundo é o nome da função. Se a função por sua vez tiver parâmetros, estes são indicados imediatamente após o nome da função, separados por vírgulas.
A função em si deve conter uma referência ao vetor que lhe é passado como primeiro parâmetro, mas o vetor não precisa ser passado ao chamar Init. Vamos mostrar isto com um exemplo da função Arange que simula 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 */
A função Arange tem dois parâmetros opcionais - "start" e "step". Por isso, vamos permitir esta forma de chamar Init(7,Arange,10) com o resultado correspondente:
//+------------------------------------------------------------------+ //| 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 */
Operações com vetores
As operações usuais de adição, subtração, multiplicação e divisão podem ser realizadas em vetores usando um escalar.
//+------------------------------------------------------------------+ //| 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] */ //+------------------------------------------------------------------+
São definidas as operações de adição, subtração, multiplicação e divisão de dois vetores do mesmo tamanho, elemento por elemento.
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] */
Também são definidas quatro operações de produtos vetoriais.
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]] */
Como se pode ver no exemplo, o método Outer() retorna uma matriz na qual o número de filas e colunas corresponde ao tamanho dos vetores a serem multiplicados. Os métodos Dot() e MatMul() funcionam da mesma maneira. Isto supõe que na operação Outer(), o vetor à esquerda é vertical e o vetor à direita é horizontal. Para os métodos Dot() e MatMul(), a ordem vetorial é invertida - o vetor horizontal está à esquerda e o vetor vertical está à direita.
Norma do vetor
Sobre vetores e matrizes, é definido o conceito de normalidade, que representa o conceito de comprimento ou valor absoluto de um vetor. Há um total de três alternativas para o cálculo de normas vetoriais, que estão listadas em 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 */
Você pode usar a norma para medir a distância entre dois vetores:
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 */
Tipo matrix
Um vetor é um caso especial de uma matriz, que na verdade é uma matriz bidimensional do tipo double. Assim, podemos dizer que uma matriz é um conjunto de vetores do mesmo tamanho. O número de filas na matriz é igual ao número de vetores e o número de colunas é igual ao comprimento dos vetores.
As operações de adição e multiplicação também são definidas sobre matrizes. Linguagens de programação comuns usam arrays para representar matrizes. Mas as matrizes regulares não podem ser adicionadas umas às outras, não podem ser multiplicadas umas pelas outras e não há definição de uma norma para elas. Em matemática, são considerados muitos tipos e tipos diferentes de matrizes. Por exemplo, unidades, simétricas, obliquamente simétricas, triangulares superiores (triangulares inferiores) e outras matrizes.
Uma matriz pode ser criada e iniciada usando métodos incorporados similares aos métodos vetoriais.
Método | Contraparte em NumPy | Descrição |
---|---|---|
void static matrix.Eye(const int rows, const int cols, const int ndiag=0) | Cria uma matriz com uns na diagonal especificada e zeros em outros lugares | |
void matrix.Identity() | Preenche a matriz com uns na diagonal principal e zeros em outros lugares | |
void static matrix.Ones(const int rows, const int cols) | Cria uma nova matriz por número de filas e colunas, preenchida com unidades | |
void static matrix.Zeros(const int rows, const int cols) | Cria uma nova matriz pelo número de filas e colunas preenchida com zeros | |
void static matrix.Tri(const int rows, const int cols, const int ndiag=0) | tri | Cria uma matriz com uns na diagonal indicada e abaixo, e zeros em outros lugares |
void matrix.Diag(const vector v, const int ndiag=0) | diag | Extrai uma diagonal ou cria uma matriz diagonal |
void matrix.Full(const int rows, const int cols, const scalar value) | Cria uma nova matriz pelo número de filas e colunas, preenchidas com um valor escalar | |
void matrix.Fill(const scalar value) | Preenche a matriz com o valor especificado |
Exemplos de criação e de preenchimento de matrizes:
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]] */
O exemplo a seguir mostra como as funções próprias podem ser utilizadas no preenchimento de matrizes:
//+------------------------------------------------------------------+ //| 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]] */
Além disso, observe que há duas maneiras de criar uma matriz sem inicializar os valores.
//--- create a matrix of a given 'rows x cols' size matrix m(3, 3); // ------ equivalent matrix m; m.Resize(3, 3);
Norma de matriz
Há um total de nove alternativas para o cálculo da norma da matriz. Estão listadas em 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 */
Operações com matrizes e vetores
As matrizes contêm métodos especiais para a solução de problemas matemáticos:
- Transposição
- Adicionar, subtrair, multiplicar e dividir as matrizes elemento por elemento
- Adicionar, subtrair, multiplicar e dividir os elementos da matriz por um escalar
- Produto de matrizes e vetores pelo método MatMul (matrix product)
- Inner()
- Outer()
- Kron()
- Inv() — matriz inversa
- Solve() — resolução de um sistema de equações lineares
- LstSq() — resolução de um sistema de equações lineares usando o método dos mínimos quadrados (para matrizes não quadradas ou degeneradas)
- PInv() — matriz dos mínimos quadrados pseudo-inversos
- Trabalho com colunas, filas e diagonais
Decomposição de matriz:
Método | Contraparte em NumPy | Descrição |
---|---|---|
bool matrix.Cholesky(matrix& L) | cholesky | Calcula a decomposição de Cholecky. |
bool matrix.QR(matrix& Q, matrix& R) | qr | Calcula a fatoração qr |
bool matrix.SVD(matrix& U, matrix& V, vector& singular_values) | Calcula a decomposição SVD | |
bool matrix.Eig(matrix& eigen_vectors, vector& eigen_values) | Calcula os valores próprios e os vetores próprios direitos de uma matriz quadrada | |
bool matrix.EigVals(vector& eigen_values) | Calcula os valores próprios de uma matriz comum | |
bool matrix.LU(matrix& L, matrix& U) |
| Executa a decomposição LU de uma matriz como o produto de uma matriz triangular inferior e uma matriz triangular superior |
bool matrix.LUP(matrix& L, matrix& U, matrix& P) |
| Executa a decomposição LUP de rotação parcial, que é fatoração LU com permutações de linha: PA = LU |
Produto de matrizes e vetores
Para efetuar o produto matricial de matrizes e vetores, é definido o método MatMul(). É frequentemente utilizado na solução de muitos problemas matemáticos. Ao multiplicar uma matriz e um vetor, apenas são permitidas duas alternativas:
- O vetor horizontal da esquerda é multiplicado pela matriz da direita, o comprimento do vetor é igual ao número de colunas da matriz;
- A matriz da esquerda é multiplicada pelo vetor vertical da direita, com o número de colunas da matriz igual ao comprimento do vetor.
Se o comprimento do vetor não for igual ao número de colunas da matriz, será causado um erro crítico de execução.
As matrizes da seguinte forma podem ser multiplicadas umas com as outras A[M,N] * B[N,K] = С[M,K], ou seja, o número de colunas na matriz da esquerda deve ser igual ao número de filas na matriz da direita. Se as dimensões não forem concertadas, o resultado será uma matriz vazia. Vamos mostrar todas as variações do produto da matriz através de exemplos.
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]] */
Para entender melhor o funcionamento interno dos tipos matrix e vector estes exemplos mostram como as matrizes podem ser utilizadas em vez de vetores ou, em outras palavras, que os vetores podem ser representados como matrizes.
Números complexos - tipo complex
struct complex { double real; // real part double imag; // imaginary part };O tipo "complex" pode ser passado por valor como parâmetro para funções MQL5 (ao contrário das estruturas usuais, que são passadas apenas por referência). For functions imported from DLLs, the "complex" type must be passed only by reference.
The 'i' suffix is used to describe 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 numberSomente operações simples estão disponíveis para números complexos: =, +, -, *, /, +=, -=, *=, /=, ==, !=.
Em breve será adicionado suporte para números complexos em matrizes e vetores, assim como funções matemáticas adicionais: obtenção do valor absoluto, seno, cosseno e muitos outros.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/9805
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso