Алгоритм Краута (нижне-верхняя (LU) декомпозиция матрицы)
Страница 2. Программа LU-декомпозиции


Программа LU-декомпозиции

Программа самой декомпозиции и некоторых ее приложений приводится ниже.

/* 
LU-декомпозиция в соответствии с алгоритмом Краута.
Описание:
int LU_decompos(double **a,int n,int *indx,int *d,double *vv);
параметры:
a - исходная матрица (n x n) на входе;
n - размер матрицы;
indx - массив целых чисел (размера n) для запоминания перемещений;
d - на выходе, содержит +1 или -1 для четного или нечетного числа перемещений.
vv - временный массив (size n).
Результат:
0 - некорректная входная матрица (непригодна для декомпозиции),
1 - положительный результат.

Обратная замена, использующая LU-декомпозицию матрицы.
Описание:
void LU_backsub(double **a,int n,int *indx,double *b);
Параметры:
a - матрица, разложенная по Крауту;
n - размер матрицы;
indx - порядок перемещения, полученный алгоритмом декомпозиции;
b - вектор (размера n).
Примечание: a и indx не изменяются в этой функции и могут быть использованы повторно.

Инвертирование матрицы с использованием LU-разложенной матрицы.
Описание:
void LU_invert(double **a,int n,int *indx,double **inv,double *col);
Параметры:
a - матрица, разложенная по Крауту;
n - размер матрицы;
indx - порядок перестановки, полученный алгоритмом декомпозиции;
inv - матрица назначения;
col - временный массив (размера n).

Получение матрицы, полученной с использованием LU-разложенной матрицы
Описание:
double LU_determ(double **a,int n,int *indx,int *d);
Параметры:
a - матрица, разложенная по Крауту;
n - размер матрицы;
indx - порядок перемещения, полученный алгоритмом декомпозиции;
d - знак равенства (+1 или -1) полученный при декомпозиции.
Результат:
определяющее значение.
*/

/* Для fabs(); включение может быть перемещено, если fabs() реализована как inline */
#include <math.h>
/* "small number" для избежания переполнения в некоторых случаях */
#define TINY 1.e-30

/* декомпозиция */
int LU_decompos(double **a, int n, int *indx, int *d, double *vv) {
register int i,imax,j,k;
double big,sum,temp;
for(i=0;i<n;i++) {
big=0.;
for(j=0;j<n;j++) if((temp=fabs(a[i][j]))>big) big=temp;
if(big==0.) return(0);
vv[i]=big;
}
/* главный цикл алгоритма Краута */
for(j=0;j<n;j++) {
/* это часть a) алгоритма, исключая i==j */
for(i=0;i<j;i++) {
sum=a[i][j];
for(k=0;k<i;k++) sum-=a[i][k]*a[k][j];
a[i][j]=sum;
}
/* инициализация для поиска наибольшего элемента */
big=0.; imax=j;
for(i=j;i<n;i++) {
sum=a[i][j];
for(k=0;k<j;k++) sum-=a[i][k]*a[k][j];
a[i][j]=sum;
if((temp=vv[i]*fabs(sum))>=big) {big=temp;imax=i;}
}
/* обмен строк, если нужен, смена равенства и размера множителя */
if(imax!=j) {
for(k=0;k<n;k++) {
temp=a[imax][k]; a[imax][k]=a[j][k]; a[j][k]=temp;
}
*d=-(*d); vv[imax]=vv[j];
}
/* сохраняем индекс */
indx[j]=imax;
if(a[j][j]==0.) a[j][j]=TINY;
if(j<n-1) {
temp=1./a[j][j];
for(i=j+1;i<n;i++) a[i][j]*=temp;
}
}
return(1);
}

/* обратная замена */
void LU_backsub(double **a,int n,int *indx,double *b) {
register int i,j,ip,ii=-1;
double sum;
/* первый шаг обратной замены */
for(i=0;i<n;i++) {
ip=indx[i];
sum=b[ip];b[ip]=b[i];
if(ii>=0) for(j=ii;j<i;j++) sum-=a[i][j]*b[j];
else if(sum) ii=i;/* получен ненулевой элемент */
b[i]=sum;
}
/* второй шаг */
for(i=n-1;i>=0;i--) {
sum=b[i];
for(j=i+1;j<n;j++) sum-=a[i][j]*b[j];
b[i]=sum/a[i][i];
}
}

/* инвертирование матрицы */
void LU_invert(double **a,int n,int *indx,double **inv,double *col) {
register int i,j;
for(j=0;j<n;j++) {
for(i=0;i<n;i++) col[i]=0.;
col[j]=1.;
LU_backsub(a,n,indx,col);
for(i=0;i<n;i++) inv[i][j]=col[i];
}
}

/* определяющее вычисление*/
double LU_determ(double **a,int n,int *indx,int *d) {
register int j;
double res=(double)(*d);
for(j=0;j<n;j++) res*=a[j][j];
return(res);
}
 
« Предыдущая статья   Следующая статья »