Você está na página 1de 4

Sistema de Matrizes Esparsas Orientado por Objetos em C++

F.M. Paula, E. J. Silva, R. C. Mesquita


Departamento de Engenharia Eltrica - Universidade Federal de Minas Gerais
Av. do Contorno 842, Centro, Belo Horizonte, MG, 30110-060, Brasil

Resumo - O objetivo deste artigo mostrar a
potencialidade da programao orientada por objetos
( POO ) na implementao de mtodos de resoluo de sistemas
lineares compostos por matrizes esparsas reais e complexas.
Alguns exemplos de implementao em C++ so apresentados.
Um exemplo de validao utilizando o mtodo COCG
considerado. Alm disso, feita uma discusso sobre o tempo
computacional da implementao.

I. INTRODUO

Grandezas matriciais surgem em vrios sistemas de
software voltados para aplicaes numricas. Assim, a
possibilidade de introduzir matriz como um tipo definido
numa linguagem parece ser bastante atrativa. E isto , de
certa forma, o que as linguagens que suportam a
metodologia orientada por objetos permitem.
O sistema aqui discutido foi desenvolvido utilizando a
linguagem de programao C++ [4]. Esta linguagem foi
escolhida porque, alm de suportar os conceitos mais
avanados da POO, ela totalmente compatvel com o C.
Frisa-se que a programao orientada por objetos tem como
principais objetivos alcanar a portabilicade, legibilidade,
reusabilidade e facilidade de manuteno de programas
complexos.
A biblioteca numrica desenvolvida de aplicao
geral, entretanto, os mtodos para soluo de sistemas
lineares foram escolhidos considerando sua utilizao num
programa de elementos finitos[3]. Para matrizes reais, foi
implementado o ICCG ( Incomplete Cholesky Conjugated
Gradients ). Para matrizes complexas foram implementados
o bi-CG ( bi- Conjugated Gradients ) e o COCG (
Conjugate Orthogonal Conjugate Gradients ). Como
exemplo de implementao, o COCG ser descrito. Para
manipulaes simples, nas quais as matrizes podem ser
representadas na forma convencional, foram definidas duas
classes bsicas: Vector e Matrix. Estas classes suportam
uma variedade de construtores e mtodos de operaes
algbricas, a saber: multiplicao de matriz por vetor,
multiplicao de vetor por escalar, adio, subtrao,
transposio, norma de vetor. Para operar com nmeros
complexos utilizou-se a classe Complex da biblioteca
padro do C++.
Neste trabalho no se preocupou em apresentar os
conceitos da POO, nem a sintaxe e semntica do C++ para
os quais j existe um extensa bibliografia[4],[7].

II. MATRIZES ESPARSAS EM C++

As matrizes esparsas so armazenadas como um
conjunto de listas encadeadas em que cada lista representa
uma linha e cada link uma estrutura do tipo[1]:

struct Data{
int column;
double value;
Data *next; };

Fig.1. Estrutura de cada n da lista encadeada

Um arranjo de ponteiros de dimenso igual ao nmero
de linhas da matriz criado, sendo que cada elemento
contm o endereo das cabeas de lista. A classe matriz
esparsa pode ser representada pela seguinte estrutura de
dados:

class SparseMatrix
{
int numRows, numColumns;
Data **data;
public:
//construtor e destrutor
SparseMatrix(int nl, int nc);//inicializa matriz
~SparseMatrix();//desaloca memoria
//funes membro
double& operator () (int i, int j);
double& InsertElement(Element*,int,int,int);
...............
};

Fig.2. Matriz Esparsa

Para criar uma matriz dentro do programa basta declarar
SparseMatrix A(1000,1000). Desta forma, cria-se um
vetor de 1000 ponteiros correspondentes aos primeiros
elementos de cada linha(cabeas de lista), sendo que o
segundo ndice no usado na alocao. Os demais
elementos so gerados medida em que a matriz vai sendo
montada atravs dos mtodos InsertElement() e da
sobrecarga do operador (). Assim a declarao A(10,10) =
200 valida.
Esta estrutura tem mostrado ser bastante eficiente no
programa de clculo de campos em funo de dois fatores
principais:
a) cada linha pode ser acessada diretamente;
b) a matriz esparsa o suficiente para se garantir que o
nmero de elementos no nulos por linha seja pequeno.
Porm, h uma certa tendncia ao comprometimento da
eficincia de tempo computacional do sistema nos casos em
que haja necessidade de buscas mais elaboradas. Este o
caso por exemplo da funo-membro GetColumn() a qual
efetua busca de elementos de uma mesma coluna.
Para matrizes complexas desenvolveu-se uma verso
dessa classe conservando suas caractersticas bsicas de
manipulao. Esta verso, que foi intitulada
ComplexSparseMatrix, pode ser assim representada:

class ComplexSparseMatrix
{
public :
// construtor e destrutor
..............
// funes membro
vector operator*(vector&);
void GetColumn(int,vector&,int[],int&);
void GetRow(int,vector&,int[],int&);
vector SolveLower(vector&);
vector SolveTransLower(vector&);
ComplexSparseMatrix& Factorize(ComplexSparseMatrix&);
...............
};

Fig.3. Matriz Complexa Esparsa

III. IMPLEMENTAO DO MTODO SOLVECOCG()

O mtodo de Gradientes Conjugados Ortogonalmente
Conjugados foi proposto para solucionar sistemas lineares
do tipo Ax = b, em que A uma matriz complexa, no-
Hermitiana, porm simtrica[2].
Este mtodo pode ser representado pelo seguinte
algoritmo :

ALGORITMO COCG

incio
{Dado c - preciso desejada}
{inicializao}
escolha x
0
;
v
0
= b - Ax
0
;
p
0
= 0 ;

|
0
= 0;
w
0
= K
-1
v
0;
{K a matriz pr-condicionadora}
e
0
= (v
0
,w
0
);
{processo iterativo}
faa
p
j
= w
j
+ |
j
p
j;

u
j
= Ap
j;

j
= (u
j
,p
j
);
se
j = 0

ento pare;


seno
o
j
= e
j
/
j
;


x
j+1
= x
j
+ o
j
p
j
;


v
j+1
= v
j
+ o
j

j
;


se ( ||x
j+1
|| <=c)
ento pare;
seno
w
j+1
= K
-1
v
j+1
;


e
j+1
= (v
j+1
,w
j+1
);
|
j
= e
j+1
/ e
j
;
fim se;
fim se;
enquanto ||x
j+1
|| >=c;

Fig. 4. O Mtodo Gradientes Conjugados Ortogonalmente Conjugados

onde x indica o complexo conjugado de um vetor e (,)
indica o produto interno complexo padro entre dois
vetores.
Ressalta-se a utilizao da Fatorizao Incompleta de
Cholesky[5] como pr-condicionamento do sistema. Ou
seja,

K = TT
T
, (1)

em que T pode ser assim calculado:

t a t t t
ij ij ik jk jj
k
j
=
=

[ ] /
1
1
, j <= i-1 (2)
t a t
ii ii ik
k
j
2 2
1
1
=
=

[ ] (3)

A codificao do algoritmo referente Fig.4 em C++
apresentada a seguir.

void ComplexSparseMatrix ::
SolveCOCG (ComplexSparseMatrix& A, Vector& b)
{
ComplexSparseMatrix T(A.numrows,A.numcolumns);
// cria e inicializa com zero vetores com mesma
//dimenso do vetor b
Vector r(b.size,0), rb(b.size,0), x(b.size,0), p(b.size,0),
z(b.size,0), w(b.size,0), u(b.size,0), ub(b.size,0);
complex e, e_ant, mi, alpha, y, beta;

r = b - A*x;
z = (T.Factorize(A)).SolveLower(r);
w =T.SolveTransLower(z);
e = (conjugado(r)).prod(w);
do {
p = w + p*beta;
u = A*p;
ub = conjugado(u);
mi = ub.prod(p);
alpha = e / mi;
x += p*alpha;
r -= u*alpha;
rb = conjugado(r);
y = r*r;
if(abs(y) > 1.E-7)
{
z = T.SolveLower(r);
w = T.SolveTransLower(z);
e = rb.prod(w);
beta = e / e_ant;
}
} while(abs(y) > 1.E-7);
b = x;
}

Fig.5. Implementao em C++ do COCG

Alm de ser uma funo-membro da classe
ComplexSparseMatrix, esta uma funo que no possui
nenhum tipo de retorno (void). Neste sentido, ela pode ser
invocada por objetos desta classe atravs de nome
(SolveCOCG()) e do operador ponto (.). Dois parmetros
devem ser passados por referncia, sendo que o resultado
atribudo ao vetor independente. Assim, se A um objeto
da classe ComplexSparseMatrix e b um objeto de
Vector, a seguinte chamada vlida

A.SolveCOCG(A,b)

Em uma anlise do algoritmo e sua codificao,
verifica-se a quase total semelhana entre os mesmos, ou
seja, no h perda de legibilidade do algoritmo. Este fato se
deve s caractersticas da metodologia orientada por
objetos que permitem o uso do polimorfismo ( utilizao de
uma mesma interface para aplicaes distintas ) de
operadores e funes. Dessa forma, o operador ( * ) pde
ser definido para efetuar o produto escalar entre dois
vetores, r*r. Em outra situao, ele foi implementado para
efetuar o produto entre uma matriz esparsa A e o vetor p,
A*p. As funes que implementam este operador foram
assim desenvolvidas:

complex Vector :: operator * (Vector &c)
{
complex aux = 0;
for(int i=1;i<=c.size;++i)
if((vet[i] !=0) || (c.vet[i] !=0))
aux += *(vet+i)* (c.vet[i]);
return aux;
}

Vector ComplexSparseMatrix :: operator * (Vector &c)
{
Element *elem;// ponteiro para estrutura Element
Vector result(numrows,0);// inicializa com zeros o vetor de
// dimenso numrows ( no. de linhas da matriz A )
for(i = 1;i<=numrows;++i)
for(elem = elementRow[i];elem!=NULL;elem = elem->next)
{
result.vet[i] += elem->value *c.vet[elem->column];
if(elem->column != i)
result.vet[elem->column] += elem->value * c.vet[i];
}
return result;
}

Fig.6. Sobrecarga de operadores.

Pode ser verificado que no primeiro caso o operador *
pertence classe Vector e que retorna um complexo. No
segundo caso, ele pertence classe ComplexSparseMatrix
e retorna um vetor. Destaca-se que Element uma estrutura
do tipo[1] similar da Fig. 1, porm desenvolvida para
nmeros complexos. E, a nica semelhana entre estas
sobrecargas de operador o fato do operando da esquerda
ser passado implicitamente para as funes.
Constata-se tambm a utilizao dos mtodos
Factorize(), SolveLower(), SolveTransLower()
pertencentes esta ltima classe, como visto na Fig.3, e que
implementam a Fatorizao Incompleta de Cholesky.

IV. RESULTADOS COMPUTACIONAIS

A implementao dos algoritmos foi realizada utilizando
um mesmo compilador de tal forma a se obter uma
portabilidade do programa entre Workstations e micros PC.
Trata-se do compilador GNU C, C++(GCC), de domnio
pblico, e com verses para os dois ambientes.
Para validao das implementaes, vrios sistemas de
equaes geradas pela aplicao de Mtodo de Elementos
Finitos a problemas eletromagnticos tridimensionais foram
resolvidas. Como exemplo so mostrado a seguir trs casos,
para os quais utilizou-se o algoritmo COCG. As
caractersticas das matrizes podem ser assim apresentadas:

Tabela 1. Caractersticas das Matrizes

Dimenso No. elementos
no-nulos
Problema 1 328 7152
Problema 2 1201 16579
Problema 3 2325 51698

Para tais problemas observou-se o comportamento da
implementao SolveCOCG() apresentado como a seguir:


Fig. 7. Convergncia com fator de deslocamento =1

Observa-se atravs da Fig. 7 a convergncia dos trs
casos. Ressalta-se a utilizao da Norma Euclidiana para o
teste de convergncia. A preciso adotada c = 10
-8
.
Em uma anlise superficial, foi feita a comparao do
tempo computacional entre uma implementao j existente
em FORTRAN[6] e a apresentada neste artigo em C++.
Como a forma de armazenamento e manipulao dos
elementos das matrizes diferem de uma implementao para
outra, os resultados no puderam ser conclusivos.
Entretanto, pde-se notar tempos aproximadamente iguais
nos Prob. 1 e 2. No caso do Prob. 3, o C++ foi quase 50%
mais lento.
No C++, o tempo de CPU aumentado devido a vrios
fatores. Primeiro, deve-se considerar que durante a
execuo do programa inmeras mensagens so enviadas.
Outro aspecto a criao e destruio de objetos
temporrios, que requer a alocao e desalocao de blocos
de memria repetidas vezes.
Ressalta-se tambm que em FORTRAN o tipo Complex
bsico, o que no acontece em C++. Neste caso, trabalha-
se com uma biblioteca padro Complex.h, isto , este tipo
tratado como um objeto.

V. CONCLUSES

Sob o ponto de vista da legibilidade, observando a
Fig.5, nota-se claramente as etapas de soluo do problema
se comparando com o algoritmo apresentado na Fig.4. Este
fato facilita ao usurio utilizar a biblioteca de funes sem
se preocupar com os cdigos que a implementao oculta.
Em funo disso, garante-se a sua reusabilidade e facilidade
de manuteno, isto , os mtodos pertencentes a esta
biblioteca podem ser aplicados a outros algoritmos sem
qualquer tipo de perda
A forma de armazenamento utilizada, lista encadeada,
para representao de linhas mostrou-se eficiente. Isso
porque suas linhas e colunas so armazenadas em ordem
crescente, o que permite um acesso quase que direto aos
elementos. Contudo, quando se desejam pesquisas mais
especficas como citado na seo II, h um certo
comprometimento do tempo de busca.
Foi feita a validao das implementaes e apresentado
o caso COCG. Uma das questes que ainda persiste na
metodologia orientada por objetos a elevao do tempo
computacional. No presente trabalho, isto atribuido
principalmente criao e destruio de objetos
temporrios. Esta ocorrncia se mostrou influente no tempo
computacional medida em que o nmero de elementos no
nulos cresciam e por consequncia o nmero de operaes
tambm. No pior caso, o C++ chegou a ser 50% mais lento
que a implementao em FORTRAN.
No entanto, devido ao barateamento dos recursos
computacionais e levando-se em conta a legibilidade do
algoritmo, esta diferena pode ser tolerada.
A partir da implementao do algoritmo COCG, sendo
suas observaes cabveis s outras implementaes, pde-
se verificar toda a potencialidade do paradigma orientado
por objetos aplicados a sistemas de matrizes esparsas sejam
elas reais ou complexas.

VI. REFERNCIAS

[1] Buzzi-Ferraris,G."Scientific C++: Numerical Libraries the Object-
Oriented Way", Addison-Wesley, 1993.
[2] Van der Vorst, H.A., Melissen, J.B.M.,"A Petrov-Galerkin Type
Method for Solving Ax=b, where A is Symmetric Complex"IEEE
Trans. mag. MAG-26, pp.:706-708, 1990.
[3] Silva, E.J., Mesquita,R.C.,Saldanha,R.R,Palmeira,P.F.M."An Object-
Oriented Finite Element Program for Electromagnetic Field
Computation", IEEE Trans. Mag. Vol 30, No.5, pp:3618-3621 ,Sep.
1994
[4] Stroustrup, B."The Annoted C++ Reference Manual", Addison-
Wesley,1990
[5] D. W. Kershaw, The incomplete Cholesky-conjugate gradient method
for the iterative solution of linear equations, J. Comp. Phys, 26,43-
65 (1978)
[6] Mesquita, R. C. Clculo de Campos Eletomagnticos
Tridimensionais Utilizando Elementos Finitos: magnetosttica,
Quase-Esttica e aquecimento indutivo,UFSC, Florianpolis
[7 Winblad, A. L. Edward, J. D. King, D. R. Objected-Oriented
SoftwareAddison-Wesley,1990