preview
Fatorando Matrizes — Uma modelagem mais prática

Fatorando Matrizes — Uma modelagem mais prática

MetaTrader 5Exemplos | 5 abril 2024, 10:12
91 0
Daniel Jose
Daniel Jose

Introdução

Olá pessoal, e sejam bem-vindos a mais um de meus artigos, voltado a ter um conteúdo didático.

No artigo anterior Fatorando Matrizes — O Básico , falei um pouco de como você, meu caro e entusiasta leitor, pode conseguir usar matrizes em sua forma de efetuar cálculos de uma forma geral. Porém, como ali, queríamos que você, conseguisse entender, como o cálculo estava sendo feito. Não nos preocupamos em de fato criar uma modelagem das matrizes de forma adequada.

Muito provavelmente você não tenha se dado conta, que a modelagem das matrizes estava um tanto quanto estranha. Já que não havia a indicação de linhas e colunas, mas apenas indicações de colunas. O que é muito estranho, quando se está lendo um código, que faz fatorações de matrizes. E se você estava esperando ver linhas e colunas sendo indicadas. Pode acabar ficando bastante confuso, no momento de tentar implementar a fatoração.

Além do mais, aquela forma de modelar as matrizes, não é nem de longe a melhor maneira. Isto por que, quando modelamos matrizes daquela maneira, passamos a ter uma certa limitação, que nos obriga a usar outras técnicas, ou funções, que não seriam de fato necessárias. Isto quando a modelagem é feita de uma maneira um pouco mais adequada.

Como o procedimento, apesar de não ser complicado, precisa ser de fato bem compreendido, para que seja adequadamente utilizado. Preferi, não entrar em detalhes sobre isto, no artigo anterior. Então neste artigo, poderei explicar a coisa com mais calma. Sem atropelamentos, ou correndo o risco de acabar dando uma ideia equivocada sobre como você deverá pensar no momento em que for modelar suas matrizes, para que estas sejam adequadamente fatoradas.

Matrizes são de fato, a melhor forma de fazer certos tipos de cálculos. Isto por que, elas necessitam de poucas coisas sendo implementadas. Porém, justamente por conta disto, precisamos ter um maior cuidado ao implementar, qualquer coisa que em matrizes. Pois diferente de uma modelagem convencional, se você modelar de forma errada algo em matrizes. Acabará obtendo resultados bastante bizarros, ou no mínimo terá uma grande dificuldade na manutenção do código desenvolvido.


Cuidados na modelagem de uma matriz

Talvez você esteja pensando: Por que, este camarada, disse que a modelagem no artigo anterior estava estranha ?!?! Eu consegui entender. Então não consigo compreender por que, de dizer que ela estava estranha. Bem meu caro leitor. Vamos ver o fragmento do código do artigo anterior, onde as matrizes estavam sendo modeladas. Talvez assim fique um pouco mais claro o que queremos lhe mostrar. O fragmento pode ser visto abaixo.

20. //+------------------------------------------------------------------+
21. void Arrow(const int x, const int y, const ushort angle, const uchar size = 100)
22. {
23.     double M_1[2][2] = {
24.                            cos(_ToRadians(angle)), sin(_ToRadians(angle)),
25.                           -sin(_ToRadians(angle)), cos(_ToRadians(angle))
26.                         },
27.            M_2[][2]  =  {
28.                            0.0,  0.0,
29.                            1.5, -.75,
30.                            1.0,  0.0,
31.                            1.5,  .75
32.                         },
33.            M_3[M_2.Size() / 2][2];

Apesar de funcionar, da forma como pode ser visto no fragmento. A coisa em si, tá muito enrolada. Difícil de entender. Observe o seguinte, quando escrevemos no código um array multidimensional. Usamos a seguinte configuração.

Rótulo[Dimesão_01][Dimensão_02]....[Dimensão_N];

Apesar de aparentemente ser simples de entender, isto quando estamos dentro de um código generalista. Este tipo de notação é difícil de ser compreendido, quando levamos a coisa para o campo, onde faremos a fatoração de matrizes. Isto por que, quando estamos trabalhando com matrizes, esta forma de expressar um array multidimensional, faz com que as coisas, venham a se tornar bem confusas, logo mais você entenderá o por quê. Para simplificar, vamos reduzir a coisa a um sistema bidimensional. Ou seja, teremos apenas linhas e colunas. Porém, matrizes podem ter qualquer número de dimensões. Mas simplificando para uma matriz bidimensional, a forma de escrita ficaria como mostrado abaixo.


E o que isto significa ?!?! Bem, o M representa o nome da matriz. Já o l indica o número de linhas, e o c o número de colunas. Em termos gerais, quando se estiver acessando um elemento da matriz, você usará a mesma notação, o que tornaria as coisas como mostrado abaixo.


Note que agora a matriz M é formada por seis elementos, que podem ser acessados seguindo o tal sistema de linhas e colunas. Mas observe atentamente esta imagem acima. Com o que ela se parece ?!?! Você pode dizer que ela se parece com diversas coisas dependendo do seu grau de experiência. Mas em termos de computação, o que seria ?!?! Bem isto seria um array de duas dimensões. Mas pensar desta forma, torna a matriz estática. E uma matriz é uma entidade dinâmica. Ela pode ser lida de muitas formas diferentes, dependendo do que você esteja calculando. Existem casos em que ela deverá ser lida na diagonal. Existem outros em que ela deverá ser lida coluna a coluna, e existem casos em que ela deverá ser lida linha a linha. Então pensar em uma matriz, como sendo um array multidimensional, faz com que algo dinâmico, passe a ser visto de maneira estática. E isto complica bastante a forma de implementar alguns dos cálculos envolvendo matrizes.

Porém, não estou aqui para ensinar um bispo a rezar o pai nosso. Estou aqui, querendo mostrar, a você, meu caro leitor e entusiasta, como você pode visualizar qualquer matriz de uma forma melhor. Permitindo que ela continue a ser uma entidade dinâmica, como tem de ser.

Desta forma, a ideia de pensar em uma matriz como sendo um array, não está errada. O problema é pensar que se trata de um array multidimensional. O ideal é que você pense na matriz como sendo um array unidimensional, porém sem um número fixo de dimensões. Parece doideira o que acabei de escrever. Mas o problema é a linguagem. Atualmente não existem de fato, termos ou expressões, que permitam escrever, ou descrever certas ideias ou conceitos.

Pense na dificuldade que Isaac Newton deve ter tido, ao elaborar as primeiras explicações sobre Cálculos. Deve ter sido bastante complicado, dadas a limitações, por falta de termos adequados para explicar alguns conceitos. Mas vamos voltar a nossa questão.

Ok, já temos uma forma de imaginar a matriz em termos de array. Mas agora vem o primeiro problema. Como enfileirar os elementos no array ?!?! Bem, se você não entendeu o porquê disto, ser um problema. É por que, não entende tudo que podemos fazer em termos de fatoração de matrizes. A forma como os elementos venham a ser enfileirados, influenciará profundamente a forma como o código de fatoração será implementado. Mesmo que os resultados venham a ser os mesmos em qualquer caso. Você pode precisar de mais ou menos saltos dentro do array, a fim de conseguir produzir o resultado correto. Isto por conta justamente do fato, de que a memória do computador é linear. Assim se você enfileirar os elementos da seguinte forma: t11, t12, t21, t22, t31 e t32, que é uma forma adequada em muitos casos, precisará forçar saltos a fim de acessar os elementos em uma ordem diferente. Isto para efetuar algum cálculo específico. E isto com toda a certeza irá acontecer, não importa o que se faça, acontecerá.

Então normalmente, quando enfileiramos os elementos dentro do array, fazemos isto lendo linha por linha. Mas nada impede de você os enfileirar de uma outra maneira, como por exemplo: coluna por coluna. Ou de qualquer outra forma que você possa vir a imaginar. Seja livre para fazer da forma como melhor ser for conveniente.

Uma vez feito isto, temos um outro pequeno problema. Porém este não vem do fato de estarmos programando. E sim da forma como as matrizes são fatoradas. Neste caso, não entrarei em detalhes sobre o este tema. E o motivo é simples: A forma como você vai lidar com ele dependerá, da forma como você implementou a matriz, ou do tipo de matriz que está sendo usada. Neste caso, sugiro que você procure estudar livros ou literatura matemática, para entender como implementar a solução, para cada um dos problemas que surgirem. Isto para que você consiga implementar as fatorações adequadamente. Porém nunca é de fato complicado implementar o código, o código em si é a parte fácil do trabalho. A parte complicada é entender como a fatoração será executada. Um exemplo disto é calcular o determinante da matriz mostrada na figura acima. Note que ela não é uma matriz quadrada, e gerar o determinante neste caso é um pouco diferente do que seria feito em uma matriz quadrada. Como foi dito, procure estudar a parte da matemática, pois cada caso específico, pode exigir uma determinada abordagem.


A confusão está armada

Bem, agora que já expliquei e nivelei um pouco as coisas, podemos partir para a fase da codificação. Vamos continuar com o exemplo visto no artigo anterior. Isto por que, aquele exemplo é bem prático e simples de entender. Além do que, é mais fácil mostrar, usando ele, uma outra vantagem em usar cálculos matriciais em alguns casos. Então vamos relembrar como era o código. Isto pode ser feito observando o código logo abaixo.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. #property indicator_chart_window
04. #property indicator_plots 0
05. //+------------------------------------------------------------------+
06. #include <Canvas\Canvas.mqh>
07. //+------------------------------------------------------------------+
08. CCanvas canvas;
09. //+------------------------------------------------------------------+
10. #define _ToRadians(A) (A * (M_PI / 180.0))
11. //+------------------------------------------------------------------+
12. void MatrixA_x_MatrixB(const double &A[][], const double &B[][], double &R[][], const int nDim)
13. {
14.     for (int c = 0, size = (int)(B.Size() / nDim); c < size; c++)
15.     {
16.         R[c][0] = (A[0][0] * B[c][0]) + (A[0][1] * B[c][1]);
17.         R[c][1] = (A[1][0] * B[c][0]) + (A[1][1] * B[c][1]);
18.     }
19. }
20. //+------------------------------------------------------------------+
21. void Arrow(const int x, const int y, const ushort angle, const uchar size = 100)
22. {
23.     double M_1[2][2]{
24.                         cos(_ToRadians(angle)), sin(_ToRadians(angle)),
25.                         -sin(_ToRadians(angle)), cos(_ToRadians(angle))
26.                     },
27.            M_2[][2] {
28.                         0.0,  0.0,
29.                         1.5, -.75,
30.                         1.0,  0.0,
31.                         1.5,  .75
32.                     },
33.            M_3[M_2.Size() / 2][2];
34. 
35.     int dx[M_2.Size() / 2], dy[M_2.Size() / 2];
36.     
37.     MatrixA_x_MatrixB(M_1, M_2, M_3, 2);
38.     ZeroMemory(M_1);
39.     M_1[0][0] = M_1[1][1] = size;
40.     MatrixA_x_MatrixB(M_1, M_3, M_2, 2);
41. 
42.     for (int c = 0; c < (int)M_2.Size() / 2; c++)
43.     {
44.         dx[c] = x + (int) M_2[c][0];
45.         dy[c] = y + (int) M_2[c][1];
46.     }
47. 
48.     canvas.FillPolygon(dx, dy, ColorToARGB(clrPurple, 255));
49.     canvas.FillCircle(x, y, 5, ColorToARGB(clrRed, 255));
50. }
51. //+------------------------------------------------------------------+
52. int OnInit()
53. {    
54.     int px, py;
55.     
56.     px = (int)ChartGetInteger(0, CHART_WIDTH_IN_PIXELS, 0);
57.     py = (int)ChartGetInteger(0, CHART_HEIGHT_IN_PIXELS, 0);
58. 
59.     canvas.CreateBitmapLabel("BL", 0, 0, px, py, COLOR_FORMAT_ARGB_NORMALIZE);
60.     canvas.Erase(ColorToARGB(clrWhite, 255));
61.         
62.     Arrow(px / 2, py / 2, 160);
63. 
64.     canvas.Update(true);
65.     
66.     return INIT_SUCCEEDED;
67. }
68. //+------------------------------------------------------------------+
69. int OnCalculate(const int rates_total, const int prev_calculated, const int begin, const double &price[])
70. {
71.     return rates_total;
72. }
73. //+------------------------------------------------------------------+
74. void OnDeinit(const int reason)
75. {
76.     canvas.Destroy();
77. }
78. //+------------------------------------------------------------------+

Como este código foi explicado no artigo anterior, estando também disponível no anexo daquele artigo. Aqui não vamos voltar a explicar ele. Assim como também, focaremos apenas no fragmento que de fato precisa ser manipulado. Ou seja, o procedimento Arrow e o procedimento MatrixA_x_MatrixB, que são os que de fato fazem algo no nosso código de demonstração.

Muito bem, para começar, vamos mudar a forma como os arrays foram construídos. Na verdade, a mudança será bem mais simples e sútil do que possa parecer. Mas ainda assim, fará diferença na maneira como deveremos começar a agir.

Para que você, meu caro leitor, comece a entender. Vamos tomar o array M_1, que é visto no código acima. Então observem ele para entender o que será explicado.

Note uma coisa interessante aqui, que foi justamente o tema explicado no tópico anterior. Na linha 23, o array, ou matriz M_1, é declarado como tendo duas linhas e duas colunas. Neste caso não temos dúvidas com relação a isto. Assim como também o array, ou matriz M_2, que não tem uma definição de número de linhas, mas tem o de colunas que é de duas colunas. Até este ponto, não existe nenhuma dúvida ou problema. Sendo bem simples de entender o que estamos fazendo. Já que cada nova linha no código seria uma nova linha na matriz, e cada nova coluna, na linha, seria uma nova coluna na matriz. Simples assim. Porém, existe um problema. E este está no código do procedimento MatrixA_x_MatrixB. Você consegue perceber o problema ?!?! Sim. Não. Talvez. Quem sabe, esteja vendo, mas não entendendo.

Bem, de fato existe um problema neste procedimento MatrixA_x_MatrixB, que é responsável por multiplicar as matrizes. Porém, como o que estamos fazendo aqui, é algo bastante simples, isto não compromete a implementação do código. No entanto, isto não justifica o problema permanecer ali, existindo a atrasando a nossa vida. Isto no momento em que precisamos, implementar uma multiplicação mais elaborada, será um problema. Ou uma baita de uma pedra no nosso sapato.

Caso você não tenha percebido o problema, quero que preste atenção na variável B. Esta representa uma matriz, que está multiplicando a outra matriz. Porém para perceber melhor o problema, vamos reduzir a matriz B, a uma única coluna, porém com duas linhas. Isto por que a matriz A contem duas colunas. E para que a multiplicação aconteça, é preciso fazer o que é visto na figura abaixo.


Assim teremos o resultado adequado. Isto é o que acontece em uma multiplicação de matrizes, ou uma fatoração matricial. Para mais detalhes procure estudar sobre o assunto. De qualquer forma, a multiplicação é feita, linha vezes coluna, resultando assim em um valor que ficará na coluna. Isto por que o segundo fator é uma coluna. Se a multiplicação fosse feita da forma coluna vezes linha. O valor resultante deveria se montado em forma de linhas.

Apesar do que acabei de dizer, possa parecer ter sido tido apenas para lhe confundir. Na verdade esta é a regra para se efetuar a multiplicação de matrizes. Então quando um outro programador for analisar o código, não irá ver isto sendo feito. E é justamente este o problema que pode ser visto nas linhas 16 e 17. Que é justamente onde o calculo mostrado na figura acima deveria está sendo feito. Porém, observe que na matriz A estamos usando o calculo pela linha, mas na matriz B, também estamos usando o cálculo por linha. O que é confuso, apesar de fornecer os dados corretos, neste exemplo simples.

Muito bem, você pode pensar: E dai ?!?! Se está funcionando deixe como está. Mas não é esta a questão. Se em algum momento, você precisar melhorar o código. Seja para fins de conseguir cobrir uma matriz maior, ou um caso um pouco diferente. Pronto. Você vai acabar se complicando todinho, tentando fazer algo relativamente simples funcionar. Então é preciso que este tipo de coisa seja feita, sem toda esta confusão. Para resolver isto, precisamos deixar de usar esta modelagem, e passar a usar uma modelagem um pouco diferente. Mesmo que inicialmente ela pareça confusa, pelo menos ela estará correta. Seguindo exatamente o que é mostrado na imagem acima.

Bem, para separar as coisas, vamos ver como fazer isto em um novo tópico.


Tornando as coisas menos complicadas

Apesar do que iremos, fazer aqui, parecer ser complicado. Na verdade não é assim tão complicado. Se for feita da maneira correta, e tomando os devidos cuidados. Você conseguirá fazer algo, que de outra forma seria muito mais demorado. E fará de uma maneira bem simples. Veja a figura abaixo.


Esta representação, demonstra que ambas matrizes são equivalentes. Isto por que a matriz com os elementos A, do lado esquerdo, que é uma matriz de linhas. Quando precisamos transformar ela em uma matriz com elementos B, do lado direito, que neste caso é uma matriz de colunas. Não necessitaremos de muitas coisas sendo feitas, talvez um simples giro, ou a troca de um índex em alguns casos. De qualquer forma, isto muitas vezes precisará ser feito. Converter uma matriz de linhas em uma de colunas e vice-versa. Justamente para permitir a fatoração entre matrizes. Mas para que tudo fique correto, a11 deverá ser igual a b11 e a21 deverá ser igual a b12.

Haverá casos que você notará não ser preciso, grandes mudanças. Apenas mudar um índex. E poderemos mudar uma estrutura de linhas para uma estrutura de colunas. Mas fazer isto de maneira adequada dependerá de cada caso específico. Por isto é bom que você estude como é feita a fatoração matricial. Lendo livros de matemática para se inteirar sobre o assunto.

Agora voltando ao nosso código, que foi visto no tópico anterior. Vamos começar corrigindo a representação em primeiro lugar. Para fazer isto, bastará mudar o código, conforme mostrado no fragmento abaixo.

20. //+------------------------------------------------------------------+
21. void Arrow(const int x, const int y, const ushort angle, const uchar size = 100)
22. {
23.     double  M_1[]= {
24.                        cos(_ToRadians(angle)), sin(_ToRadians(angle)),
25.                        -sin(_ToRadians(angle)), cos(_ToRadians(angle))
26.                    },
27.             M_2[]= {
28.                        0.0,  0.0,
29.                        1.5, -.75,
30.                        1.0,  0.0,
31.                        1.5,  .75
32.                    },
33.            M_3[M_2.Size()];

Observe que agora não temos mais índex, nos arrays. A estrutura das matrizes, está sendo criada como mostrado no código. Ou seja, linhas são linhas e coluna são colunas. Porém, preste atenção ao arrays, ou matrizes dinâmicas, como a M_3. Veja que precisamos definir corretamente o comprimento a ser alocado. Isto justamente para evitar erros de RUN-TIME, durante o acesso aos elementos destas matrizes mencionadas.

Esta é a primeira parte. Porém ao fazer isto, o procedimento MatrixA_x_MatrixB, não mais conseguirá entender como fazer os cálculos. Assim como também o laço presente na linha 42, veja o código no tópico anterior, não conseguirá entender como decodificar os dados.

Então vamos primeiro corrigir a questão do calculo que está sendo feito no procedimento MatrixA_x_MatrixB. Para depois corrigir a plotagem para a tela. Mas antes de continuarmos, note que a matriz M_1, praticamente não mudou, isto por ela ser uma matriz simétrica e quadrada. Este é um dos casos em que podemos ler ela tanto na forma de linhas quanto na forma de colunas.

Bem, como grande parte do código mudará, vamos ver todo no novo código no fragmento abaixo. Assim acredito que será mais simples de explicar como tudo estará funcionando.

09. //+------------------------------------------------------------------+
10. #define _ToRadians(A) (A * (M_PI / 180.0))
11. //+------------------------------------------------------------------+
12. void MatrixA_x_MatrixB(const double &A[], const ushort Rows, const double &B[], double &R[])
13. {
14.     uint Lines = (uint)(A.Size() / Rows);
15. 
16.     for (uint cbl = 0; cbl < B.Size(); cbl += Rows)
17.         for (uint car = 0; car < Rows; car++)
18.         {
19.             R[car + cbl] = 0;
20.             for (uint cal = 0; cal < Lines; cal++)
21.                 R[car + cbl] += (A[(cal * Rows) + car] * B[cal + cbl]);
22.         }
23. }
24. //+------------------------------------------------------------------+
25. void Plot(const int x, const int y, const double &A[])
26. {
27.     int dx[], dy[];
28. 
29.     for (uint c0 = 0, c1 = 0; c1 < A.Size(); c0++)
30.     {
31.         ArrayResize(dx, c0 + 1, A.Size());
32.         ArrayResize(dy, c0 + 1, A.Size());
33.         dx[c0] = x + (int)(A[c1++]);
34.         dy[c0] = y + (int)(A[c1++]);
35.     }
36. 
37.     canvas.FillPolygon(dx, dy, ColorToARGB(clrPurple, 255));
38.     canvas.FillCircle(x, y, 5, ColorToARGB(clrRed, 255));
39. 
40.     ArrayFree(dx);
41.     ArrayFree(dy);
42. }
43. //+------------------------------------------------------------------+
44. void Arrow(const int x, const int y, const ushort angle, const uchar size = 100)
45. {
46.     double  M_1[]={
47.                      cos(_ToRadians(angle)), sin(_ToRadians(angle)),
48.                      -sin(_ToRadians(angle)), cos(_ToRadians(angle))
49.                   },
50.             M_2[]={
51.                      0.0,  0.0,
52.                      1.5, -.75,
53.                      1.0,  0.0,
54.                      1.5,  .75
55.                   },
56.            M_3[M_2.Size()];
57.     
58.     MatrixA_x_MatrixB(M_1, 2, M_2, M_3);
59.     ZeroMemory(M_1);
60.     M_1[0] = M_1[3] = size;
61.     MatrixA_x_MatrixB(M_1, 2, M_3, M_2);
62.     Plot(x, y, M_2);
63. }
64. //+------------------------------------------------------------------+

Uau, agora de fato a coisa toda ficou muito complicada. Não estou entendendo nadinha de nada. Será que de fato precisamos de toda esta confusão sendo feita ?!?! Calma meu caro leitor. Este código não é nada complicado ou confuso. Na verdade eu o considero muito simples e bastante objetivo. Além de ser altamente flexível, e já vou explicar o motivo de estar dizer isto.

Neste fragmento, de fato a multiplicação entre duas matrizes acontece da forma correta. Neste caso que pode ser visto, foi implementado o modelo coluna vezes linha, resultando assim em uma nova linha como produto da multiplicação. A multiplicação acontece exatamente na linha 21. Sei que pode parecer extremamente complicado o que está sendo feito no procedimento da linha 12. Mas não é nada complicado. Já que todas aquelas variáveis que podem ser vistas, estão ali, justamente para nos permitir acessar corretamente um determinado índex no array.

Como não existem testes sendo feitos, para garantir que o número de linhas de uma matriz seja igual ao de colunas da outra matriz. Você, ao usar este procedimento, deve tomar este cuidado, para que não ocorra erros de RUN-TIME.

Agora que a matriz A que deverá ser montada em termos de colunas, está multiplicando a matriz B, que deverá ser montada pensando em termos de linhas. E o resultado é colocado na matriz R, que será construída em termos de linhas, podemos ver como as chamadas acontecerão. Isto é feito nas linhas 58 e 61. Primeiro vamos ver a linha 58. Note que a matriz M_1, que está montada com os valores pensados em colunas, deverá ser passada como primeira matriz. Já a matriz M_2, que é dinâmica e pensada em termos de linhas, deverá ser passada como sendo a segunda matriz. Se você mudar esta ordem, na linha 58, obterá um erro nos valores calculados. Sei que parece bastante estranho, dizer que 2 x 3 é diferente de 3 x 2. Mas quando se fala em matrizes, de fato a ordem dos fatores influencia o produto obtido. De qualquer forma, note que é bem como estava sendo feito antes. Claro que o segundo argumento da chamada, indica o número de colunas na primeira matriz. Como o intuito aqui é ser didático e não eficiente ou totalmente infalível, não estou me preocupando em testar se a matriz B, no caso M_2, poderá ou não ser multiplicada pela matriz A, que no caso é a M_1. Estou supondo que você não mudará a estrutura, talvez, apenas aumentar o número de linhas na matriz M_2, o que não atrapalhará em nada a fatoração feita em MatrixA_x_MatrixB.

Ok. As linhas 59 e 60, já foram explicadas no artigo anterior. Assim como também o que acontece na linha 61, é equivalente ao que acontece na linha 58. Podendo assim considerarmos isto como já explicado. Porém, na linha 62, temos uma nova chamada, que chamará o procedimento na linha 25. Mas por que ?!?! O motivo, é que você pode usar este procedimento na linha 25, para efetuar a plotagem de outros objetos ou imagens diretamente no gráfico. Tudo que você precisa fazer, será passar uma matriz do tipo linha, para este procedimento. Onde cada linha representa um vértice na imagem a ser desenhada. Estes pontos, que deverão estar na matriz, devem seguir a seguinte ordem: X na primeira coluna e Y na segunda coluna. Já que estamos plotando algo em uma tela que é um elemento bidimensional. Sendo assim, mesmo que você desenhe algo em 3D, deverá efetuar os devidos cálculos na matriz para que um vértice, que esteja na dimensão Z, seja projetado no plano XY. Você não precisa se preocupar em separar as coisas, ou com o tamanho da matriz. O procedimento Plot, fará isto. Veja que na linha 27, declaramos dois arrays dinâmicos. Já na linha 29, criamos um laço for bem curioso, para muitos de vocês, acostumados a construírem ele de doutra forma. Neste laço, temos duas variáveis. Uma que será controlada pelo laço e outra que será controlada no código dentro do laço. A variável c0, é a que será controlada pelo laço. Ela tem o objetivo, de instanciar corretamente o índex para dx e dy. Assim como também alocar mais memória, quando for necessário fazer isto. Veja como isto está sendo feito nas linhas 31 e 32. Você pode achar isto pouco eficiente, porém olhe a documentação do MQL5 e você entenderá que não é bem assim.

Já a variável c1, é controlada dentro do código. Para ver isto, observe oque está acontecendo com c1 nas linhas 33 e 34. A cada interação ela é incrementada em uma unidade. Porém, é justamente c1, que diz ao laço for para que este seja encerrado. Se você não observou isto, note na linha 29, qual a condição usada para encerrar o laço.

Aqui não estamos checando se o array, ou matriz A, está ou não corretamente construído. Se ele não estiver devidamente construído, tendo duas colunas em cada linha. Em algum momento dentro deste laço for, haverá o disparo de um erro de RUN-TIME, indicando que houve uma tentativa de acesso fora do range. Então preste atenção ao criar a matriz A.

No final de tudo isto, usamos a linha 37, para chamar um procedimento na classe CCanvas. Este tem como objetivo, plotar a figura da matriz no gráfico. A linha 38, mostra onde está o ponto de origem da plotagem. Se tudo der certo, você verá a imagem mostrada logo abaixo.


E como não podia deixar de existir, nas linhas 40 e 41, devolvemos a memória alocada para o sistema operacional. Liberando assim o recurso que foi alocado.


Considerações finais

Nestes dois artigos, o anterior e neste. Procurei apresentar a você, meu caro leitor, algo que muitos consideram complicado, ou difícil de ser implementado ou utilizado. Que é a fatoração matricial. Sei que este material apresentado aqui, não cobre todos os aspectos e vantagens de usar matrizes em alguns de seus cálculos. Porém quero ressaltar, que entender como desenvolver formas de calcular matrizes é algo importante. Não é atoa que programas 3D, sejam jogos ou mesmo editores de imagem vetorial, fazem uso exatamente deste tipo de fatoração. Mesmo alguns programas, que muitos consideram aparentemente simples, como programas que manipulam imagens do tipo bitmap, também em diversos casos, usam cálculos matriciais, a fim de agilizar a implementação do sistema que está sendo implementado.

Nestes dois artigos, tentei mostrar justamente isto. Já que vejo, muitos que estão iniciando na programação, simplesmente ignorarem a necessidade de realmente aprender a programar certas coisas. Muitas vezes usam bibliotecas, ou outros programas da moda, sem se quer se darem conta do que está sendo feito por debaixo dos panos.

Aqui, tentei deixar a coisa da maneira o mais simples, quanto foi possível deixa. Focando em apenas uma única operação. A multiplicação de duas matrizes. E para provar como deixei a coisa extremamente simples. Não cheguei a mostrar como usar a GPU para efetuar o trabalho que é feito no procedimento MatrixA_x_MatrixB. O que de fato, acontece em muitos dos casos. Aqui usamos apenas o poder da CPU para fazer as coisas. Mas no geral os procedimentos que efetuam as fatorações em matrizes, são feitos não pela CPU e sim pela GPU, usando para isto OpenCL a fim de programar a GPU da forma correta.

Mas acredito, ter de alguma forma mostrado que podemos fazer muito, mais do que alguns julgam ser possível. Então procurem estudar este material mostrado nestes dois artigos. Pois pretendo em breve, explicar sobre um assunto, em que fatoração usando matrizes é algo primordial.

Um último detalhe que quero acrescentar, é que esta multiplicação de duas matrizes apresentada aqui, é focada em resolver um problema local. Não é nem de longe a forma como se estuda em livros ou na escola. Então não espere usar este mesmo modelo de fatoração de forma genérica. Pois não funcionará. Ela apenas funciona para o problema proposto, que era efetuar a rotação de um objeto.



Arquivos anexados |
Matrizes.mq5 (2.9 KB)
Desenvolvendo um agente de Aprendizado por Reforço em MQL5 com Integração RestAPI (Parte 5): Escolhendo o Algoritmo do agente Desenvolvendo um agente de Aprendizado por Reforço em MQL5 com Integração RestAPI (Parte 5): Escolhendo o Algoritmo do agente
Este capítulo da série aborda algoritmos de aprendizado por reforço, focando em Q-Learning, Deep Q-Network (DQN), e Proximal Policy Optimization (PPO). Explora como essas técnicas podem ser integradas para melhorar a automação de tarefas, detalhando suas características, vantagens, e aplicabilidades práticas. A seleção do algoritmo mais adequado é vista como crucial para otimizar a eficiência operacional em ambientes dinâmicos e incertos, prometendo discussões futuras sobre a implementação prática e teórica desses métodos.
Redes neurais de maneira fácil (Parte 61): O problema do otimismo no aprendizado por reforço off-line Redes neurais de maneira fácil (Parte 61): O problema do otimismo no aprendizado por reforço off-line
Durante o aprendizado off-line, otimizamos a política do Agente com base nos dados da amostra de treinamento. A estratégia resultante confere ao Agente confiança em suas ações. Mas, essa confiança nem sempre é justificada, já que pode acarretar maiores riscos durante a utilização prática do modelo. Hoje vamos examinar um dos métodos para reduzir esses riscos.
Desenvolvendo um sistema de Replay (Parte 46): Projeto do Chart Trade (V) Desenvolvendo um sistema de Replay (Parte 46): Projeto do Chart Trade (V)
Cansado de perder tempo procurando aquele arquivo, que é preciso para fazer a sua aplicação funcionar ?!?! Que tal embutir tudo no executável ? Assim você nunca irá perder tempo procurando as coisas. Sei que muitos fazem uso, exatamente daquela forma de distribuir e guardar as coisas. Mas existe uma maneira bem mais adequada. Pelo menos no que diz respeito a distribuição de executáveis e armazenamento dos mesmos. A forma que irei explicar aqui, pode vim a lhe ser de grande ajuda. Já que você pode usar o próprio MetaTrader 5 como sendo um grande ajudante, assim como o MQL5. Não é algo lá tão complexo, ou difícil de ser entendido.
Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 07): Dendrogramas Funcionalidades do assistente MQL5 que você precisa conhecer (Parte 07): Dendrogramas
A classificação de dados para análise e previsão é uma área muito diversificada do aprendizado de máquina, que compreende um grande número de abordagens e métodos. Neste artigo, examinaremos uma dessas abordagens, nomeadamente o agrupamento hierárquico aglomerativo (Agglomerative Hierarchical Clustering).