Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Решение СЛАУ, вычисление обратных матриц и определителей с использованием LU-разложения

01.01.2007
unit LU_Utils;
 
interface
uses
Classes;
type
 
TDblArr = array of Double;
 
TIntArr = array of Integer;
 
TDblMatr = array of array of Double;
 
procedure
CopyMatr(Src, Dest: TDblMatr);
 
//исходная матрица разрушается, при необходимости нужно сделать копию
procedure
LUDecomp(Matr: TDblMatr; Indx: TIntArr; var DSign: Integer);
procedure
LUBackSubst(Matr: TDblMatr; Indx: TIntArr; Reslt: TDblArr);
 
//решение системы линейных уравнений. XY на входе - правые части,
//на выходе - вектор решений
//LU-разложение матрицы может использоваться многократно с
//разными правыми частями (при модификации кода)
procedure
SLAUSolver(Matr: TDblMatr; XY: TDblArr);
 
//исходная матрица заменяется обратной
procedure
MatrInverse(Matr: TDblMatr);
 
//исходная матрица сохраняется
function Determinant(Matr: TDblMatr): Double;
 
implementation
uses
SysUtils;
 
procedure
CopyMatr(Src, Dest: TDblMatr);
var
  n
, i: Integer;
begin
  n
:= Length(Src);
 
for i := 0 to n - 1 do
   
Move(Src[i, 0], Dest[i, 0], n * SizeOf(Double));
end;
 
procedure
LUDecomp(Matr: TDblMatr; Indx: TIntArr; var DSign: Integer);
const
 
Tiny = 1.0E-40;
var
  n
, k, j, imax, i: Integer;
  sum
, dum, big: Double;
  VV
: TDblArr;
 
DumPtr: Pointer;
begin
  n
:= Length(Matr);
 
SetLength(VV, n);
 
DSign := 1;
 
 
for i := 0 to n - 1 do begin
    big
:= 0;
   
for j := 0 to n - 1 do
     
if (abs(Matr[i, j]) > big) then
        big
:= Abs(Matr[i, j]);
   
if (big = 0.0) then
     
raise Exception.Create('Stopped. Matrix is singular!!!');
    VV
[i] := 1 / big;
 
end;
 
 
for j := 0 to n - 1 do begin
   
for i := 0 to j - 1 do begin
      sum
:= Matr[i, j];
     
for k := 0 to i - 1 do
        sum
:= sum - Matr[i, k] * Matr[k, j];
     
Matr[i, j] := sum;
   
end;
 
    big
:= 0;
   
for i := j to n - 1 do begin
      sum
:= Matr[i, j];
     
for k := 0 to j - 1 do
        sum
:= sum - Matr[i, k] * Matr[k, j];
     
Matr[i, j] := sum;
      dum
:= VV[i] * abs(sum);
     
if (dum > big) then begin
        big
:= dum;
        imax
:= i;
     
end;
   
end;
 
   
if (j <> imax) then begin
     
DumPtr := Pointer(Matr[imax]);
     
Pointer(Matr[imax]) := Pointer(Matr[j]);
     
Pointer(Matr[j]) := DumPtr;
     
DSign := -DSign;
      VV
[imax] := VV[j]
   
end;
 
   
Indx[j] := imax;
   
if (Matr[j, j] = 0) then
     
Matr[j, j] := Tiny;
   
if (j <> n - 1) then begin
      dum
:= 1 / Matr[j, j];
     
for i := j + 1 to n - 1 do
       
Matr[i, j] := Matr[i, j] * dum;
   
end;
 
end;
end;
 
procedure
LUBackSubst(Matr: TDblMatr; Indx: TIntArr; Reslt: TDblArr);
var
  n
, j, ip, ii, i: Integer;
  sum
: Double;
begin
  n
:= Length(Matr);
  ii
:= -1;
 
 
for i := 0 to n - 1 do begin
    ip
:= Indx[i];
    sum
:= Reslt[ip];
   
Reslt[ip] := Reslt[i];
   
if (ii <> -1) then
     
for j := ii to i - 1 do
        sum
:= sum - Matr[i, j] * Reslt[j]
   
else
     
if (sum <> 0.0) then
        ii
:= i;
   
Reslt[i] := sum;
 
end;
 
 
for i := n - 1 downto 0 do begin
    sum
:= Reslt[i];
   
if (i < n - 1) then
     
for j := i + 1 to n - 1 do
        sum
:= sum - Matr[i, j] * Reslt[j];
   
Reslt[i] := sum / Matr[i, i];
 
end
end;
 
procedure
SLAUSolver(Matr: TDblMatr; XY: TDblArr);
var
 
Indx: TIntArr;
 
DSign: Integer;
begin
 
SetLength(Indx, Length(XY));
 
LUDecomp(Matr, Indx, DSign);
 
LUBackSubst(Matr, Indx, XY);
end;
 
procedure
MatrInverse(Matr: TDblMatr);
var
  n
, i, j: Integer;
 
Indx: TIntArr;
 
Col: TDblArr;
 
DSign: Integer;
 
Temp: TDblMatr;
begin
  n
:= Length(Matr);
 
SetLength(Indx, n);
 
SetLength(Col, n);
 
SetLength(Temp, n, n);
 
LUDecomp(Matr, Indx, DSign);
 
for j := 0 to n - 1 do begin
   
for i := 0 to n - 1 do
     
Col[i] := 0;
   
Col[j] := 1;
   
LUBackSubst(Matr, Indx, Col);
   
for i := 0 to n - 1 do
     
Temp[i, j] := Col[i];
 
end;
 
CopyMatr(Temp, Matr);
 
Temp := nil;
end;
 
function Determinant(Matr: TDblMatr): Double;
var
  n
, j: Integer;
 
Indx: TIntArr;
 
DSign: Integer;
 
Temp: TDblMatr;
begin
  n
:= Length(Matr);
 
SetLength(Indx, n);
 
SetLength(Temp, n, n);
 
CopyMatr(Matr, Temp);
 
LUDecomp(Temp, Indx, DSign);
 
Result := DSign;
 
for j := 0 to n - 1 do
   
Result := Result * Temp[j, j];
end;
 
end.
unit Unit1;
 
interface
 
uses
 
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 
Dialogs, LU_Utils, StdCtrls;
 
type
  TForm1
= class(TForm)
    Memo1
: TMemo;
    Button1
: TButton;
    Button2
: TButton;
    Button3
: TButton;
    procedure Button1Click
(Sender: TObject);
    procedure Button2Click
(Sender: TObject);
    procedure Button3Click
(Sender: TObject);
 
private
   
{ Private declarations }
 
public
   
{ Public declarations }
 
end;
 
var
  Form1
: TForm1;
 
implementation
 
{$R *.dfm}
 
function ShowArr(Arr: TDblArr): string;
var
  i
: Integer;
begin
 
Result := '';
 
for i := 0 to Length(Arr) - 1 do
   
Result := Result + FormatFloat('0.0000', Arr[i]) + '  ';
end;
 
procedure
ShowMatr(Matr: TDblMatr; Strings: TStrings);
var
  n
, i, j: Integer;
  s
: string;
begin
  n
:= Length(Matr);
 
for i := 0 to n - 1 do begin
    s
:= '';
   
for j := 0 to n - 1 do
      s
:= s + FormatFloat('0.0000', Matr[i, j]) + '  ';
   
Strings.Add(s);
 
end;
end;
 
procedure TForm1
.Button1Click(Sender: TObject);
var
  M
:TDblMatr;
  B
:TDblArr;
begin
SetLength(M,3,3);
SetLength(B,3);
  M
[0, 0] := 0.5;
  M
[0, 1] := 2;
  M
[0, 2] := -1;
  M
[1, 0] := -15;
  M
[1, 1] := -0.1;
  M
[1, 2] := 3.2;
  M
[2, 0] := 0.7;
  M
[2, 1] := 4.1;
  M
[2, 2] := -0.2;
  B
[0] := 11.4;
  B
[1] := -196.02;
  B
[2] := 10.22;
  Memo1
.Clear;
 
ShowMatr(M, Memo1.Lines);
  Memo1
.Lines.Add('');
 
SLAUSolver(M, B);
 
ShowMatr(M, Memo1.Lines);
  Memo1
.Lines.Add('');
  Memo1
.Lines.Add(ShowArr(B));
end;
 
procedure TForm1
.Button2Click(Sender: TObject);
var
  M
:TDblMatr;
begin
 
SetLength(M,3,3);
  M
[0, 0] := 1;
  M
[0, 1] := 1;
  M
[0, 2] := 1;
  M
[1, 0] := 1;
  M
[1, 1] := 2;
  M
[1, 2] := 1;
  M
[2, 0] := 1;
  M
[2, 1] := 1;
  M
[2, 2] := 3;
  Memo1
.Clear;
 
ShowMatr(M, Memo1.Lines);
  Memo1
.Lines.Add('');
 
MatrInverse(M);
 
ShowMatr(M, Memo1.Lines);
end;
 
procedure TForm1
.Button3Click(Sender: TObject);
var
  M
:TDblMatr;
begin
 
SetLength(M,3,3);
  M
[0, 0] := 1;
  M
[0, 1] := 0;
  M
[0, 2] := 1;
  M
[1, 0] := 0;
  M
[1, 1] := 2;
  M
[1, 2] := 0;
  M
[2, 0] := 1;
  M
[2, 1] := 0;
  M
[2, 2] := 3;
  Memo1
.Clear;
 
ShowMatr(M, Memo1.Lines);
  Memo1
.Lines.Add('');
  Memo1
.Lines.Add(FormatFloat('0.0000', Determinant(M)));
end;
 
end.

Автор: MBo