O documento discute algoritmos computacionais para resolver sistemas lineares utilizando decomposições de matrizes. Apresenta a decomposição A=LU comparando-a com a eliminação de Gauss e discute a implementação da decomposição LU em Java, notando que seu custo de processamento é da ordem de N3, assim como a eliminação de Gauss.
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 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
3. • 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
4. 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;
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
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());
}
}
7. }
}
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;
}
}
}
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 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());
}
}
}
11. }
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|
12. * |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
13. // 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];
14. }
}
// 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;
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, 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++;