ОБЪЕДИНЕННЫЙ   ИНСТИТУТ   ЯДЕРНЫХ   ИССЛЕДОВАНИЙ
lit
  Библиотека   программ   JINRLIB eng

DirectSolverN (N=2,3,4,5,6) - решение системы линейных уравнений
общего вида прямым методом (по правилу Крамера)

F099

Автор: А.П.Сапожников Язык: Фортран

Подпрограмма-функция DirectSolverN (N=2,3,4,5,6) выполняет решение системы линейных уравнений A*X = B общего вида прямым методом, т.е. по правилу Крамера:
X(i)=DX(i)/D

Общеизвестно, что для решения системы порядка N методами типа Гаусса-Жордана требуется O(N3) операций.
В то же время прямое использование правила Крамера требует вычисления N+1 определителя N порядка, т.е. (N+1)! операций. Однако при малых N обе оценки вполне соизмеримы, а при N < 4 просто-напросто (N+1)! < N3.
Более того, экспериментально установлено, что вплоть до 6 порядка система решается прямым методом гораздо быстрее (при N=6 - в 2 раза).
Поэтому мы предоставляем всем желающим семейство программ

DirectSolverN(A,B,X) (N=2,3,4,5,6)
для решения систем линейных уравнений A*X=B, где
A - матрица системы NxN;
B - массив длиной N;
X - массив длиной N, куда будет записано решение.

Все программы оформлены как функции, возвращающие детерминант матрицы системы или 0, если система несовместна.

Особенностью этого семейства программ является то, что они генерировались автоматически с помощью специально построенной для этой цели рекурсивной процедуры DeterGen, написанной на языке Паскаль.

В самом деле - кому захочется вручную "расписывать" определитель 6 порядка! Да и ошибиться тут нетрудно. Текст упомянутой процедуры публикуется ниже, мы полагаем, что он представляет самостоятельную ценность.

Замечание:

В связи с ограничениями фортранного компилятора максимальное значение размерности системы N для Microsoft Fortran 5.00 равно 5.

Пример:
       Implicit Real*8 (a-h,o-z)
       dimension a(4,4),b(4),x(4)
       do i=1,4
         b(i)=0.0d0
         do j=1,4
           a(i,j)=1.0d0/(i+j)    ! Hilbert matrix
           b(i)=b(i)+a(i,j)      ! solution = all 1
         enddo
       enddo
       d=DirectSolver4(a,b,x)
       write(*,*) ' Determinant for Hilbert matrix = ',d
Результат:
       Determinant for Hilbert matrix =   2.362055933475061E-009
Текст процедуры DeterGen:
       Procedure DeterGen(N:integer; Lines:TStrings);
       Type Matrix=array[1..9,1..9] of string[6];
       var i,j,k,N0:integer;
           a:Matrix; Indent:string;
       Function Dig(d:integer):char;
       begin Result:=Chr(d+Ord('0')); end;
 
       Procedure Determ(n:integer; a:Matrix; Lines:TStrings);
       var s,s1,sg:string; i,j,k:integer;
           b:Matrix;
       begin  sg:=''; s:='D'+Dig(n);
         if (n=2) and (N0=2) then begin Lines.Add(Indent+'D2 = '+a[1][1]+'*'+a[2][2]+'-'
		+a[1][2]+'*'+a[2][1]); Exit; end;
         if n=3 then
         begin  s1:=Indent+'             '; s1[6]:='&';
           Lines.Add(Indent+'D3 = '+a[1][1]+'*('+a[2][2]+'*'+a[3][3]+'-'+a[3][2]+'*'
		+a[2][3]+')-'+a[1][2]+'*('+a[2][1]+'*'+a[3][3]+'-');
           Lines.Add(s1+a[2][3]+'*'+a[3][1]+')+'+a[1][3]+'*('+a[2][1]+'*'+a[3][2]+'-'
		+a[2][2]+'*'+a[3][1]+')');
           Exit;
         end;
         for j:=1 to n do
         begin
           for i:=1 to n-1 do for k:=1 to n   do b[i][k]:=a[i+1][k];
           for i:=1 to n-1 do for k:=j to n-1 do b[i][k]:=b[i][k+1];
           Determ(n-1,b,Lines);
           s1:=Indent+s+' = '; if j<>1 then s1:=s1+s+sg;
           Lines.Add(s1+a[1][j]+' * D'+Dig(n-1));
           if sg=' - ' then sg:=' + ' else sg:=' - ';
         end;
       end;
       begin  N0:=N; Indent:='      ';
         Lines.Clear;  if n>9 then n:=9;
         Lines.Add('      Function DirectSolver'+Dig(n)+'(A,B,X)  ! for Linear System
		A*X=B');
         Lines.Add('C *** Generated by "DeterGen" procedure  ***');
         Lines.Add('      Implicit Real*8 (A-H,O-Z)');
         Lines.Add('      Dimension A('+Dig(n)+','+Dig(n)+')  ! system Matrix');
         Lines.Add('      Dimension B('+Dig(n)+')    ! system Right Part');
         Lines.Add('      Dimension X('+Dig(n)+')    ! system Solution');
         for i:=1 to n do  for j:=1 to n do  a[i][j]:='A('+Dig(i)+','+Dig(j)+')';
         Determ(n,a,Lines);
         Lines.Add('      D = D'+Dig(n));
         Lines.Add('      if(D.ne.0) then');
         for k:=1 to n do
         begin Indent:='        ';
           for i:=1 to n do a[i][k]:='B('+Dig(i)+')';
           Determ(n,a,Lines);
           Lines.Add(Indent+'X('+Dig(k)+') = D'+Dig(n)+' / D');
           for i:=1 to n do a[i][k]:='A('+Dig(i)+','+Dig(k)+')';
         end;
         Lines.Add('      endif');
         Lines.Add('      DirectSolver'+Dig(n)+'=D');
         Lines.Add('      return');
         Lines.Add('      End');
       end;


home up e-mail