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

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

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

помогите решить задачку

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
Проверка
Антиспам проверка
Image CAPTCHA
...