´Algebra Linear - Operac¸˜oes com Matrizes
Felipe Schimith Batista1
1
Instituto de Matem´atica e Estat´ısitica - Universidade Estadual do Rio de Janeiro
felipeschimith@gmail.com
Resumo. O trabalho visa contextualizar os teoremas e m´etodos da ´Algebra Li-
near aplicados em soluc¸˜oes computacionais. Este trabalho apresenta o refe-
rencial te´orico utilizado como base para resolver computacionalmente sistemas
lineares. Apresentaremos a ”Decomposic¸˜ao A=LU”fazendo uma comparac¸˜ao
com a decomposic¸˜ao de Gauss, a ”Decomposic¸˜ao A=LDU”comparando-a com
o m´etodo de Crout. Por fim apresentamos o ”M´etodo de Gauss-Jordan”que
obt´em a inversa de uma matriz. A implementac¸˜ao foi feita na linguagem de
programac¸˜ao Java e tamb´em ser´a documentada e comentada.
1. Introduc¸˜ao
Na Matem´atica a teoria de sistemas lineares ´e a base e uma parte fundamental da ´algebra
linear, um tema que ´e usado na maior parte da matem´atica moderna. Deve-se observar
que, em primeiro lugar, a equac¸˜ao linear ´e, necessariamente, uma equac¸˜ao polinomial.
Tamb´em na matem´atica aplicada, podemos encontrar v´arios usos de sistemas lineares.
Exemplos s˜ao a f´ısica, a economia, a engenharia, a biologia, a geografia, a navegac¸˜ao,
a aviac¸˜ao, a cartografia, a demografia e a astronomia.[RUGGIERO 1996] Um sistema
de equac¸˜oes lineares ´e um conjunto finito de equac¸˜oes lineares aplicadas num mesmo
conjunto, igualmente finito, de vari´aveis.[ANTON 2006]
Algoritmos computacionais s˜ao, por encontrar as soluc¸˜oes, uma parte importante
da ´algebra linear num´erica. Voltando na hist´oria da ´algebra linear, uma vers˜ao preliminar
da eliminac¸˜ao gaussiana apareceu pela primeira vez no livro chinˆes “Nove Cap´ıtulos de
Arte Matem´atica”, em torno de 200 a.C.
O poder do m´etodo n˜ao tinha sido reconhecido at´e que o grande matem´atico Carl
Friedich Gauss no ano de 1801 utilizou o m´etodo para calcular a ´orbita do asteroide Ceres
com pouqu´ıssimas informac¸˜oes utilizando m´ınimos quadrados e o procedimento que hoje
denominamos eliminac¸˜ao gaussiana. O trabalho de Gauss causou sensac¸˜ao quando Ceres
reapareceu na constelac¸˜ao de Virgem, local aproximado aos seus c´alculos.[ANTON 2006]
Mais tarde o m´etodo foi popularizado quando Willian Jordan (engenheiro alem˜ao)
em 1888 publicou no seu livro de geod´esia intitulado “Handbuch der Vermessungskunde”.
Embora as ideias tenham sido conhecidas antes, muitas vezes o cr´edito pela
popularizac¸˜ao da decomposic¸˜ao LU ´e atribu´ıda ao l´ogico e matem´atico britˆanico Alan
Turing, pelo seu trabalho de 1948 nesse assunto.
Ao final dos anos 1970, a Fundac¸˜ao Nacional de Ciˆencias e o Departamento de
Energia dos EUA financiaram o desenvolvimento de rotinas de computacionais para in-
verter matrizes e resolver sistemas de equac¸˜oes lineares. Aquela pesquisa levou a um
conjunto de programas Fortran chamado LINPAC que s˜ao uma referˆencia para muitos
algoritmos computacionais de hoje, inclusive no MATLAB. As rotinas LIMPAC est˜ao
organizadas em torno de quatro fatorac¸˜oes de matrizes, uma das quais ´e a decomposic¸˜ao
LU. C.B. Moler, J.J. Dongarra, G.W. Stewart e J.R. Brunch, os principais programadores
do LINPAC, basearam muitas de suas id´eias no trabalho de Jemes Boyle e Kenneth Dritz,
do Laborat´orio Argonne (nos EUA).[ANTON 2006]
2. Teoria de Matrizes
Este cap´ıtulo tem como objetivo apresentar as propriedades, teoremas e m´etodos da
´Algebra Linear que foram usados como base para implementar soluc¸˜oes computacionais
para resolver equac¸˜oes lineares utilizando matrizes.
2.1. Resoluc¸˜ao de Sistemas Lineares
Antes de nos aprofundarmos nas operac¸˜oes com matrizes, ´e necess´ario entender os con-
ceitos e m´etodos das operac¸˜oes elementares de um sistema linear que podemos imple-
mentar para encontrar as soluc¸˜oes computacionalmente. Por exemplo, um m´etodo para
resolver um sistema linear ´e substituir o sistema inicial por outro que tenha o mesmo con-
junto soluc¸˜ao do primeiro, mas que seja muito mais f´acil de resolver. O novo sistema ´e
obtido ap´os a aplicac¸˜ao de uma s´erie de operac¸˜oes que simplificam as equac¸˜oes do sistema
que tˆem a propriedade especial de n˜ao alterar o conjunto soluc¸˜ao.
Estas operac¸˜oes s˜ao chamadas operac¸˜oes elementares e s˜ao de trˆes tipos diferentes.
• Trocar duas equac¸˜oes do sistema de posic¸˜ao.
• Substituir uma equac¸˜ao pela mesma equac¸˜ao multiplicada por um escalar diferente
de 0.
• Substituir uma equac¸˜ao pela mesma equac¸˜ao somada a outra equac¸˜ao multiplicada
por um escalar.
Note que se multiplicarmos uma equac¸˜ao por 0, estaremos excluindo esta equac¸˜ao
do sistema, o que tem o efeito prov´avel de aumentar o conjunto soluc¸˜ao, por isso,
esta n˜ao ´e uma operac¸˜ao elementar. ´E f´acil ver que ao efetuarmos qualquer uma das
operac¸˜oes acima sobre as equac¸˜oes do sistema, n˜ao estaremos acrescentando nem dimi-
nuindo soluc¸˜oes.
Somente os coeficientes do sistema s˜ao alterados atrav´es das operac¸˜oes elemen-
tares, as vari´aveis permanecem inalteradas. Portanto, na hora de efetuar os c´alculos, ao
inv´es de considerar todo o sistema, podemos considerar apenas a matriz de coeficientes
do sistema, chamada matriz aumentada:
[A|B] =
α11 α12 ... α1n β1
α21 α22 ... α2n β2
α31 α32 ... α3n β3
... ... ... ...
αm1 αm2 ... αmn βm
As operac¸˜oes elementares ser˜ao efetuadas sobre as linhas desta matriz.
Definic¸˜ao. Operac¸˜oes Elementares sobre as linhas de uma matriz:
• a troca da posic¸˜ao relativa de duas linhas
Li ← Lj
• a multiplicac¸˜ao de uma linha por uma constante
Li ← cLj ⇔ c = 0
• a substituic¸˜ao de uma linha pela sua soma com outra linha qualquer
Li ← Li + Lj
Teorema. Se dois sistemas lineares Ax = B e Cx = D s˜ao tais que a matriz aumentada
[C|D] ´e obtida de [A|B] aplicando-se operac¸˜oes elementares, ent˜ao os dois sistemas pos-
suem as mesmas soluc¸˜oes. Sistemas que possuem as mesmas soluc¸˜oes s˜ao chamados
sistemas equivalentes.
2.2. Decomposic¸˜ao A=LU
A decomposic¸˜ao LU de uma matriz A surge da necessidade de resolver um conjunto de
sistemas do tipo Ax = b1, Ax = b2, Ax = b3 e assim por diante. Poder´ıamos resolver cada
um desses sistemas escalonando a matriz completa [A b] correspondente at´e sua forma
escalonada reduzida mas, computacionalmente, o escalonamento ´e um processo muito
demorado e poder´ıamos ter centenas de b’s para resolver.
Supondo-se que A seja uma matriz mxm que pode ser escalonada at´e sua forma
reduzida sem trocar linhas, a ´Algebra Linear nos diz que ela pode ser escrita na forma A
= LU, onde L Lower ´e uma matriz triangular inferior mxm cuja diagonal principal possui
apenas 1’s e U Upper ´e uma matriz triangular superior mxm que nada mais ´e do que a
pr´opria forma escalonada reduzida de A.
Para uma matriz 3x3: A = L*U


a11 a12 a13
a21 a22 a23
a31 a32 a33

 =


1 0 0
l21 1 0
l31 l32 1

 ∗


u11 u12 u13
0 u22 u23
0 0 u33


A importˆancia de escrevermos uma matriz como o produto de duas outras matrizes
triangulares, uma inferior e a outra superior, se d´a pelo fato de que, ao assumirmos que
A = LU, podemos reescrever a equac¸˜ao Ax = b como LUx = B ou, pela propriedade
associativa, L(Ux) = B. Tomando-se Ux = y, temos Ly = b e Ux = y. Resolvendo-se
a primeira equac¸˜ao para y e a segunda para x, obteremos a resposta procurada de uma
maneira bem mais simples do que fazer pelo m´etodo tradicional, visto que as matrizes
s˜ao triangulares.
Vale lembrar que quando um pivˆo nulo ´e encontrado temos um caso onde pode ou
n˜ao existir uma decomposic¸˜ao LU.
2.2.1. Comparando eliminac¸˜ao gaussiana com decomposic¸˜ao LU
Para determinac¸˜ao das inc´ognitas, o m´etodo da eliminac¸˜ao de Gauss desenvolve duas fa-
ses: a primeira ´e a eliminac¸˜ao progressiva, onde reduz o n´umero de vari´aveis ao longo
da execuc¸˜ao para, ent˜ao, aplicar a segunda fase, chamada de substituic¸˜ao regressiva, onde
utiliza o resultado da primeira para determinar a soluc¸˜ao geral do sistema. Dois passos
descritos, o primeiro ´e o que consome mais tempo de c´alculo, uma vez que ´e nesta fase
que consiste o maior n´umero de operac¸˜oes aritm´eticas e de trocas dedados.
Por isso, encontrar um m´etodo que minimize esta fase cr´ıtica implica em aumentar o
desempenho para realizar a tarefa de resoluc¸˜ao de sistemas lineares. Os m´etodos de
decomposic¸˜ao LU consistem em separar a fase de eliminac¸˜ao da matriz dos coeficien-
tes, que consomem maior tempo, das manipulac¸˜oes envolvidas com o vetor dos termos
independentes.
Portanto, devemos deixar claro que, ao contr´ario da eliminac¸˜ao de Gauss, uma
decomposic¸˜ao de LU ´e uma estrat´egia de melhoria na resoluc¸˜ao de sistemas lineares.
Sendo assim, n˜ao existe “o m´etodo” de decomposic¸˜ao LU, mas sim algumas abordagens
a serem tomadas que permitem decompor o sistema. Uma implicac¸˜ao interessante disso
´e que a pr´opria eliminac¸˜ao de Gauss pode ser descrita como uma decomposic¸˜ao LU.
O custo de processamento do algoritmo de decomposic¸˜ao LU pode ser visto pelo
n´umero de estruturas de repetic¸˜ao utilizados no c´odigo. No c´odigo implementado, o custo
´e da Ordem(n3
) para a decomposic¸˜ao LU.
/*
* Decomposi o de A em L e U
* */
for (int k = 0; k < numLin; k++) { //n
for (int i = k + 1; i < numLin; i++) { //n*n
matrizL[i][k] = (double)
matriz[i][k].floatValue()/
matriz[k][k].floatValue();
matriz[i][k] = 0.0;
for (int j = k + 1; j < numLin; j++)
{//n*n*n
matriz[i][j] = (double)
matriz[i][j].floatValue()-
(matrizL[i][k].floatValue() *
matriz[k][j].floatValue());
}
}
}
}
Da mesma forma podemos calcular o custo de processamento do algoritmo de
eliminac¸˜ao Gaussiana pode ser visto pelo n´umero de estruturas de repetic¸˜ao utilizados no
c´odigo. No c´odigo implementado no trabalho anterior, o custo ´e da Ordem(n3
).
/**
* A primeira funcao obtem a triangular superior da matriz
composta.
*/
public static void TriangularSuperior(Double[][] matriz,
int numLin, int numCol, Double[][] matriz2, int
numLin2, int numCol2,Double[][] matrizx) {
double calculo;
for (int coluna = 0; coluna < numLin2; coluna++) {n
for (int linha = coluna + 1; linha < numLin2;
linha++) {n*n
calculo =
(matriz[linha][coluna].floatValue() /
matriz[coluna][coluna].floatValue());
matriz[linha][coluna]=0.0;
for(int s=coluna+1; s <numLin2;
s++){n*n*n
matriz[linha][s]=
matriz[linha][s].floatValue() -
(calculo*matriz[coluna][s].floatValue());
}
matriz2[linha][0]=
(double)matriz2[linha][0].floatValue()
-
(matriz2[coluna][0].floatValue()*calculo);
}
}
}
Podemos concluir que o custo do processamento da decomposic¸˜ao LU ´e idˆentico
ao custo da Eliminac¸˜ao Gaussiana.
2.3. Decomposic¸˜ao A=LDU
A Decomposic¸˜ao A=LDU tamb´em ´e utilizada para soluc¸˜ao de sistemas lineares, que con-
siste em efetuar a decomposic¸˜ao da matriz A em trˆes componentes L Lower, D Diagonal
e U Upper a soma dos elementos correspondentes.
A decomposic¸˜ao A = LDU permite resolver um sistema Ax = b em trˆes passos:
• achar c de Lc = b
• achar z de Dz = c
• achar x de Ux = z
A decomposic¸˜ao LDU ´e ´unica e permite flexibilidade para o c´alculo pr´atico das
matrizes L e U. Por exemplo, isto acontece com a reduc¸˜ao de Crout, na qual considera-se
LD como sendo uma matriz triangular inferior L (sem elementos unit´arios na sua diago-
nal) de modo que A = LU com U triangular superior e elementos unit´arios na sua diagonal.
Esta reduc¸˜ao permite calcular alternadamente as colunas de L e de U.
O processo consiste em obter primeiramente a fatorac¸˜ao LU, e depois decom-
pondo a matriz U no produto de uma matriz D, com uma matriz que tamb´em se designa
por U, onde:
• D ´e uma matriz m x m diagonal cujos elementos da diagonal principal s˜ao os pivos
da eliminac¸˜ao de Gauss ou zero no caso de n˜ao haver pivˆo;
• U ´e uma matriz m x m obtida apos eliminac¸˜ao de Gauss, dividindo cada linha pelo
respectivo pivo.
Para uma matriz 3x3: A=LDU


a11 a12 a13
a21 a22 a23
a31 a32 a33

 =


1 0 0
l21 1 0
l31 l32 1

 ∗


d11 0 0
0 d22 0
0 0 d33

 ∗


1 u12 u13
0 1 u23
0 0 1


Quando um pivˆo nulo ´e encontrado temos um caso onde pode ou n˜ao existir uma
decomposic¸˜ao LU. A decomposic¸˜ao LU n˜ao ´e ´unica, j´a a decomposic¸˜ao LDU por sua vez
´e ´unica.
2.3.1. Comparac¸˜ao da decomposic¸˜ao LDU e Crout
Para compararmos LDU com Crout primeiro precisamos de fazer uma pequena
apresentac¸˜ao de Crout que ´e uma variante da fatorac¸˜ao triangular da matriz A. Toma-se a
matriz U como triangular de diagonal unit´aria e L como triangular inferior.


a11 a12 a13
a21 a22 a23
a31 a32 a33

 =


l11 0 0
l21 l22 0
l31 l32 l33

 ∗


1 u12 u13
0 1 u23
0 0 1


Como falado anteriormente a decomposic¸˜ao LDU consiste numa pequena alterac¸˜ao da
fatorac¸˜ao de Crout e tem a vantagem de atribuir `as matrizes triangulares L e U um papel
totalmente idˆentico. Consiste em considerar que estas s˜ao ambas matrizes triangulares
com diagonal unit´aria e tomar a fatorac¸˜ao na seguinte forma A = LDU em que D ´e uma
matriz diagonal.
O custo de processamento do algoritmo de decomposic¸˜ao LDU pode ser visto pelo
n´umero de estruturas de repetic¸˜ao utilizados no c´odigo. No c´odigo implementado, o custo
´e da Ordem (n3
) para a decomposic¸˜ao de A em LU e n2
para decomposic¸˜ao de U em DU’.
Resumindo podemos concluir que a decomposic¸˜ao LDU tem o custo ´e da Ordem(n3
).
public static void TransformaTraingularLU(Double[][]
matriz, int numLin,
int numCol, Double[][] matrizL) {
/*
* Decomposi o de A em L e U
* */
for (int k = 0; k < numLin; k++) { //n
for (int i = k + 1; i < numLin; i++) { //n*n
matrizL[i][k] = (double)
matriz[i][k].floatValue()/
matriz[k][k].floatValue();
matriz[i][k] = 0.0;
for (int j = k + 1; j < numLin; j++)
{//n*n*n
matriz[i][j] = (double)
matriz[i][j].floatValue()-
(matrizL[i][k].floatValue() *
matriz[k][j].floatValue());
}
}
}
}
public static void DecompoeUemDU(Double[][] matriz, int
numLin, int numCol, Double[][] matrizx) {
/*
* U*matrizy = b (matrizx)
* Calcula U[m,n]/D[x,y] = U’ sendo que x=y
* */
for (int k = 0; k < numLin; k++) {//n
for (int i = 0; i < numCol; i++) {//n*n
matrizx[i][k] = 0.0;
}
}
for (int p = numLin - 1; p >= 0; p--) {//n
matrizx[p][p]=(double)matriz[p][p].floatValue();
for (int j = p; j < numCol; j++) {//n*n
matriz[p][j]=(double)matriz[p][j].floatValue()
/matrizx[p][p].floatValue();
}
}
}
O custo de processamento do algoritmo de Crout tamb´em pode ser visto pelo
n´umero de estruturas de repetic¸˜ao utilizados no c´odigo. No c´odigo implementado, o custo
´e n3
para a decomposic¸˜ao de A em LU e n2
para decomposic¸˜ao de L em DL’.
public static void TransformaTraingularLU(Double[][]
matriz, int numLin,
int numCol, Double[][] matrizL,Double[][] matrizU)
{
/*
* Decomposi o de A em L e U
* */
int i, j, k;
double sum = 0;
for (int linha = 0; linha < numLin; linha++) {//n
for (int coluna = 0; coluna < numCol; coluna++)
{//n*n
if (linha == coluna) {
matrizU[linha][coluna] = 1.0;
} else {
matrizU[linha][coluna] = 0.0;
}
}
}
for (j = 0; j < numLin; j++) {//n
for (i = j; i < numCol; i++) {//n*n
sum = 0;
for (k = 0; k < j; k++) {//n*n*n
sum = sum +
matrizL[i][k].floatValue() *
matrizU[k][j].floatValue();
}
matrizL[i][j] = matriz[i][j].floatValue()
- sum;
}
for (i = j; i < numCol; i++) {//n*n
sum = 0;
for(k = 0; k < j; k++) {//n*n*n
sum = sum +
matrizL[j][k].floatValue() *
matrizU[k][i].floatValue();
}
if (matrizL[j][j] == 0) {
System.out.printf("t Foi
encontrada uma divizao por zero
que impossibilita a execucao
desse metodo.");
}
else{
matrizU[j][i] =
(matriz[j][i].floatValue() -
sum) /
matrizL[j][j].floatValue();
}
}
}
}
public static void DecompoeLemDL(Double[][] matriz, int
numLin,
int numCol, Double[][] matrizx) {
/*
* L*matrizy = b (matrizx)
* Calcula L[m,n]/D[x,y] = L’ sendo que x=y
* */
for (int k = 0; k < numLin; k++) { //n
for (int i = 0; i < numCol; i++) {//n*n
matrizx[i][k] = 0.0;
}
}
for (int p = numLin - 1; p >= 0; p--) {//n
matrizx[p][p]=(double)matriz[p][p].floatValue();
for (int j = p; j >= 0; j--) {//n*n
matriz[p][j]=
(double)matriz[p][j].floatValue()/
matrizx[p][p].floatValue();
}
}
}
Avaliando os algoritmos implementados podemos concluir que o algoritmo
de Crout tem o custo O(n3
) o que o torna praticamente idˆentico ao algoritmo de
decomposic¸˜ao LDU o custo ´e da Ordem(n3
).
2.4. M´etodo de Gauss-Jordan
O m´etodo de Gauss-Jordan ´e um m´etodo de escalonamento que consiste em aplicar
operac¸˜oes elementares `a matriz aumentada de um sistema, at´e que ela esteja na forma
escalonada reduzida. A vantagem deste processo ´e que um sistema cuja matriz aumentada
´e uma matriz na forma escalonada reduzida tem soluc¸˜ao imediata, enquanto que para
resolver um sistema que est´a apenas na forma escalonada ainda ´e necess´ario fazer uma
s´erie de substituic¸˜oes para obter a soluc¸˜ao final.
• O primeiro elemento n˜ao-nulo de cada linha n˜ao-nula (chamado o pivˆo da linha)
´e igual a 1.
• O pivˆo da linha i + 1 ocorre `a direita do pivˆo da linha i.
• Se uma coluna cont´em um pivˆo, ent˜ao todas os outros elementos desta coluna s˜ao
iguais a 0.
• Todas as linhas nulas ocorrem abaixo das linhas n˜ao-nulas.
As etapas para resolver um sistemas de equac¸˜oes utilizando a eliminac¸˜ao de
Gauss-Jordan ´e descrito a seguir.
1. Escreva a matriz aumentada do sistema.
2. Use as operac¸˜oes lineares para transformar a matriz aumentada na forma descrita
abaixo, que ´e chamado de forma escalonada reduzida de linha.
(a) Em cada linha que n˜ao consiste inteiramente em zeros, o elemento dife-
rente de zero mais `a esquerda ´e o pivˆo.
(b) Cada coluna que cont´em um pivˆo tem zeros em todas as outras entradas.
(c) O pivˆo em qualquer linha est´a `a esquerda de qualquer pivˆo nas linhas
abaixo dele.
(d) ) Caso existam linhas que consistem inteiramente de zeros, elas s˜ao agru-
padas em conjunto na parte inferior da matriz.
3. Ao atingir o resultado descrito no processo 2, se vocˆe obter uma linha cujos ele-
mentos s˜ao todos os zeros, exceto a ´ultima `a direita. Nesse caso, o sistema ´e
inconsistente e n˜ao tem soluc¸˜oes. Caso contr´ario, as soluc¸˜oes do sistema est˜ao na
matriz final.
Avaliando os algoritmos implementados podemos concluir que o algoritmo de
Gauss-Jordan tem o custo na Ordem(n3
) o que o torna praticamente idˆentico ao custo do
algoritmo de decomposic¸˜ao LDU e ao custo do M´etodo de Crout avaliados nesse artigo.
3. Algoritmos
Este cap´ıtulo apresenta os algoritmos desenvolvidos utilizando como base os conheci-
mentos adquiridos na ´algebra linear. Algumas func¸˜oes secund´arias como obtenc¸˜ao das
matrizes a partir de arquivos textos e func¸˜ao de impress˜ao de matrizes foram omitidas dos
programas. Focarmos a apresentac¸˜ao nas partes essenciais de processamento de matrizes.
3.1. Decomposic¸˜ao A=LU
Este algoritmo consiste em fazer a fatorac¸˜ao da A em LU. Abaixo inclu´ımos o c´odigo
utilizado para processar computacionalmente essa operac¸˜ao.
public static void TransformaTraingularLU(Double[][]
matriz, int numLin,
int numCol, Double[][] matrizL) {
/*
* Decomposi o de A em L e U
*
* L
* |1 0 0|
* |R 1 0|
* |R R 1|
*
* U
* |R R R|
* |0 R R|
* |0 0 R|
*
* */
for (int k = 0; k < numLin; k++) { //n
for (int i = k + 1; i < numLin; i++) { //n*n
matrizL[i][k] = (double)
matriz[i][k].floatValue()/
matriz[k][k].floatValue();
matriz[i][k] = 0.0;
for (int j = k + 1; j < numLin; j++)
{//n*n*n
matriz[i][j] = (double)
matriz[i][j].floatValue()-
(matrizL[i][k].floatValue() *
matriz[k][j].floatValue());
}
}
}
}
3.2. Decomposic¸˜ao A=LDU
Este algoritmo consiste em fazer a fatorac¸˜ao da A em LU, depois fatorar U para obter DU’.
Abaixo inclu´ımos o c´odigo utilizado para processar computacionalmente essa operac¸˜ao.
public static void TransformaTraingularLU(Double[][]
matriz, int numLin,
int numCol, Double[][] matrizL) {
/*
* Decomposi o de A em L e U
*
* L
* |1 0 0|
* |R 1 0|
* |R R 1|
*
* U
* |R R R|
* |0 R R|
* |0 0 R|
*
* */
for (int k = 0; k < numLin; k++) { //n
for (int i = k + 1; i < numLin; i++) { //n*n
matrizL[i][k] = (double)
matriz[i][k].floatValue()/
matriz[k][k].floatValue();
matriz[i][k] = 0.0;
for (int j = k + 1; j < numLin; j++)
{//n*n*n
matriz[i][j] = (double)
matriz[i][j].floatValue()-
(matrizL[i][k].floatValue() *
matriz[k][j].floatValue());
}
}
}
}
public static void DecompoeUemDU(Double[][] matriz, int
numLin, int numCol, Double[][] matrizx) {
/*
* U*matrizy = b (matrizx)
* Calcula U[m,n]/D[x,y] = U’ sendo que x=y
*
* U’
* |1 R R|
* |0 1 R|
* |0 0 1|
*
* D
* |R 0 0|
* |0 R 0|
* |0 0 R|
*
*
* */
for (int k = 0; k < numLin; k++) {n
for (int i = 0; i < numCol; i++) {n*n
matrizx[i][k] = 0.0;
}
}
for (int p = numLin - 1; p >= 0; p--) {n
matrizx[p][p]=(double)matriz[p][p].floatValue();
for (int j = p; j < numCol; j++) {n*n
matriz[p][j]=(double)matriz[p][j].floatValue()/matrizx[p][p].flo
}
}
}
3.3. M´etodo de Gauss-Jordan
Este algoritmo consiste em aplicar operac¸˜oes elementares `a matriz aumentada de um sis-
tema, at´e que ela esteja na forma escalonada reduzida. Abaixo inclu´ımos o c´odigo utili-
zado para processar computacionalmente essa operac¸˜ao.
public static void Gauss(double[][] matriz, int numLin,
int numCol, double[] matriz2, int numCol2,
double[][] matrizx ) {
double[][] a;// N-por-N+1 matriz aumentada
// constroi a matriz
a = new double[numCol2][numCol2 + numCol2 + 1];
for (int i = 0; i < numCol2; i++)//n
for (int j = 0; j < numCol2; j++)//n*n
a[i][j] = matriz[i][j];
for (int i = 0; i < numCol2; i++)
a[i][numCol2 + i] = 1.0;
for (int i = 0; i < numCol2; i++)
a[i][numCol2 + numCol2] = matriz2[i];
// E l i m i n a o de Gauss-Jordan
for (int p = 0; p < numCol2; p++) {//n
// busca a linha do pivo usando pivoteamento
parcial
int max = p;
for (int i = p + 1; i < numCol2; i++) {//n*n
if (Math.abs(a[i][p]) >
Math.abs(a[max][p])) {
max = i;
}
}
// muda aposicao da linha p com a linha max
swap(p, max,a);
// singular ou quase singular
if (Math.abs(a[p][p]) <= EPSILON) {
continue;
// throw new
// RuntimeException("A Matriz e singular
ou quase singular");
}
// pivota
pivota(p, p,numCol2,a);//n*n*n
}
for (int i = 0; i < numCol2; i++){
matriz2[i]=a[i][6];
for (int j = 0; j < numCol2; j++)
matrizx[i][j] = a[i][j];
}
System.out.println();
}
// executa o pivoteamento em (p, q) usando Eliminacao
Gauss-Jordan
private static void pivota(int p, int q,int N, double
a[][]) {
// altera tudo, menos linha p e coluna q
for (int i = 0; i < N; i++) {//n
double alpha = a[i][q] / a[p][q];
for (int j = 0; j <= N + N; j++) {//n*n
if (i != p && j != q)
a[i][j] -= alpha * a[p][j];
}
}
// zera a coluna q
for (int i = 0; i < N; i++)
if (i != p)
a[i][q] = 0.0;
// escala a linha p
for (int j = 0; j <= N + N; j++)
if (j != q)
a[p][j] /= a[p][q];
a[p][q] = 1.0;
}
3.4. M´etodo de Crout
Este algoritmo consiste em fazer a fatorac¸˜ao da A em LU, sendo que L ´e triangular
inferior e U ´e triangular superior unit´aria. Abaixo inclu´ımos o c´odigo utilizado para
processar computacionalmente essa operac¸˜ao.
public static void TransformaTraingularLU(Double[][]
matriz, int numLin,
int numCol, Double[][] matrizL,Double[][] matrizU)
{
/*
* Decomposi o de A em L e U
*
* L
* |R 0 0|
* |R R 0|
* |R R R|
*
* U
* |1 R R|
* |0 1 R|
* |0 0 1|
*
*
* */
int i, j, k;
double sum = 0;
for (int linha = 0; linha < numLin; linha++) {
for (int coluna = 0; coluna < numCol; coluna++) {
if (linha == coluna) {
matrizU[linha][coluna] = 1.0;
} else {
matrizU[linha][coluna] = 0.0;
}
}
}
for (j = 0; j < numLin; j++) {
for (i = j; i < numCol; i++) {
sum = 0;
for (k = 0; k < j; k++) {
sum = sum +
matrizL[i][k].floatValue() *
matrizU[k][j].floatValue();
}
matrizL[i][j] = matriz[i][j].floatValue()
- sum;
}
for (i = j; i < numCol; i++) {
sum = 0;
for(k = 0; k < j; k++) {
sum = sum +
matrizL[j][k].floatValue() *
matrizU[k][i].floatValue();
}
if (matrizL[j][j] == 0) {
System.out.printf("t Foi
encontrada uma divizao por zero
que impossibilita a e x e c u o
desse metodo.");
}
else{
matrizU[j][i] =
(matriz[j][i].floatValue() -
sum) /
matrizL[j][j].floatValue();
}
}
}
}
public static void DecompoeLemDL(Double[][] matriz, int
numLin,
int numCol, Double[][] matrizx) {
/*
* L*matrizy = b (matrizx)
* Calcula L[m,n]/D[x,y] = L’ sendo que x=y
*
* L
* |R 0 0|
* |R R 0|
* |R R R|
*
* <=>
*
* L’
* |1 0 0|
* |R 1 0|
* |R R 1|
*
* D
* |R 0 0|
* |0 R 0|
* |0 0 R|
*
* */
for (int k = 0; k < numLin; k++) {
for (int i = 0; i < numCol; i++) {
matrizx[i][k] = 0.0;
}
}
for (int p = numLin - 1; p >= 0; p--) {
matrizx[p][p]=(double)matriz[p][p].floatValue();
for (int j = p; j >= 0; j--) {
matriz[p][j]=
(double)matriz[p][j].floatValue()/
matrizx[p][p].floatValue();
}
}
}
4. Conclus˜ao
Podemos concluir que existem v´arias formas de processar e resolver sistemas lineares uti-
lizando conceitos de ´Algebra Linear de forma computacional. O estudo visa alcanc¸ar a
utilizac¸˜ao pr´atica de sistemas lineares e de matrizes, superando as limitac¸˜oes da resoluc¸˜ao
manual de problemas reais e compreendendo os resultados obtidos atrav´es de sistemas
computacionais. Com esse trabalho esperamos contribuir com o aprendizado da ´algebra
linear computacional no curso de ciˆencias computacionais, possibilitando que esses algo-
ritmos sejam utilizadas e que inspirem a elaborac¸˜ao de teses, n˜ao apenas no conte´udo de
sistemas lineares, sua representac¸˜ao e soluc¸˜ao matricial mas tamb´em em outras situac¸˜oes
onde seja poss´ıvel discutir a contribuic¸˜ao da matem´atica da soluc¸˜ao de problemas reais.
5. Apˆendice
Nessa sess˜ao apresentamos os algoritmos que serviram de apoio para o desenvolvimento
das operac¸˜oes com matrizes. S˜ao eles:
5.1. Impress˜ao de Matriz
Essa func¸˜ao percorre todos os campos da matriz apresentando-os no log do console do
programa.
public static void imprimeMatriz(Double[][] matriz, int
numLin, int numCol) {
for (int linha = 0; linha < numLin; linha++) {
for (int coluna = 0; coluna < numCol; coluna++) {
System.out.printf("t %.2f t",
matriz[linha][coluna]);
}
System.out.println();
}
}
5.2. Carrega a Matriz
Essa func¸˜ao carrega os campos de uma matriz que est˜ao armazenados em um arquivo
texto para uma array de Double. Essa func¸˜ao foi desenvolvida para facilitar o processo de
carga da matriz.
public static String carregaMatriz(Double[][] matriz,
String nomeArquivo) {
Scanner arquivo;
String linCol = "";
try {
arquivo = new Scanner(new File(nomeArquivo));
int j = 0;
int i = 0;
while (arquivo.hasNextLine()) {
String line = arquivo.nextLine();
Scanner scanner = new Scanner(line);
scanner.useDelimiter(",");
j = 0;
while (scanner.hasNextDouble()) {
matriz[i][j] =
scanner.nextDouble();
j++;
}
scanner.close();
i++;
}
arquivo.close();
linCol = Integer.toString(i) + "," +
Integer.toString(j);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return linCol;
}
Referˆencias
ANTON, H. & BUSBY, R. (2006). Algebra Linear Contemporˆanea. BOOKMAN COM-
PANHIA EDITORA, 1th edition.
RUGGIERO, M.G. & LOPES, V. (1996). C´alculo num´erico – aspectos computacionais.

Algebra linear operações com matrizes

  • 1.
    ´Algebra Linear -Operac¸˜oes com Matrizes Felipe Schimith Batista1 1 Instituto de Matem´atica e Estat´ısitica - Universidade Estadual do Rio de Janeiro felipeschimith@gmail.com Resumo. O trabalho visa contextualizar os teoremas e m´etodos da ´Algebra Li- near aplicados em soluc¸˜oes computacionais. Este trabalho apresenta o refe- rencial te´orico utilizado como base para resolver computacionalmente sistemas lineares. Apresentaremos a ”Decomposic¸˜ao A=LU”fazendo uma comparac¸˜ao com a decomposic¸˜ao de Gauss, a ”Decomposic¸˜ao A=LDU”comparando-a com o m´etodo de Crout. Por fim apresentamos o ”M´etodo de Gauss-Jordan”que obt´em a inversa de uma matriz. A implementac¸˜ao foi feita na linguagem de programac¸˜ao Java e tamb´em ser´a documentada e comentada. 1. Introduc¸˜ao Na Matem´atica a teoria de sistemas lineares ´e a base e uma parte fundamental da ´algebra linear, um tema que ´e usado na maior parte da matem´atica moderna. Deve-se observar que, em primeiro lugar, a equac¸˜ao linear ´e, necessariamente, uma equac¸˜ao polinomial. Tamb´em na matem´atica aplicada, podemos encontrar v´arios usos de sistemas lineares. Exemplos s˜ao a f´ısica, a economia, a engenharia, a biologia, a geografia, a navegac¸˜ao, a aviac¸˜ao, a cartografia, a demografia e a astronomia.[RUGGIERO 1996] Um sistema de equac¸˜oes lineares ´e um conjunto finito de equac¸˜oes lineares aplicadas num mesmo conjunto, igualmente finito, de vari´aveis.[ANTON 2006] Algoritmos computacionais s˜ao, por encontrar as soluc¸˜oes, uma parte importante da ´algebra linear num´erica. Voltando na hist´oria da ´algebra linear, uma vers˜ao preliminar da eliminac¸˜ao gaussiana apareceu pela primeira vez no livro chinˆes “Nove Cap´ıtulos de Arte Matem´atica”, em torno de 200 a.C. O poder do m´etodo n˜ao tinha sido reconhecido at´e que o grande matem´atico Carl Friedich Gauss no ano de 1801 utilizou o m´etodo para calcular a ´orbita do asteroide Ceres com pouqu´ıssimas informac¸˜oes utilizando m´ınimos quadrados e o procedimento que hoje denominamos eliminac¸˜ao gaussiana. O trabalho de Gauss causou sensac¸˜ao quando Ceres reapareceu na constelac¸˜ao de Virgem, local aproximado aos seus c´alculos.[ANTON 2006] Mais tarde o m´etodo foi popularizado quando Willian Jordan (engenheiro alem˜ao) em 1888 publicou no seu livro de geod´esia intitulado “Handbuch der Vermessungskunde”. Embora as ideias tenham sido conhecidas antes, muitas vezes o cr´edito pela popularizac¸˜ao da decomposic¸˜ao LU ´e atribu´ıda ao l´ogico e matem´atico britˆanico Alan Turing, pelo seu trabalho de 1948 nesse assunto. Ao final dos anos 1970, a Fundac¸˜ao Nacional de Ciˆencias e o Departamento de Energia dos EUA financiaram o desenvolvimento de rotinas de computacionais para in- verter matrizes e resolver sistemas de equac¸˜oes lineares. Aquela pesquisa levou a um conjunto de programas Fortran chamado LINPAC que s˜ao uma referˆencia para muitos algoritmos computacionais de hoje, inclusive no MATLAB. As rotinas LIMPAC est˜ao
  • 2.
    organizadas em tornode quatro fatorac¸˜oes de matrizes, uma das quais ´e a decomposic¸˜ao LU. C.B. Moler, J.J. Dongarra, G.W. Stewart e J.R. Brunch, os principais programadores do LINPAC, basearam muitas de suas id´eias no trabalho de Jemes Boyle e Kenneth Dritz, do Laborat´orio Argonne (nos EUA).[ANTON 2006] 2. Teoria de Matrizes Este cap´ıtulo tem como objetivo apresentar as propriedades, teoremas e m´etodos da ´Algebra Linear que foram usados como base para implementar soluc¸˜oes computacionais para resolver equac¸˜oes lineares utilizando matrizes. 2.1. Resoluc¸˜ao de Sistemas Lineares Antes de nos aprofundarmos nas operac¸˜oes com matrizes, ´e necess´ario entender os con- ceitos e m´etodos das operac¸˜oes elementares de um sistema linear que podemos imple- mentar para encontrar as soluc¸˜oes computacionalmente. Por exemplo, um m´etodo para resolver um sistema linear ´e substituir o sistema inicial por outro que tenha o mesmo con- junto soluc¸˜ao do primeiro, mas que seja muito mais f´acil de resolver. O novo sistema ´e obtido ap´os a aplicac¸˜ao de uma s´erie de operac¸˜oes que simplificam as equac¸˜oes do sistema que tˆem a propriedade especial de n˜ao alterar o conjunto soluc¸˜ao. Estas operac¸˜oes s˜ao chamadas operac¸˜oes elementares e s˜ao de trˆes tipos diferentes. • Trocar duas equac¸˜oes do sistema de posic¸˜ao. • Substituir uma equac¸˜ao pela mesma equac¸˜ao multiplicada por um escalar diferente de 0. • Substituir uma equac¸˜ao pela mesma equac¸˜ao somada a outra equac¸˜ao multiplicada por um escalar. Note que se multiplicarmos uma equac¸˜ao por 0, estaremos excluindo esta equac¸˜ao do sistema, o que tem o efeito prov´avel de aumentar o conjunto soluc¸˜ao, por isso, esta n˜ao ´e uma operac¸˜ao elementar. ´E f´acil ver que ao efetuarmos qualquer uma das operac¸˜oes acima sobre as equac¸˜oes do sistema, n˜ao estaremos acrescentando nem dimi- nuindo soluc¸˜oes. Somente os coeficientes do sistema s˜ao alterados atrav´es das operac¸˜oes elemen- tares, as vari´aveis permanecem inalteradas. Portanto, na hora de efetuar os c´alculos, ao inv´es de considerar todo o sistema, podemos considerar apenas a matriz de coeficientes do sistema, chamada matriz aumentada: [A|B] = α11 α12 ... α1n β1 α21 α22 ... α2n β2 α31 α32 ... α3n β3 ... ... ... ... αm1 αm2 ... αmn βm As operac¸˜oes elementares ser˜ao efetuadas sobre as linhas desta matriz. Definic¸˜ao. Operac¸˜oes Elementares sobre as linhas de uma matriz: • a troca da posic¸˜ao relativa de duas linhas Li ← Lj
  • 3.
    • a multiplicac¸˜aode uma linha por uma constante Li ← cLj ⇔ c = 0 • a substituic¸˜ao de uma linha pela sua soma com outra linha qualquer Li ← Li + Lj Teorema. Se dois sistemas lineares Ax = B e Cx = D s˜ao tais que a matriz aumentada [C|D] ´e obtida de [A|B] aplicando-se operac¸˜oes elementares, ent˜ao os dois sistemas pos- suem as mesmas soluc¸˜oes. Sistemas que possuem as mesmas soluc¸˜oes s˜ao chamados sistemas equivalentes. 2.2. Decomposic¸˜ao A=LU A decomposic¸˜ao LU de uma matriz A surge da necessidade de resolver um conjunto de sistemas do tipo Ax = b1, Ax = b2, Ax = b3 e assim por diante. Poder´ıamos resolver cada um desses sistemas escalonando a matriz completa [A b] correspondente at´e sua forma escalonada reduzida mas, computacionalmente, o escalonamento ´e um processo muito demorado e poder´ıamos ter centenas de b’s para resolver. Supondo-se que A seja uma matriz mxm que pode ser escalonada at´e sua forma reduzida sem trocar linhas, a ´Algebra Linear nos diz que ela pode ser escrita na forma A = LU, onde L Lower ´e uma matriz triangular inferior mxm cuja diagonal principal possui apenas 1’s e U Upper ´e uma matriz triangular superior mxm que nada mais ´e do que a pr´opria forma escalonada reduzida de A. Para uma matriz 3x3: A = L*U   a11 a12 a13 a21 a22 a23 a31 a32 a33   =   1 0 0 l21 1 0 l31 l32 1   ∗   u11 u12 u13 0 u22 u23 0 0 u33   A importˆancia de escrevermos uma matriz como o produto de duas outras matrizes triangulares, uma inferior e a outra superior, se d´a pelo fato de que, ao assumirmos que A = LU, podemos reescrever a equac¸˜ao Ax = b como LUx = B ou, pela propriedade associativa, L(Ux) = B. Tomando-se Ux = y, temos Ly = b e Ux = y. Resolvendo-se a primeira equac¸˜ao para y e a segunda para x, obteremos a resposta procurada de uma maneira bem mais simples do que fazer pelo m´etodo tradicional, visto que as matrizes s˜ao triangulares. Vale lembrar que quando um pivˆo nulo ´e encontrado temos um caso onde pode ou n˜ao existir uma decomposic¸˜ao LU. 2.2.1. Comparando eliminac¸˜ao gaussiana com decomposic¸˜ao LU Para determinac¸˜ao das inc´ognitas, o m´etodo da eliminac¸˜ao de Gauss desenvolve duas fa- ses: a primeira ´e a eliminac¸˜ao progressiva, onde reduz o n´umero de vari´aveis ao longo da execuc¸˜ao para, ent˜ao, aplicar a segunda fase, chamada de substituic¸˜ao regressiva, onde utiliza o resultado da primeira para determinar a soluc¸˜ao geral do sistema. Dois passos descritos, o primeiro ´e o que consome mais tempo de c´alculo, uma vez que ´e nesta fase que consiste o maior n´umero de operac¸˜oes aritm´eticas e de trocas dedados. Por isso, encontrar um m´etodo que minimize esta fase cr´ıtica implica em aumentar o
  • 4.
    desempenho para realizara tarefa de resoluc¸˜ao de sistemas lineares. Os m´etodos de decomposic¸˜ao LU consistem em separar a fase de eliminac¸˜ao da matriz dos coeficien- tes, que consomem maior tempo, das manipulac¸˜oes envolvidas com o vetor dos termos independentes. Portanto, devemos deixar claro que, ao contr´ario da eliminac¸˜ao de Gauss, uma decomposic¸˜ao de LU ´e uma estrat´egia de melhoria na resoluc¸˜ao de sistemas lineares. Sendo assim, n˜ao existe “o m´etodo” de decomposic¸˜ao LU, mas sim algumas abordagens a serem tomadas que permitem decompor o sistema. Uma implicac¸˜ao interessante disso ´e que a pr´opria eliminac¸˜ao de Gauss pode ser descrita como uma decomposic¸˜ao LU. O custo de processamento do algoritmo de decomposic¸˜ao LU pode ser visto pelo n´umero de estruturas de repetic¸˜ao utilizados no c´odigo. No c´odigo implementado, o custo ´e da Ordem(n3 ) para a decomposic¸˜ao LU. /* * Decomposi o de A em L e U * */ for (int k = 0; k < numLin; k++) { //n for (int i = k + 1; i < numLin; i++) { //n*n matrizL[i][k] = (double) matriz[i][k].floatValue()/ matriz[k][k].floatValue(); matriz[i][k] = 0.0; for (int j = k + 1; j < numLin; j++) {//n*n*n matriz[i][j] = (double) matriz[i][j].floatValue()- (matrizL[i][k].floatValue() * matriz[k][j].floatValue()); } } } } Da mesma forma podemos calcular o custo de processamento do algoritmo de eliminac¸˜ao Gaussiana pode ser visto pelo n´umero de estruturas de repetic¸˜ao utilizados no c´odigo. No c´odigo implementado no trabalho anterior, o custo ´e da Ordem(n3 ). /** * A primeira funcao obtem a triangular superior da matriz composta. */ public static void TriangularSuperior(Double[][] matriz, int numLin, int numCol, Double[][] matriz2, int numLin2, int numCol2,Double[][] matrizx) { double calculo; for (int coluna = 0; coluna < numLin2; coluna++) {n for (int linha = coluna + 1; linha < numLin2;
  • 5.
    linha++) {n*n calculo = (matriz[linha][coluna].floatValue()/ matriz[coluna][coluna].floatValue()); matriz[linha][coluna]=0.0; for(int s=coluna+1; s <numLin2; s++){n*n*n matriz[linha][s]= matriz[linha][s].floatValue() - (calculo*matriz[coluna][s].floatValue()); } matriz2[linha][0]= (double)matriz2[linha][0].floatValue() - (matriz2[coluna][0].floatValue()*calculo); } } } Podemos concluir que o custo do processamento da decomposic¸˜ao LU ´e idˆentico ao custo da Eliminac¸˜ao Gaussiana. 2.3. Decomposic¸˜ao A=LDU A Decomposic¸˜ao A=LDU tamb´em ´e utilizada para soluc¸˜ao de sistemas lineares, que con- siste em efetuar a decomposic¸˜ao da matriz A em trˆes componentes L Lower, D Diagonal e U Upper a soma dos elementos correspondentes. A decomposic¸˜ao A = LDU permite resolver um sistema Ax = b em trˆes passos: • achar c de Lc = b • achar z de Dz = c • achar x de Ux = z A decomposic¸˜ao LDU ´e ´unica e permite flexibilidade para o c´alculo pr´atico das matrizes L e U. Por exemplo, isto acontece com a reduc¸˜ao de Crout, na qual considera-se LD como sendo uma matriz triangular inferior L (sem elementos unit´arios na sua diago- nal) de modo que A = LU com U triangular superior e elementos unit´arios na sua diagonal. Esta reduc¸˜ao permite calcular alternadamente as colunas de L e de U. O processo consiste em obter primeiramente a fatorac¸˜ao LU, e depois decom- pondo a matriz U no produto de uma matriz D, com uma matriz que tamb´em se designa por U, onde: • D ´e uma matriz m x m diagonal cujos elementos da diagonal principal s˜ao os pivos da eliminac¸˜ao de Gauss ou zero no caso de n˜ao haver pivˆo; • U ´e uma matriz m x m obtida apos eliminac¸˜ao de Gauss, dividindo cada linha pelo respectivo pivo. Para uma matriz 3x3: A=LDU
  • 6.
      a11 a12 a13 a21a22 a23 a31 a32 a33   =   1 0 0 l21 1 0 l31 l32 1   ∗   d11 0 0 0 d22 0 0 0 d33   ∗   1 u12 u13 0 1 u23 0 0 1   Quando um pivˆo nulo ´e encontrado temos um caso onde pode ou n˜ao existir uma decomposic¸˜ao LU. A decomposic¸˜ao LU n˜ao ´e ´unica, j´a a decomposic¸˜ao LDU por sua vez ´e ´unica. 2.3.1. Comparac¸˜ao da decomposic¸˜ao LDU e Crout Para compararmos LDU com Crout primeiro precisamos de fazer uma pequena apresentac¸˜ao de Crout que ´e uma variante da fatorac¸˜ao triangular da matriz A. Toma-se a matriz U como triangular de diagonal unit´aria e L como triangular inferior.   a11 a12 a13 a21 a22 a23 a31 a32 a33   =   l11 0 0 l21 l22 0 l31 l32 l33   ∗   1 u12 u13 0 1 u23 0 0 1   Como falado anteriormente a decomposic¸˜ao LDU consiste numa pequena alterac¸˜ao da fatorac¸˜ao de Crout e tem a vantagem de atribuir `as matrizes triangulares L e U um papel totalmente idˆentico. Consiste em considerar que estas s˜ao ambas matrizes triangulares com diagonal unit´aria e tomar a fatorac¸˜ao na seguinte forma A = LDU em que D ´e uma matriz diagonal. O custo de processamento do algoritmo de decomposic¸˜ao LDU pode ser visto pelo n´umero de estruturas de repetic¸˜ao utilizados no c´odigo. No c´odigo implementado, o custo ´e da Ordem (n3 ) para a decomposic¸˜ao de A em LU e n2 para decomposic¸˜ao de U em DU’. Resumindo podemos concluir que a decomposic¸˜ao LDU tem o custo ´e da Ordem(n3 ). public static void TransformaTraingularLU(Double[][] matriz, int numLin, int numCol, Double[][] matrizL) { /* * Decomposi o de A em L e U * */ for (int k = 0; k < numLin; k++) { //n for (int i = k + 1; i < numLin; i++) { //n*n matrizL[i][k] = (double) matriz[i][k].floatValue()/ matriz[k][k].floatValue(); matriz[i][k] = 0.0; for (int j = k + 1; j < numLin; j++) {//n*n*n matriz[i][j] = (double) matriz[i][j].floatValue()- (matrizL[i][k].floatValue() * matriz[k][j].floatValue()); } }
  • 7.
    } } public static voidDecompoeUemDU(Double[][] matriz, int numLin, int numCol, Double[][] matrizx) { /* * U*matrizy = b (matrizx) * Calcula U[m,n]/D[x,y] = U’ sendo que x=y * */ for (int k = 0; k < numLin; k++) {//n for (int i = 0; i < numCol; i++) {//n*n matrizx[i][k] = 0.0; } } for (int p = numLin - 1; p >= 0; p--) {//n matrizx[p][p]=(double)matriz[p][p].floatValue(); for (int j = p; j < numCol; j++) {//n*n matriz[p][j]=(double)matriz[p][j].floatValue() /matrizx[p][p].floatValue(); } } } O custo de processamento do algoritmo de Crout tamb´em pode ser visto pelo n´umero de estruturas de repetic¸˜ao utilizados no c´odigo. No c´odigo implementado, o custo ´e n3 para a decomposic¸˜ao de A em LU e n2 para decomposic¸˜ao de L em DL’. public static void TransformaTraingularLU(Double[][] matriz, int numLin, int numCol, Double[][] matrizL,Double[][] matrizU) { /* * Decomposi o de A em L e U * */ int i, j, k; double sum = 0; for (int linha = 0; linha < numLin; linha++) {//n for (int coluna = 0; coluna < numCol; coluna++) {//n*n if (linha == coluna) { matrizU[linha][coluna] = 1.0; } else { matrizU[linha][coluna] = 0.0; } } }
  • 8.
    for (j =0; j < numLin; j++) {//n for (i = j; i < numCol; i++) {//n*n sum = 0; for (k = 0; k < j; k++) {//n*n*n sum = sum + matrizL[i][k].floatValue() * matrizU[k][j].floatValue(); } matrizL[i][j] = matriz[i][j].floatValue() - sum; } for (i = j; i < numCol; i++) {//n*n sum = 0; for(k = 0; k < j; k++) {//n*n*n sum = sum + matrizL[j][k].floatValue() * matrizU[k][i].floatValue(); } if (matrizL[j][j] == 0) { System.out.printf("t Foi encontrada uma divizao por zero que impossibilita a execucao desse metodo."); } else{ matrizU[j][i] = (matriz[j][i].floatValue() - sum) / matrizL[j][j].floatValue(); } } } } public static void DecompoeLemDL(Double[][] matriz, int numLin, int numCol, Double[][] matrizx) { /* * L*matrizy = b (matrizx) * Calcula L[m,n]/D[x,y] = L’ sendo que x=y * */ for (int k = 0; k < numLin; k++) { //n for (int i = 0; i < numCol; i++) {//n*n matrizx[i][k] = 0.0;
  • 9.
    } } for (int p= numLin - 1; p >= 0; p--) {//n matrizx[p][p]=(double)matriz[p][p].floatValue(); for (int j = p; j >= 0; j--) {//n*n matriz[p][j]= (double)matriz[p][j].floatValue()/ matrizx[p][p].floatValue(); } } } Avaliando os algoritmos implementados podemos concluir que o algoritmo de Crout tem o custo O(n3 ) o que o torna praticamente idˆentico ao algoritmo de decomposic¸˜ao LDU o custo ´e da Ordem(n3 ). 2.4. M´etodo de Gauss-Jordan O m´etodo de Gauss-Jordan ´e um m´etodo de escalonamento que consiste em aplicar operac¸˜oes elementares `a matriz aumentada de um sistema, at´e que ela esteja na forma escalonada reduzida. A vantagem deste processo ´e que um sistema cuja matriz aumentada ´e uma matriz na forma escalonada reduzida tem soluc¸˜ao imediata, enquanto que para resolver um sistema que est´a apenas na forma escalonada ainda ´e necess´ario fazer uma s´erie de substituic¸˜oes para obter a soluc¸˜ao final. • O primeiro elemento n˜ao-nulo de cada linha n˜ao-nula (chamado o pivˆo da linha) ´e igual a 1. • O pivˆo da linha i + 1 ocorre `a direita do pivˆo da linha i. • Se uma coluna cont´em um pivˆo, ent˜ao todas os outros elementos desta coluna s˜ao iguais a 0. • Todas as linhas nulas ocorrem abaixo das linhas n˜ao-nulas. As etapas para resolver um sistemas de equac¸˜oes utilizando a eliminac¸˜ao de Gauss-Jordan ´e descrito a seguir. 1. Escreva a matriz aumentada do sistema. 2. Use as operac¸˜oes lineares para transformar a matriz aumentada na forma descrita abaixo, que ´e chamado de forma escalonada reduzida de linha. (a) Em cada linha que n˜ao consiste inteiramente em zeros, o elemento dife- rente de zero mais `a esquerda ´e o pivˆo. (b) Cada coluna que cont´em um pivˆo tem zeros em todas as outras entradas. (c) O pivˆo em qualquer linha est´a `a esquerda de qualquer pivˆo nas linhas abaixo dele. (d) ) Caso existam linhas que consistem inteiramente de zeros, elas s˜ao agru- padas em conjunto na parte inferior da matriz. 3. Ao atingir o resultado descrito no processo 2, se vocˆe obter uma linha cujos ele- mentos s˜ao todos os zeros, exceto a ´ultima `a direita. Nesse caso, o sistema ´e inconsistente e n˜ao tem soluc¸˜oes. Caso contr´ario, as soluc¸˜oes do sistema est˜ao na matriz final.
  • 10.
    Avaliando os algoritmosimplementados podemos concluir que o algoritmo de Gauss-Jordan tem o custo na Ordem(n3 ) o que o torna praticamente idˆentico ao custo do algoritmo de decomposic¸˜ao LDU e ao custo do M´etodo de Crout avaliados nesse artigo. 3. Algoritmos Este cap´ıtulo apresenta os algoritmos desenvolvidos utilizando como base os conheci- mentos adquiridos na ´algebra linear. Algumas func¸˜oes secund´arias como obtenc¸˜ao das matrizes a partir de arquivos textos e func¸˜ao de impress˜ao de matrizes foram omitidas dos programas. Focarmos a apresentac¸˜ao nas partes essenciais de processamento de matrizes. 3.1. Decomposic¸˜ao A=LU Este algoritmo consiste em fazer a fatorac¸˜ao da A em LU. Abaixo inclu´ımos o c´odigo utilizado para processar computacionalmente essa operac¸˜ao. public static void TransformaTraingularLU(Double[][] matriz, int numLin, int numCol, Double[][] matrizL) { /* * Decomposi o de A em L e U * * L * |1 0 0| * |R 1 0| * |R R 1| * * U * |R R R| * |0 R R| * |0 0 R| * * */ for (int k = 0; k < numLin; k++) { //n for (int i = k + 1; i < numLin; i++) { //n*n matrizL[i][k] = (double) matriz[i][k].floatValue()/ matriz[k][k].floatValue(); matriz[i][k] = 0.0; for (int j = k + 1; j < numLin; j++) {//n*n*n matriz[i][j] = (double) matriz[i][j].floatValue()- (matrizL[i][k].floatValue() * matriz[k][j].floatValue()); } } }
  • 11.
    } 3.2. Decomposic¸˜ao A=LDU Estealgoritmo consiste em fazer a fatorac¸˜ao da A em LU, depois fatorar U para obter DU’. Abaixo inclu´ımos o c´odigo utilizado para processar computacionalmente essa operac¸˜ao. public static void TransformaTraingularLU(Double[][] matriz, int numLin, int numCol, Double[][] matrizL) { /* * Decomposi o de A em L e U * * L * |1 0 0| * |R 1 0| * |R R 1| * * U * |R R R| * |0 R R| * |0 0 R| * * */ for (int k = 0; k < numLin; k++) { //n for (int i = k + 1; i < numLin; i++) { //n*n matrizL[i][k] = (double) matriz[i][k].floatValue()/ matriz[k][k].floatValue(); matriz[i][k] = 0.0; for (int j = k + 1; j < numLin; j++) {//n*n*n matriz[i][j] = (double) matriz[i][j].floatValue()- (matrizL[i][k].floatValue() * matriz[k][j].floatValue()); } } } } public static void DecompoeUemDU(Double[][] matriz, int numLin, int numCol, Double[][] matrizx) { /* * U*matrizy = b (matrizx) * Calcula U[m,n]/D[x,y] = U’ sendo que x=y * * U’ * |1 R R|
  • 12.
    * |0 1R| * |0 0 1| * * D * |R 0 0| * |0 R 0| * |0 0 R| * * * */ for (int k = 0; k < numLin; k++) {n for (int i = 0; i < numCol; i++) {n*n matrizx[i][k] = 0.0; } } for (int p = numLin - 1; p >= 0; p--) {n matrizx[p][p]=(double)matriz[p][p].floatValue(); for (int j = p; j < numCol; j++) {n*n matriz[p][j]=(double)matriz[p][j].floatValue()/matrizx[p][p].flo } } } 3.3. M´etodo de Gauss-Jordan Este algoritmo consiste em aplicar operac¸˜oes elementares `a matriz aumentada de um sis- tema, at´e que ela esteja na forma escalonada reduzida. Abaixo inclu´ımos o c´odigo utili- zado para processar computacionalmente essa operac¸˜ao. public static void Gauss(double[][] matriz, int numLin, int numCol, double[] matriz2, int numCol2, double[][] matrizx ) { double[][] a;// N-por-N+1 matriz aumentada // constroi a matriz a = new double[numCol2][numCol2 + numCol2 + 1]; for (int i = 0; i < numCol2; i++)//n for (int j = 0; j < numCol2; j++)//n*n a[i][j] = matriz[i][j]; for (int i = 0; i < numCol2; i++) a[i][numCol2 + i] = 1.0; for (int i = 0; i < numCol2; i++) a[i][numCol2 + numCol2] = matriz2[i]; // E l i m i n a o de Gauss-Jordan for (int p = 0; p < numCol2; p++) {//n
  • 13.
    // busca alinha do pivo usando pivoteamento parcial int max = p; for (int i = p + 1; i < numCol2; i++) {//n*n if (Math.abs(a[i][p]) > Math.abs(a[max][p])) { max = i; } } // muda aposicao da linha p com a linha max swap(p, max,a); // singular ou quase singular if (Math.abs(a[p][p]) <= EPSILON) { continue; // throw new // RuntimeException("A Matriz e singular ou quase singular"); } // pivota pivota(p, p,numCol2,a);//n*n*n } for (int i = 0; i < numCol2; i++){ matriz2[i]=a[i][6]; for (int j = 0; j < numCol2; j++) matrizx[i][j] = a[i][j]; } System.out.println(); } // executa o pivoteamento em (p, q) usando Eliminacao Gauss-Jordan private static void pivota(int p, int q,int N, double a[][]) { // altera tudo, menos linha p e coluna q for (int i = 0; i < N; i++) {//n double alpha = a[i][q] / a[p][q]; for (int j = 0; j <= N + N; j++) {//n*n if (i != p && j != q) a[i][j] -= alpha * a[p][j];
  • 14.
    } } // zera acoluna q for (int i = 0; i < N; i++) if (i != p) a[i][q] = 0.0; // escala a linha p for (int j = 0; j <= N + N; j++) if (j != q) a[p][j] /= a[p][q]; a[p][q] = 1.0; } 3.4. M´etodo de Crout Este algoritmo consiste em fazer a fatorac¸˜ao da A em LU, sendo que L ´e triangular inferior e U ´e triangular superior unit´aria. Abaixo inclu´ımos o c´odigo utilizado para processar computacionalmente essa operac¸˜ao. public static void TransformaTraingularLU(Double[][] matriz, int numLin, int numCol, Double[][] matrizL,Double[][] matrizU) { /* * Decomposi o de A em L e U * * L * |R 0 0| * |R R 0| * |R R R| * * U * |1 R R| * |0 1 R| * |0 0 1| * * * */ int i, j, k; double sum = 0; for (int linha = 0; linha < numLin; linha++) { for (int coluna = 0; coluna < numCol; coluna++) { if (linha == coluna) { matrizU[linha][coluna] = 1.0;
  • 15.
    } else { matrizU[linha][coluna]= 0.0; } } } for (j = 0; j < numLin; j++) { for (i = j; i < numCol; i++) { sum = 0; for (k = 0; k < j; k++) { sum = sum + matrizL[i][k].floatValue() * matrizU[k][j].floatValue(); } matrizL[i][j] = matriz[i][j].floatValue() - sum; } for (i = j; i < numCol; i++) { sum = 0; for(k = 0; k < j; k++) { sum = sum + matrizL[j][k].floatValue() * matrizU[k][i].floatValue(); } if (matrizL[j][j] == 0) { System.out.printf("t Foi encontrada uma divizao por zero que impossibilita a e x e c u o desse metodo."); } else{ matrizU[j][i] = (matriz[j][i].floatValue() - sum) / matrizL[j][j].floatValue(); } } } } public static void DecompoeLemDL(Double[][] matriz, int numLin, int numCol, Double[][] matrizx) {
  • 16.
    /* * L*matrizy =b (matrizx) * Calcula L[m,n]/D[x,y] = L’ sendo que x=y * * L * |R 0 0| * |R R 0| * |R R R| * * <=> * * L’ * |1 0 0| * |R 1 0| * |R R 1| * * D * |R 0 0| * |0 R 0| * |0 0 R| * * */ for (int k = 0; k < numLin; k++) { for (int i = 0; i < numCol; i++) { matrizx[i][k] = 0.0; } } for (int p = numLin - 1; p >= 0; p--) { matrizx[p][p]=(double)matriz[p][p].floatValue(); for (int j = p; j >= 0; j--) { matriz[p][j]= (double)matriz[p][j].floatValue()/ matrizx[p][p].floatValue(); } } } 4. Conclus˜ao Podemos concluir que existem v´arias formas de processar e resolver sistemas lineares uti- lizando conceitos de ´Algebra Linear de forma computacional. O estudo visa alcanc¸ar a utilizac¸˜ao pr´atica de sistemas lineares e de matrizes, superando as limitac¸˜oes da resoluc¸˜ao manual de problemas reais e compreendendo os resultados obtidos atrav´es de sistemas computacionais. Com esse trabalho esperamos contribuir com o aprendizado da ´algebra linear computacional no curso de ciˆencias computacionais, possibilitando que esses algo- ritmos sejam utilizadas e que inspirem a elaborac¸˜ao de teses, n˜ao apenas no conte´udo de
  • 17.
    sistemas lineares, suarepresentac¸˜ao e soluc¸˜ao matricial mas tamb´em em outras situac¸˜oes onde seja poss´ıvel discutir a contribuic¸˜ao da matem´atica da soluc¸˜ao de problemas reais. 5. Apˆendice Nessa sess˜ao apresentamos os algoritmos que serviram de apoio para o desenvolvimento das operac¸˜oes com matrizes. S˜ao eles: 5.1. Impress˜ao de Matriz Essa func¸˜ao percorre todos os campos da matriz apresentando-os no log do console do programa. public static void imprimeMatriz(Double[][] matriz, int numLin, int numCol) { for (int linha = 0; linha < numLin; linha++) { for (int coluna = 0; coluna < numCol; coluna++) { System.out.printf("t %.2f t", matriz[linha][coluna]); } System.out.println(); } } 5.2. Carrega a Matriz Essa func¸˜ao carrega os campos de uma matriz que est˜ao armazenados em um arquivo texto para uma array de Double. Essa func¸˜ao foi desenvolvida para facilitar o processo de carga da matriz. public static String carregaMatriz(Double[][] matriz, String nomeArquivo) { Scanner arquivo; String linCol = ""; try { arquivo = new Scanner(new File(nomeArquivo)); int j = 0; int i = 0; while (arquivo.hasNextLine()) { String line = arquivo.nextLine(); Scanner scanner = new Scanner(line); scanner.useDelimiter(","); j = 0; while (scanner.hasNextDouble()) { matriz[i][j] = scanner.nextDouble(); j++; } scanner.close(); i++;
  • 18.
    } arquivo.close(); linCol = Integer.toString(i)+ "," + Integer.toString(j); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return linCol; } Referˆencias ANTON, H. & BUSBY, R. (2006). Algebra Linear Contemporˆanea. BOOKMAN COM- PANHIA EDITORA, 1th edition. RUGGIERO, M.G. & LOPES, V. (1996). C´alculo num´erico – aspectos computacionais.