Модуль реализации матричных вычислений для массивов больших размеров
WEB-сайт: http://delphikingdom.com
В этом модуле «осели» все операции с матрицами и векторами, которые я использовал для работы. Но есть алгоритмы, которые многие, наверняка, увидят впервые: Divide – алгоритм прямого деления, MSqrt – квадратный корень, MAbs – абсолютная величина. Поскольку модуль содержит все, от элементарных операций до матричных, разобраться будет несложно:
Например, решение системы ЛУ (консольное приложение)
var
N : Integer;
A : Matrix;
b, x : Vector;
begin
N := . . .;
A.Init( N, N );
b.Init( N );
x.Init( N ); // или x.Init( B ); или x.InitRow( A );
. . .
{ формирование A и b }
. . .
x.Divide( b, A );
x.Print;
. . .
end.
Некоторые алгоритмы требуют пояснения, например:
Matrix.E( i, j : LongWord ) или Vector.E( i : Integer ) : RealPtr
(RealPtr = ^Real) функция для вычисления адреса элемента матрицы/вектора. Перешла из ДОС когда в модуле использовался алгоритм управления виртуальной памятью для больших размерностей.
Matrix.Multiple( X, Y : Vector )
Результатом, которого является произведение вектора X на транспонированный вектор Y - матрица ранга 1.
Matrix.Invert( A : Matrix )
– если A[N,M], и N <> M то результат – матрица размера [M,N] – псевдообратная = A+.
Matrix.Addition( A : Matrix; B : Real )
– добавление числа в главную диагональ.
Matrix.Diag( r : Real )
– присваивание значения главной диагонали.
unit HMatrixW;
{
Матричная алгебра 1996-1998,
HNV 1996 .
}
interface
uses
SysUtils,
HNVString,
Math,
// VHeapLow,
Windows,
Dialogs;
const
MaxRow = 214748364; { Максимальное к-во элементов в векторе }
NumbSpline : LongWord = 1;
Indicator : Word = $118F;
Condition : Boolean = True;
InitCount : Integer = 0;
InitSize : Integer = 0;
var
NIteration : LongWord; { Число итераций процесса }
Temp : Real;
MathEps : Real; { Относительная машинная точность }
SqrtEps : Real; { и корень из нее }
Eps : Real;
MinEps : Real;
type
VirtualPtr =
record
Ptr : Pointer;
Size : LongWord;
end;
RealPtr =
^Real;
ArrayType =
array[ 1..1 ] of real;
ArrayPtr =
^ArrayType;
VectorPrim = { Вектор }
object
VAddr : VirtualPtr; { Виртуальный адрес (tail of DOS) }
FInit : Word; { Флаг инициализации (tail of DOS) }
n : LongWord; { Размерность вектора }
function Addr : ArrayPtr; { Адрес начала вектора }
function E( I : LongWord ) : RealPtr; { Адрес элемента }
{ _ }
procedure Copy( X : VectorPrim ); { = X }
{ _ _ }
procedure Substrac( X, Y : VectorPrim ); { X - Y }
{ _ _ }
procedure Addition( X, Y : VectorPrim ); { X + Y }
procedure Init( Size : LongWord ); overload;
procedure Init( X : VectorPrim ); overload;
procedure Free;
function Summ : Real; { Сумма элементов вектора }
function SummSqr : Real; { Сумма квадратов элементов }
procedure Sort( a1 : VectorPrim ); { Сортировка вектора по возрастанию }
procedure SortAbs( a1 : VectorPrim ); { -<>- по модулю }
procedure SortBy( a1 : VectorPrim ); { Сортировка вектора по возрастанию }
procedure Clear; { Очистить нулями }
procedure Print;
procedure PrintF( M : Byte );
procedure ScMultiple( X : Real; y : VectorPrim ); { Умножение на скаляр }
procedure ScDivide( X : Real; y : VectorPrim ); { Деление на скаляр }
procedure SetAll( X : Real ); { Все эл-ты = X }
procedure Multiple( x, y : VectorPrim ); overload; { поэлементное умножение }
end;
MatrixPrimArray =
array[ 1..1 ] of VectorPrim;
MatrixVPrimPtr =
^MatrixPrimArray;
Matrix = { Матрица }
object
VAddr : VirtualPtr; { Виртуальный адрес массива векторов
матрица хранится по строкам. Максималь-
ная размерность MaxRow * MaxRow (tail of DOS)}
FInit : Word; { Флаг инициализации (tail of DOS) }
n, m : LongWord; { Размерности матрицы }
function Addr : MatrixVPrimPtr; { Адрес массива векторов-строк }
function E( i, j : LongWord ) : RealPtr; { Адрес элемента }
procedure Copy( B : Matrix ); { = B }
procedure Multiple( A, B : Matrix ); overload; { A * B }
procedure Multiple( A, B : VectorPrim ); overload;
procedure Substrac( A, B : Matrix ); { A - B }
procedure Addition( A, B : Matrix ); overload; { A + B }
procedure Addition( A : Matrix; B : VectorPrim ); overload;
procedure Addition( A : Matrix; B : Real ); overload;
procedure Divide( Bx, Ax : Matrix ); { B / A }
procedure Diag( B : VectorPrim ); overload; { Diag = b }
procedure Diag( r : Real ); overload; { Diag(*) = r }
procedure Col( i : LongWord; B : VectorPrim ); overload; { Столбец = b }
procedure Row( i : LongWord; B : VectorPrim ); overload; { Строка = b }
procedure Col( i : LongWord; r : Real ); overload; { Столбец = r }
procedure Row( i : LongWord; r : Real ); overload; { Строка = r }
procedure Clear; { Обнуление эл-тов }
procedure Invert( A : Matrix ); { Вычисление обратной/псевдообратной матрицы }
procedure Print;
procedure PrintF( M2 : Byte ); { M2 - к-во знач. цифр }
procedure ScMultiple( X : Real; Y : Matrix ); { умножение на скаляр }
procedure Trans( A : Matrix ); { Транспонирование }
procedure MSqrt( AX : Matrix ); { Вычисление корня для }
{ положительно-определенной матрицы }
procedure MAbs( AX : Matrix ); { Матричная функция ABS }
function Cond : Real; { числo обусловленности (1-Ok)}
function Norm : Real; { Норма матрицы }
function Alpha : Real; { Параметр регуляризации }
procedure Init( Size1, Size2 : LongWord ); overload; { Размещение матрицы }
procedure Init( A : Matrix ); overload;
procedure InitTrans( A : Matrix );
procedure InitSqr( A : Matrix );
procedure ReadFromFile( FN : string ); { Читать из файла TXT,
Init не требуется }
procedure MSqr( A : Matrix ); { = Trans( A ) * A }
procedure Simmetry( A : Matrix ); { = ( Trans( A ) + A ) / 2 }
function Asimm : Real; { Ассимметрия матрицы }
function Difference( A : Matrix ) : Real;
procedure Free; { Освобождение памяти }
end;
Vector =
object( VectorPrim )
procedure Divide( x : Vector; AB : Matrix ); overload; { =x / AB }
procedure Divide( x, y : Vector ); overload;
procedure Multiple( A : Matrix; x : Vector ); overload; { =A * x }
procedure Diag( A : Matrix ); { =Диаголаль }
procedure Col( i : LongWord; A : Matrix ); { =Столбец }
procedure Row( i : LongWord; A : Matrix ); { =Строка }
function Max : Real; { Максимальный элемент }
function Min : Real; { Минимальный элемент }
procedure Abs( x : Vector ); { Абсолютная величина }
function MinIndex : LongWord; { Индекс мин.эл-та }
function MaxIndex : LongWord; { Индекс макс. эл-та }
function Poly( x : Real ) : Real; { Полином x }
procedure IntPower( x : Vector; P : Integer ); { Целая степенть(поэлементно) }
procedure SubVector( x : Vector; From, Count : LongWord );
procedure InitRow( A : Matrix ); overload;
procedure InitRow( i : Integer; A : Matrix ); overload;
procedure InitCol( A : Matrix ); overload;
procedure InitCol( i : Integer; A : Matrix ); overload;
procedure FillBodyTo( XMax : Real );
procedure FillBody;
function Difference( x : Vector ) : Real;
procedure TableDiff( x, y : Vector ); // Две программы из
procedure Smoothe( y : Vector ); // Фортран-пакета(старые)
end;
SplineCoeffType =
record
NPoint : LongWord;
h, d, bb, d1, dg, d2 : Vector;
end;
SplineCoeffPtr =
^SplineCoeffType;
Spline = { Кубические сплайны }
object
VAddr : VirtualPtr;
function Addr : SplineCoeffPtr;
procedure Init( X, Y : Vector );
function F( X : Real ) : Real; { Значение сплайна в точке X }
function Integral( A, B : Real ) : Real; overload; { Интеграл от А до В }
function Integral : Real; overload; { Интеграл }
function FMin( A, B : Real ) : Real;
function FMax( A, B : Real ) : Real;
function ZeroIn( A, B : Real ) : Real;
function DF( X : Real ) : Real; { Значение первой производной }
procedure Free;
private
function Integr( A, B : Real ) : Real; { Интеграл от А до В }
end;
PolyApprox = { Аппроксимация полиномом }
object
Coeff : Vector;
dCoeff : Vector;
PlanM : Matrix;
procedure Init( xt, yt : Vector; NP : Integer );
function PX( xr : Real ) : Real;
function DPX( xr : Real ) : Real;
procedure Free;
private
XMin, XMax : Real;
end;
Eigen = { Собственные значения ( для симметричных матриц ) }
object
private
function F( Alpha : Real ) : Real;
public
Values : Vector;
Vectors : Matrix;
AbsValues : Vector;
Cond : Real;
D, R, P : Matrix; { D, R и P - факторы : D = R * R; A = D + R + P; }
Gamma : Matrix; { Матрица ошибок извлеч. из A }
procedure Init( A : Matrix );
procedure Free;
end;
{*--------------------------------------------------------------------*}
implementation
uses
HMinZero; // одномерный поиск
procedure Error( E : Word );
begin
ShowMessage( 'Internal Erorr : ' + IntToStr( E ) );
Halt( E );
end;
procedure GetMem( var P : Pointer; Size : Integer ); { (tail of DOS) }
begin
Inc( InitSize, Size );
Inc( InitCount );
System.GetMem( P, Size );
end;
procedure FreeMem( P : Pointer; Size : Integer ); { (tail of DOS) }
begin
Dec( InitSize, Size );
Dec( InitCount );
System.FreeMem( P, Size );
end;
procedure Vector.TableDiff( x, y : Vector );
{
C SUBROUTINE DDGT3
C
C PURPOSE
C TO COMPUTE A VECTOR OF DERIVATIVE VALUES GIVEN VECTORS OF
C ARGUMENT VALUES AND CORRESPONDING FUNCTION VALUES.
C
C USAGE
C CALL DDGT3(X,Y,Z,NDIM,IER)
C
C DESCRIPTION OF PARAMETERS
C X - GIVEN VECTOR OF DOUBLE PRECISION ARGUMENT VALUES
C (DIMENSION NDIM)
C Y - GIVEN VECTOR OF DOUBLE PRECISION FUNCTION VALUES
C CORRESPONDING TO X (DIMENSION NDIM)
C Z - RESULTING VECTOR OF DOUBLE PRECISION DERIVATIVE
C VALUES (DIMENSION NDIM)
C NDIM - DIMENSION OF VECTORS X,Y AND Z
C IER - RESULTING ERROR PARAMETER
C IER = -1 - NDIM IS LESS THAN 3
C IER = 0 - NO ERROR
C IER POSITIVE - X(IER) = X(IER-1) OR X(IER) =
C X(IER-2)
C
C REMARKS
C (1) IF IER = -1,2,3, THEN THERE IS NO COMPUTATION.
C (2) IF IER = 4,...,N, THEN THE DERIVATIVE VALUES Z(1)
C ,..., Z(IER-1) HAVE BEEN COMPUTED.
C (3) Z CAN HAVE THE SAME STORAGE ALLOCATION AS X OR Y. IF
C X OR Y IS DISTINCT FROM Z, THEN IT IS NOT DESTROYED.
C
C SUBROUTINES AND FUNCTION SUBPROGRAMS REQUIRED
C NONE
C
C METHOD
C EXCEPT AT THE ENDPOINTS X(1) AND X(NDIM), Z(I) IS THE
C DERIVATIVE AT X(I) OF THE LAGRANGIAN INTERPOLATION
C POLYNOMIAL OF DEGREE 2 RELEVANT TO THE 3 SUCCESSIVE POINTS
C (X(I+K),Y(I+K)) K = -1,0,1. (SEE HILDEBRAND, F.B.,
C INTRODUCTION TO NUMERICAL ANALYSIS, MC GRAW-HILL, NEW YORK/
C TORONTO/LONDON, 1956, PP. 64-68.)
C
C ..................................................................
C
SUBROUTINE DDGT3(X,Y,Z,NDIM,IER)}
var
DY1, DY2, DY3, A, B : Real;
i : Integer;
begin
{ TEST OF DIMENSION AND ERROR EXIT IN CASE NDIM IS LESS THAN 3}
if x.n <> y.n then
Error( 8001 );
{ PREPARE DIFFERENTIATION LOOP}
A := X.e( 1 )^;
B := Y.e( 1 )^;
I := 2;
DY2 := X.e( 2 )^ - A;
if DY2 = 0 then
Error( 8002 );
DY2 := ( Y.e( 2 )^ - B ) / DY2;
{ START DIFFERENTIATION LOOP}
for I := 3 to x.n do
begin
A := X.e( I )^ - A;
if A = 0 then
Error( 8002 );
A := ( Y.e( I )^ - B ) / A;
B := X.e( I )^ - X.e( I - 1 )^;
if B = 0 then
Error( 8002 );
DY1 := DY2;
DY2 := ( Y.e( I )^ - Y.e( I - 1 )^ ) / B;
DY3 := A;
A := X.e( I - 1 )^;
B := Y.e( I - 1 )^;
if ( I - 3 ) <= 0 then
e( 1 )^ := DY1 + DY3 - DY2;
e( I - 1 )^ := DY1 + DY2 - DY3;
end;
e( n )^ := DY2 + DY3 - DY1;
end;
procedure Vector.Smoothe( y : Vector );
{
C SUBROUTINE DSE15
C
C PURPOSE
C TO COMPUTE A VECTOR OF SMOOTHED FUNCTION VALUES GIVEN A
C VECTOR OF FUNCTION VALUES WHOSE ENTRIES CORRESPOND TO
C EQUIDISTANTLY SPACED ARGUMENT VALUES.
C
C USAGE
C CALL DSE15(Y,Z,NDIM,IER)
C
C DESCRIPTION OF PARAMETERS
C Y - GIVEN VECTOR OF DOUBLE PRECISION FUNCTION VALUES
C (DIMENSION NDIM)
C Z - RESULTING VECTOR OF DOUBLE PRECISION SMOOTHED
C FUNCTION VALUES (DIMENSION NDIM)
C NDIM - DIMENSION OF VECTORS Y AND Z
C IER - RESULTING ERROR PARAMETER
C IER = -1 - NDIM IS LESS THAN 5
C IER = 0 - NO ERROR
C
C REMARKS
C (1) IF IER=-1 THERE HAS BEEN NO COMPUTATION.
C (2) Z CAN HAVE THE SAME STORAGE ALLOCATION AS Y. IF Y IS
C DISTINCT FROM Z, THEN IT IS NOT DESTROYED.
C
C SUBROUTINE AND FUNCTION SUBPROGRAMS REQUIRED
C NONE
C
C METHOD
C IF X IS THE (SUPPRESSED) VECTOR OF ARGUMENT VALUES, THEN
C EXCEPT AT THE POINTS X(1),X(2),X(NDIM-1) AND X(NDIM), EACH
C SMOOTHED VALUE Z(I) IS OBTAINED BY EVALUATING AT X(I) THE
C LEAST-SQUARES POLYNOMIAL OF DEGREE 1 RELEVANT TO THE 5
C SUCCESSIVE POINTS (X(I+K),Y(I+K)) K = -2,-1,...,2. (SEE
C HILDEBRAND, F.B., INTRODUCTION TO NUMERICAL ANALYSIS,
C MC GRAW-HILL, NEW YORK/TORONTO/LONDON, 1956, PP. 295-302.)
C
C ..................................................................
C
SUBROUTINE DSE15(Y,Z,NDIM,IER)
}
var
A, B, C : Real;
I, NDIM : Integer;
begin
{ TEST OF DIMENSION }
NDIM := y.n;
if ( NDIM < 5 ) then
Error( 8004 );
{ PREPARE LOOP }
A := Y.e( 1 )^ + Y.e( 1 )^;
C := Y.e( 2 )^ + Y.e( 2 )^;
B := 0.2 * ( A + Y.e( 1 )^ + C + Y.e( 3 )^ - Y.e( 5 )^ );
C := 0.1 * ( A + A + C + Y.e( 2 )^ + Y.e( 3 )^ + Y.e( 3 )^ + Y.e( 4 )^ );
{ START LOOP }
for I := 5 to NDIM do
begin
A := B;
B := C;
C := 0.2E0 * ( Y.e( I - 4 )^ + Y.e( I - 3 )^ + Y.e( I - 2 )^
+ Y.e( I - 1 )^ + Y.e( I )^ );
e( I - 4 )^ := A;
end;
{ UPDATE LAST FOUR COMPONENTS}
A := Y.e( NDIM )^ + Y.e( NDIM )^;
A := 0.10 * ( A + A + Y.e( NDIM - 1 )^ + Y.e( NDIM - 1 )^
+ Y.e( NDIM - 1 )^ + Y.e( NDIM - 2 )^ + Y.e( NDIM - 2 )^
+ Y.e( NDIM - 3 )^ );
e( NDIM - 3 )^ := B;
e( NDIM - 2 )^ := C;
e( NDIM - 1 )^ := A;
e( NDIM )^ := A + A - C;
end;
procedure Jacobi( AT, S : Matrix; L : Vector );
var
i, j, k, p, q : Word;
SinT, CosT, Sin2T, Cos2T,
Lambda, Mu, Omega,
AMax, App, Aqq, Apq, Temp : Real;
T : Vector;
A, B, R : Matrix;
begin
A.Init( AT );
B.Init( A );
S.Clear;
for i := 1 to S.n do
S.E( i, i )^ := 1;
R.Init( S );
T.InitRow( R );
NIteration := 0;
repeat
Inc( NIteration );
B.Copy( A );
R.Copy( S );
p := 1;
q := 2;
AMax := A.E( p, q )^;
T.Diag( A );
Temp := T.Max;
for i := 1 to A.n do
for j := i + 1 to A.n do
if Abs( A.E( i, j )^ ) > AMax then
begin
p := i;
q := j;
AMax := Abs( A.E( p, q )^ );
end;
if ( AMax + Temp ) = Temp then
Break;
App := A.E( p, p )^;
Aqq := A.E( q, q )^;
Apq := A.E( p, q )^;
Lambda := -Apq;
Mu := ( App - Aqq ) / 2.0;
Omega := Lambda / Sqrt( Sqr( Lambda ) + Sqr( Mu ) );
if Mu < 0 then
Omega := -Omega;
SinT := Omega / Sqrt( 2 * ( 1 + Sqrt( 1 - Sqr( Omega ) ) ) );
Sin2T := Sqr( SinT );
CosT := Sqrt( 1 - Sin2T );
Cos2T := Sqr( CosT );
for k := 1 to A.n do
begin
B.E( p, k )^ := A.E( p, k )^ * CosT - A.E( q, k )^ * SinT;
B.E( q, k )^ := A.E( p, k )^ * SinT + A.E( q, k )^ * CosT;
end;
for i := 1 to A.n do
begin
B.E( i, p )^ := A.E( i, p )^ * CosT - A.E( i, q )^ * SinT;
B.E( i, q )^ := A.E( i, p )^ * SinT + A.E( i, q )^ * CosT;
R.E( i, p )^ := S.E( i, p )^ * CosT - S.E( i, q )^ * SinT;
R.E( i, q )^ := S.E( i, p )^ * SinT + S.E( i, q )^ * CosT;
end;
B.E( p, p )^ := App * Cos2T + Aqq * Sin2T - 2 * Apq * SinT * CosT;
B.E( q, q )^ := App * Sin2T + Aqq * Cos2T + 2 * Apq * SinT * CosT;
B.E( p, q )^ := 0;
B.E( q, p )^ := 0;
A.Copy( B );
S.Copy( R );
until false;
L.Diag( A );
B.Free;
R.Free;
A.Free;
T.Free;
end;
function Eigen.F( Alpha : Real ) : Real;
var
Q, T, X : Vector;
St, S : Matrix;
Z : Real;
begin
Inc( NIteration );
S.Init( Gamma );
St.InitTrans( Vectors );
Q.InitRow( Gamma );
T.Init( Q );
X.Init( Q );
S.Clear;
S.Diag( Exp( Alpha ) );
S.Multiple( Vectors, S );
S.Multiple( S, St );
T.Diag( Gamma );
T.SetAll( 1 );
Q.Multiple( Gamma, T );
S.Addition( Gamma, S );
X.Divide( Q, S );
T.Substrac( X, T );
Z := T.SummSqr;
F := Ln( Z );
Q.Free;
T.Free;
S.Free;
ST.Free;
X.Free;
end;
procedure Eigen.Init( A : Matrix );
var
Iter : LongWord;
Q, T, X : Vector;
St, S : Matrix;
xZ : Real;
begin
if A.n <> A.m then { Матрица квадратная ? }
Error( 4001 );
if A.n < 2 then
Error( 4003 );
Values.InitRow( A );
Vectors.Init( A );
Jacobi( A, Vectors, Values );
AbsValues.Init( Values );
AbsValues.Abs( Values );
if AbsValues.Min <> 0 then
Cond := AbsValues.Max / AbsValues.Min
else
Cond := 1E+38;
D.Init( A );
R.Init( D );
P.Init( R );
Gamma.Init( A );
Q.InitRow( A );
X.Init( Q );
T.Init( Q );
St.Init( A );
S.Init( St );
Iter := NIteration;
D.Clear;
D.Diag( 1 );
R.ScMultiple( 4, R );
R.Addition( R, D );
R.MSqrt( R );
R.Substrac( R, D );
R.ScMultiple( 0.5, R );
D.MSqr( R );
P.Substrac( A, R );
P.Substrac( P, D );
NIteration := Iter + NIteration;
xZ := Exp( Ln( MathEps ) * ( Ln( 1 / MathEps ) / ( Ln( Cond ) + Ln( 1 / MathEps ) ) ) );
Q.SetAll( Exp( xZ ) );
S.Clear;
S.Diag( Q );
St.Trans( Vectors );
S.Multiple( Vectors, S );
S.Multiple( S, St );
Gamma.Copy( S );
Q.Free;
T.Free;
X.Free;
St.Free;
S.Free;
end;
procedure Vector.Divide( x, y : Vector );
var
i : LongWord;
begin
if x.n <> y.n then
Error( 4010 );
for i := 1 to x.n do
E( i )^ := x.E( i )^ / y.E( i )^;
end;
procedure Eigen.Free;
begin
Values.Free;
Vectors.Free;
AbsValues.Free;
D.Free;
R.Free;
P.Free;
Gamma.Free;
end;
procedure Matrix.Simmetry( A : Matrix );
var
T : Matrix;
begin
if A.n <> A.m then
Error( 5001 );
if n <> A.n then
Error( 5002 );
T.InitTrans( A );
T.Addition( T, A );
ScMultiple( 0.5, T );
T.Free;
end;
procedure Matrix.MAbs( AX : Matrix );
var
T : Matrix;
begin
T.InitSqr( AX );
MSqrt( T );
T.Free;
end;
function Spline.FMin( A, B : Real ) : Real;
begin
FMin := HMinZero.FMin( SELF, A, B );
end;
function Spline.FMax( A, B : Real ) : Real;
begin
FMax := HMinZero.FMax( SELF, A, B );
end;
function Spline.ZeroIn( A, B : Real ) : Real;
begin
ZeroIn := FZeroIn( SELF, A, B );
end;
function Spline.Integr( A, B : Real ) : Real;
var
x1, x3, x5, F1, F3, F5 : Real;
function Int( x1, x3, x5, F1, F3, F5, Eps : Real ) : Real;
var
h1, h2, f2, f4, x2, x4, s1, s2, s3 : Real;
q1, q2, st : Real;
begin
h1 := X3 - X1;
h2 := h1 / 2.;
x2 := ( X3 + X1 ) / 2.;
x4 := ( X5 + X3 ) / 2.;
f2 := F( x2 );
f4 := F( x4 );
{ Формула Симпсона }
s1 := h1 * ( f1 + 4. * f2 + f3 ) / 6.;
s2 := h1 * ( f3 + 4. * f4 + f5 ) / 6.;
{ Формула Ньютона-Коттеса 5-го порядка }
s3 := h2 * 2. * ( 7. * f1 + 32. * f2 + 12. * f3 + 32. * f4 + 7. * f5 ) / 45.;
{ Условие окончания }
st := h2 / Abs( B - A );
q1 := Abs( s1 + s2 - s3 );
q2 := 0.5 * Eps * Abs( s1 + s2 + s3 ) * st + Eps;
if ( q1 > q2 ) and
( h2 > Eps + Abs( B - A ) * Eps ) then
{ Рекурсия - если точность плохая }
Int := Int( x1, x2, x3, f1, f2, f3, Eps )
+ Int( x3, x4, x5, f3, f4, f5, Eps )
else
{ За решения принять значение формулы 5-го порядка }
Int := s3;
end;
begin
Integr := 0;
if A = B then
exit;
x1 := A;
x3 := B - ( B - A ) * 0.5;
x5 := B;
F1 := F( x1 );
F3 := F( x3 );
F5 := F( x5 );
Integr := Int( x1, x3, x5, F1, F3, F5, Eps );
end;
function Spline.Integral( A, B : Real ) : Real;
begin
Integral := Integr( A, B );
end;
function Spline.Integral : Real;
begin
Integral := Integr( Addr^.d1.e( 1 )^, Addr^.d1.e( Addr^.d1.n )^ );
end;
procedure Vector.FillBodyTo( XMax : Real );
var
x, S : Real;
i : Integer;
begin
x := Addr^[ 1 ];
S := ( XMax - x ) / ( n - 1 );
for i := 1 to n do
begin
Addr^[ i ] := x;
x := x + S;
end;
end;
procedure Vector.FillBody;
begin
FillBodyTo( Addr^[ n ] );
end;
procedure Vector.SubVector( x : Vector; From, Count : LongWord );
var
i, j : LongWord;
begin
if ( n < Count ) or ( ( Count + From - 1 ) > x.n ) then
Error( 2004 );
if ( x.n < From ) then
Error( 2005 );
j := 0;
for i := From to From + Count - 1 do
begin
Inc( j );
Addr^[ j ] := x.e( i )^;
end;
end;
procedure PolyApprox.Init( xt, yt : Vector; NP : Integer );
{
Аппроксимация зависимости Y( x )
полиномом степени NP - 1
Вход :
X, Y;
}
var
A : Matrix; { Матрица плана }
AT : Matrix; { --//-- Транспонированная }
B : Matrix;
BY : Vector;
t : Vector;
i, j : LongWord;
Z : Real;
begin
Coeff.Init( NP );
A.Init( xt.n, Coeff.n );
{
Формирование матрицы плана
}
t.Init( xt.n );
XMin := xt.Min;
XMax := xt.Max;
for i := 1 to Coeff.n do
begin
for j := 1 to xt.n do
t.E( j )^ := xt.e( j )^;
t.IntPower( t, i - 1 );
A.Col( i, t );
end;
{ Обычный метод НК }
PlanM.Init( A ); // Запомним матрицу плана
AT.InitTrans( A ); //
B.InitSqr( A ); // B = AT * A
Coeff.Multiple( AT, yt ); // Coeff = AT * y
Coeff.Divide( Coeff, B ); { Coeff = Coeff / B }
{ но, можно и так : }
{ вычисление псевдообратной матрицы }
// AT.Invert( A );
//
// Coeff.Multiple( AT, yt ); // Coeff = A+ * yt
if NP > 1 then
begin
dCoeff.Init( Coeff.n - 1 );
for i := 2 to Coeff.n do
dCoeff.e( i - 1 )^ := Coeff.e( i )^ * ( i - 1 );
end;
t.Free;
A.Free;
AT.Free;
end;
function PolyApprox.PX( xr : Real ) : Real;
begin
PX := Coeff.Poly( xr );
end;
function PolyApprox.DPX( xr : Real ) : Real;
{
Производная полинома в "xr"
}
begin
DPX := dCoeff.Poly( xr );
end;
procedure PolyApprox.Free;
begin
if Coeff.n > 1 then
dCoeff.Free;
Coeff.Free;
PlanM.Free;
end;
function Matrix.Difference( A : Matrix ) : Real;
begin
Difference := SELF.Norm - A.Norm;
end;
function Vector.Difference( x : Vector ) : Real;
begin
Difference := Sqrt( SELF.SummSqr ) - Sqrt( x.SummSqr );
end;
function Matrix.Asimm : Real;
{
Ассимметрия матрицы
}
var
i, j : LongWord;
S, T : Real;
begin
if N <> M then
Error( 2002 );
S := 0;
T := S;
for i := 1 to N do
for j := 1 to N do
if i <> j then
begin
S := S + Math.IntPower( E( i, j )^ - E( j, i )^, 2 );
{ T := T + ( E(i,j)^ + E(j,i)^ ) / 2; }
end;
S := Sqrt( S ) {/ ( T + 1 )};
Asimm := S;
end;
procedure Vector.IntPower( x : Vector; P : Integer );
{
Поэлементное возведение в целую степень
}
var
i : LongWord;
t : Vector;
begin
t.Init( x.N );
for i := 1 to x.n do
t.E( i )^ := Math.IntPower( x.E( i )^, P );
Copy( t );
t.Free;
end;
procedure Matrix.MSqr( A : Matrix );
{ T
= A * A ( квадрат матрицы )
}
var
T : Matrix;
begin
if ( N <> M ) or ( M <> A.M ) then
Error( 2001 );
T.InitTrans( A );
Multiple( T, A );
T.Free;
end;
procedure Matrix.InitSqr( A : Matrix );
{ T
= A * A ( квадрат матрицы )
}
begin
Init( A.m, A.m );
MSqr( A );
end;
function Vector.Poly( x : Real ) : Real; { Полином x }
{
Poly = .e(1) + x * ( .e(2) + x * ( .e(3) + x * ( .e(4) + ...x * .e(n))...
}
var
i : Integer;
S : Real;
begin
S := e( n )^;
for i := n - 1 downto 1 do
S := e( i )^ + S * x;
Poly := S;
end;
procedure Matrix.ReadFromFile( FN : string );
{
Чтение матрицы из текстового файла
( по строкам )
}
var
f : Text;
S : string;
i, j : LongWord;
Y : Matrix;
const
Delim : CharSet =
[ ' ', ';', #9 ];
begin
if FileExists( FN ) then
begin
Assign( f, FN );
Reset( f );
n := 0;
j := n;
while not Eof( f ) do
begin
ReadLn( f, S );
if ( Trim( S ) = '' ) then
Continue;
if ( S[ 1 ] = '''' ) then
Continue;
Inc( n );
m := WordCount( S, Delim );
if j = 0 then
j := m
else
if j <> m then
begin
ShowMessage( 'Error in input file.(1)' );
Halt;
end;
end;
Y.Init( n, m );
Y.Clear;
Reset( f );
n := 0;
while not Eof( f ) do
begin
ReadLn( f, S );
if ( Trim( S ) = '' ) then
Continue;
if ( S[ 1 ] = '''' ) then
Continue;
Inc( n );
for i := 1 to WordCount( S, Delim ) do
Y.E( n, i )^ := StrToFloat( ExtractWord( i, S, Delim ) );
end;
Init( n, m );
Copy( Y );
Y.Free;
Close( f );
end
else
begin
ShowMessage( 'File : "' + FN + '" - not found.' );
Halt;
end;
end;
function Vector.Max : Real;
{
Максимальный элемент вектора
}
var
i : LongWord;
P : ArrayPtr;
X : Real;
begin
P := Addr;
X := P^[ 1 ];
for i := 1 to n do
if P^[ i ] > X then
X := P^[ i ];
Max := X;
end;
function Vector.Min : Real;
{
Минимальный элемент вектора
}
var
i : LongWord;
P : ArrayPtr;
X : Real;
begin
P := Addr;
X := P^[ 1 ];
for i := 1 to n do
if P^[ i ] < X then
X := P^[ i ];
Min := X;
end;
procedure Vector.Abs( x : Vector );
{
.e(i)^ = Abs( x.e(i)^ )
}
var
i : LongWord;
P1 : ArrayPtr;
P2 : ArrayPtr;
begin
P1 := Addr;
P2 := x.Addr;
for i := 1 to n do
P1^[ i ] := System.Abs( P2^[ i ] );
end;
function Vector.MaxIndex : LongWord;
{
Индекс максимального элемента
}
var
i : LongWord;
j : LongWord;
P : ArrayPtr;
X : Real;
begin
P := Addr;
X := P^[ 1 ];
j := 1;
for i := 1 to n do
if P^[ i ] > X then
begin
X := P^[ i ];
j := i;
end;
MaxIndex := j;
end;
function Vector.MinIndex : LongWord;
{
Индекс минимального элемента
}
var
i : LongWord;
j : LongWord;
P : ArrayPtr;
X : Real;
begin
P := Addr;
X := P^[ 1 ];
j := 1;
for i := 1 to n do
if P^[ i ] < X then
begin
X := P^[ i ];
j := i;
end;
MinIndex := j;
end;
function Matrix.Cond : Real;
{
Число обусловленности матрицы( произведение нормы обратной и нормы исходной )
-1
Cond = ||.|| * ||.||.
}
var
B, A : Matrix;
n0, n1 : Real;
begin
n0 := SELF.Norm;
if n = m then
begin
B.Init( SELF );
A.Init( B );
B.Clear;
B.Diag( 1 );
B.Divide( B, A );
end
else
Error( 1011 );
n1 := B.Norm;
Cond := n1 * n0;
B.Free;
A.Free;
end;
function Matrix.Norm : Real;
{
Норма Фробениуса :
= Sqrt( Summ( Sqr( .e( *, * ) ) ) )
}
var
i : Integer;
S : Real;
begin
S := 0;
for i := 1 to n do
S := S + Addr^[ i ].SummSqr;
Norm := Sqrt( S );
end;
procedure Matrix.MSqrt( AX : Matrix );
{
HNV 1997
Квадратный корень матрицы A.
( предполагается, что матрица A -
положительно определенная. )
R такая, что T
R * R = A
Симметричное/асимметричное разложение матрицы.
Ассиметрия характерна для плохо обусловленных.
}
var
Y, X, R, T : Matrix;
Diff, DiffOld : Real;
Alphax, EAlpha : Real;
Reject : Boolean;
begin
Y.Init( n, n );
T.Init( Y );
X.Init( T );
R.Init( X );
X.ScMultiple( 0.5, AX );
X.Addition( X, 1 ); { B = AX / 2 + 1 }
NIteration := 0;
Y.MSqr( X );
Y.Substrac( Y, AX );
DiffOld := Y.Norm;
Alphax := 0.5;
{ Обычная реализация метода Ньютона }
repeat
Inc( NIteration );
Y.MSqr( X );
Y.Substrac( Y, AX );
T.Trans( X );
Y.Divide( Y, T );
repeat
T.ScMultiple( Alphax, Y );
R.Substrac( X, T );
T.MSqr( R );
T.Substrac( T, AX );
Diff := T.Norm;
Reject := Diff > DiffOld;
if Reject then
Alphax := -Alphax / 17
else
Break;
EAlpha := Alphax * Alphax + 1;
until EAlpha = 1;
if ( not Reject ) and
( Abs( Alphax ) * ( DiffOld - Diff ) > ( DiffOld + 1 ) * Eps ) then
begin
X.Copy( R );
DiffOld := Diff;
if Abs( Alphax ) < 0.5 then
Alphax := Alphax * 2;
end
else
Break;
until NIteration > 1023; // Обычно сходится за 20-30 итераций...
Trans( X ); // - результат
Y.Free;
X.Free;
R.Free;
T.Free;
end;
procedure Matrix.Init( Size1, Size2 : LongWord );
var
i : LongWord;
begin
if Size1 = 0 then
Error( 2018 );
m := Size2;
n := Size1;
VAddr.Size := n * SizeOf( VectorPrim );
GetMem( VAddr.Ptr, VAddr.Size );
// VAddr := GetVMem( n * SizeOf( VectorPrim ) );
{ Разпределить массив векторов-строк }
for i := 1 to n do
Addr^[ i ].Init( m );
FInit := Indicator { Флаг инициализации }
end;
procedure Matrix.Init( A : Matrix );
begin
Init( A.n, A.m );
Copy( A );
end;
procedure Matrix.InitTrans( A : Matrix );
begin
Init( A.m, A.n );
Trans( A );
end;
procedure Matrix.Trans( A : Matrix );
{
Транспонирование матрицы A
}
var
i : LongWord;
x : Vector;
B : Matrix;
begin
if ( n <> A.m ) or ( m <> A.n ) then
Error( 116 );
x.Init( A.n );
B.Init( A.m, A.n );
for i := 1 to A.m do
begin
x.Col( i, A );
B.Row( i, x );
end;
Copy( B );
B.Free;
x.Free;
end;
procedure VectorPrim.Init( Size : LongWord );
begin
if Size = 0 then
Error( 2017 );
n := Size;
{ Распределить память для вектора }
VAddr.Size := n * SizeOf( Real );
GetMem( VAddr.Ptr, VAddr.Size );
// VAddr := GetVMem( n * SizeOf( Real ) );
FInit := Indicator
end;
procedure Vector.InitRow( A : Matrix );
begin
Init( A.m );
end;
procedure Vector.InitCol( A : Matrix );
begin
Init( A.n );
end;
procedure Vector.InitRow( i : Integer; A : Matrix );
begin
InitRow( A );
Row( i, A );
end;
procedure Vector.InitCol( i : Integer; A : Matrix );
begin
InitCol( A );
Col( i, A );
end;
procedure VectorPrim.Init( X : VectorPrim );
begin
n := X.n;
{ Распределить память для вектора }
VAddr.Size := n * SizeOf( Real );
GetMem( VAddr.Ptr, VAddr.Size );
// VAddr := GetVMem( n * SizeOf( Real ) );
FInit := Indicator;
Copy( X );
end;
procedure VectorPrim.SetAll( X : Real );
var
i : LongWord;
t : ArrayPtr;
begin
t := Addr;
for i := 1 to n do
t^[ i ] := X;
end;
procedure Spline.Init( X, Y : Vector );
procedure SplineXY;
{
Вычисление коэффициентов кубического сплайна функции
заданной таблицей значений Y( x ).
}
var
i, j : LongWord;
f : Real;
begin
NumbSpline := 1;
with Addr^ do
begin
for i := 1 to NPoint - 1 do
begin
h.E( i )^ := x.E( i + 1 )^ - x.E( i )^;
d.E( i )^ := ( y.E( i + 1 )^ - y.E( i )^ ) / h.E( i )^;
end;
dg.E( 1 )^ := 2.;
dg.E( NPoint )^ := 2.;
d2.E( 1 )^ := 1.;
d1.E( NPoint - 1 )^ := 1.;
bb.E( 1 )^ := d.E( 1 )^ * 3.;
bb.E( NPoint )^ := d.E( NPoint - 1 )^ * 3.;
for i := 2 to NPoint - 1 do
begin
bb.E( i )^ := ( d.E( i )^ * h.E( i - 1 )^ + d.E( i - 1 )^ * h.E( i )^ ) * 3.;
d1.E( i - 1 )^ := h.E( i )^;
d2.E( i )^ := h.E( i - 1 )^;
dg.E( i )^ := 2. * ( h.E( i )^ + h.E( i - 1 )^ );
end;
{
Решение системы линейных уравнений с 3-х диагональной
матрицей коэффициентов
}
for i := 1 to NPoint - 1 do
begin
f := d1.E( i )^ / dg.E( i )^;
dg.E( i + 1 )^ := dg.E( i + 1 )^ - d2.E( i )^ * f;
bb.E( i + 1 )^ := bb.E( i + 1 )^ - bb.E( i )^ * f;
end;
bb.E( NPoint )^ := bb.E( NPoint )^ / dg.E( NPoint )^;
for i := 1 to NPoint - 1 do
begin
j := NPoint - i;
bb.E( j )^ := ( bb.E( j )^ - d2.E( j )^ * bb.E( j + 1 )^ ) / dg.E( j )^;
end;
for i := 1 to NPoint do
begin
d1.Copy( x ); { d1 - исходные значения X }
d2.Copy( y ); { d2 - ---:---- Y }
end;
end;
end;
begin
VAddr.Size := SizeOf( SplineCoeffType );
GetMem( VAddr.Ptr, SizeOf( SplineCoeffType ) );
// VAddr := GetVMem( SizeOf( SplineCoeffType ) );
with Addr^ do
begin
NPoint := X.n;
H.Init( X.n );
D.Init( X.n );
bb.Init( X.n );
d1.Init( X.n );
dg.Init( X.n );
d2.Init( X.n );
end;
SplineXY;
end;
function Spline.F( X : Real ) : Real;
{
Вычисление значения сплайн-функции в точке X.
}
function SplineIndex : LongWord;
{
Вычисляет номер сплайна для точки 'X'.
}
var
NS : LongWord;
procedure IndRecurs( K, L : LongWord );
var
M : LongWord;
begin
with Addr^ do
begin
NS := K;
if ( L - K ) <= 1 then
Exit;
M := ( ( K + L ) div 2 );
if ( ( X - D1.E( K )^ ) * ( X - D1.E( M )^ ) ) <= 0.0 then
IndRecurs( K, M )
else
IndRecurs( M, L );
end;
end;
begin
with Addr^ do
begin
SplineIndex := 1;
if X <= d1.E( 1 )^ then
exit;
SplineIndex := NPoint - 1;
if X >= d1.E( NPoint )^ then
exit;
IndRecurs( 1, NPoint );
SplineIndex := NS;
end;
end;
var
j : LongWord;
f1, t, s : Real;
begin
with Addr^ do
begin
j := SplineIndex;
t := ( X - d1.E( j )^ ) / h.E( j )^;
f1 := 1. - t;
s := t * d2.E( j + 1 )^ + f1 * d2.E( j )^;
s := s + h.E( j )^ * f1 * t * ( ( bb.E( j )^ - d.E( j )^ ) * f1
- ( bb.E( j + 1 )^ - d.E( j )^ ) * t );
F := s;
end;
end;
function Spline.DF( X : real ) : real;
{
Вычисление первой производной от сплайн-функции в точке 'X'.
}
var
Delta : real;
Temp : Real;
PA : PolyApprox;
xS, yS : Vector;
procedure PolyCalc( n : Integer );
begin
xS.Init( 5 );
yS.Init( 5 );
xS.SubVector( Addr^.D1, n, 5 );
yS.SubVector( Addr^.D2, n, 5 );
PA.Init( xS, yS, 5 );
DF := PA.DPX( X );
PA.Free;
yS.Free;
xS.Free;
end;
begin
Delta := Abs( X ) * SqrtEps + SqrtEps;
with Addr^ do
begin
if X - Delta <= D1.E( 1 )^ then
Temp := -3 * F( X ) + 4 * F( X + Delta ) - F( X + 2 * Delta )
else
if X + Delta >= D1.E( Npoint )^ then
Temp := 3 * F( X ) - 4 * F( X - Delta ) + F( X - 2 * Delta )
else
Temp := ( F( X + Delta ) - F( X - Delta ) );
DF := Temp / Delta / 2;
end;
end;
procedure VectorPrim.Free;
begin
FInit := 0;
FreeMem( VAddr.Ptr, VAddr.Size );
VAddr.Ptr := nil;
// FreeVMem( VAddr );
// VAddr := 0;
end;
procedure Matrix.Free;
var
i : LongWord;
begin
FInit := 0;
for i := 1 to n do
Addr^[ i ].Free;
FreeMem( VAddr.Ptr, VAddr.Size );
VAddr.Ptr := nil;
//FreeVMem( VAddr );
// VAddr := 0;
end;
procedure Spline.Free;
begin
with Addr^ do
begin
H.Free;
D.Free;
bb.Free;
d1.Free;
dg.Free;
d2.Free;
end;
FreeMem( VAddr.Ptr, VAddr.Size );
VAddr.Ptr := nil;
//FreeVMem( VAddr );
// VAddr := 0;
end;
function VectorPrim.Addr : ArrayPtr;
begin
Addr := VAddr.Ptr;
//Addr := VirtualToPtr( VAddr );
end;
function Matrix.Addr : MatrixVPrimPtr;
begin
Addr := VAddr.Ptr;
//Addr := VirtualToPtr( VAddr );
end;
function Matrix.E( I, J : LongWord ) : RealPtr;
begin
if ( i >= 1 ) and ( i <= n ) and ( j >= 1 ) and ( j <= m ) then
E := System.Addr( Addr^[ i ].E( j )^ ) { Адрес элемента I,J }
else
Error( 4 );
end;
function VectorPrim.E( I : LongWord ) : RealPtr;
begin
if ( i >= 1 ) and ( i <= n ) then
E := System.Addr( Addr^[ i ] ) { Адрес элемента I }
else
Error( 5 );
end;
procedure VectorPrim.Copy( X : VectorPrim );
begin
if FInit <> Indicator then
Error( 100 );
Move( X.Addr^, Addr^, X.n * SizeOf( Real ) ); { Быстрая пересылка }
end;
procedure Matrix.Copy( B : Matrix );
var
i : LongWord;
begin
if FInit <> Indicator then
Error( 101 );
for i := 1 to n do
Addr^[ i ].Copy( B.Addr^[ i ] ); { Векторное копирование }
end;
procedure Matrix.Multiple( A, B : Matrix );
{
Вычисление произведения двух матриц
= A * B
}
var
i, j : LongWord;
TX : Matrix;
t1, t2 : Vector;
begin
if FInit <> Indicator then
Error( 102 );
TX.Init( A.n, B.m );
t1.Init( A.m );
t2.Init( B.n );
for i := 1 to A.n do
begin
t1.Row( i, A );
for j := 1 to B.m do
begin
t2.Col( j, B );
t2.Multiple( t2, t1 );
TX.E( i, j )^ := t2.Summ;
end;
end;
Copy( TX );
TX.Free;
t1.Free;
t2.Free;
end;
procedure Matrix.Multiple( A, B : VectorPrim );
{
T
Вычисление произведения двух векторов A * B
}
var
i, j : LongWord;
begin
if FInit <> Indicator then
Error( 102 );
if A.n <> B.n then
Error( 4001 );
if n <> m then
Error( 4002 );
if n <> A.n then
Error( 4003 );
for i := 1 to n do
for j := 1 to n do
E( i, j )^ := A.E( i )^ * B.E( j )^;
end;
procedure Vector.Multiple( A : Matrix; x : Vector );
{
Вычисление произведения матрицы на вектор
= A * x
}
var
i : LongWord;
T1, T2 : Vector;
begin
if x.n <> A.m then
Error( 6 );
if FInit <> Indicator then
Error( 103 );
T1.Init( A.n );
T2.Init( A.m );
for i := 1 to A.n do
begin
T2.Row( i, A ); { Быстрая пересылка }
T2.Multiple( T2, x ); { Умножение }
T1.Addr^[ i ] := T2.Summ; { Суммирование }
end;
Copy( T1 );
T1.Free;
T2.Free;
end;
procedure VectorPrim.Multiple( x, y : VectorPrim );
var
i : LongWord;
yp, xp, Sp : ArrayPtr;
begin
if x.n <> y.n then
Error( 121 );
Sp := Addr;
xp := x.Addr;
yp := y.Addr;
for i := 1 to x.n do
Sp^[ i ] := xp^[ i ] * yp^[ i ];
end;
procedure Vector.Divide( x : Vector; AB : Matrix );
{
Решение системы линейных алгебраических уравнений
вида:
A * y = b
методом прямого деления.
}
var
b : Matrix;
begin
if ( x.n <> AB.m ) or ( AB.m <> AB.n ) then
Error( 7 );
if FInit <> Indicator then { Новый вектор }
Error( 104 );
b.Init( AB.n, 1 );
b.Col( 1, x );
b.Divide( b, AB );
Col( 1, b );
b.Free;
end;
procedure Matrix.Divide( Bx, Ax : Matrix );
{
Решение матричной системы вида :
A * Y = B, где
A[n,n], Y[n,m], B[n,m] m<=n
может быть применена для обращения матрицы
если В = Е.
}
var
i, j, k : LongWord;
d, t : real;
a, b : Matrix;
FBreak : Boolean;
begin
if FInit <> Indicator then { Новая матрица }
Error( 105 );
a.Init( Ax.n, Ax.m );
b.Init( Bx.n, Bx.m );
a.Copy( Ax );
b.Copy( Bx );
Condition := True;
MinEps := 1.0;
FBreak := false;
for i := 1 to a.n do
begin
if System.Abs( a.E( i, i )^ ) = 0.0 then
begin
Condition := Condition and ( i = 1 );
for j := 1 to a.n do
begin
if System.Abs( a.E( j, i )^ ) <> 0.0 then
begin
a.Addr^[ i ].Addition( a.Addr^[ i ], a.Addr^[ j ] );
b.Addr^[ i ].Addition( b.Addr^[ i ], b.Addr^[ j ] );
Break;
end;
end;
FBreak := True;
end;
if FBreak then
Continue;
for k := 1 to b.m do
b.E( i, k )^ := b.E( i, k )^ / a.E( i, i )^;
for k := a.n downto i do
a.E( i, k )^ := a.E( i, k )^ / a.E( i, i )^;
for j := 1 to a.n do
begin
d := a.E( j, i )^;
if ( j <> i ) and ( System.Abs( d ) <> 0.0 ) then
begin
for k := i + 1 to a.n do
begin
t := a.E( j, k )^ / d - a.E( i, k )^;
a.E( j, k )^ := t;
end;
for k := 1 to b.m do
b.E( j, k )^ := b.E( j, k )^ / d - b.E( i, k )^;
if j < i then
a.E( j, j )^ := a.E( j, j )^ / d;
end;
end;
end;
for i := 1 to a.n do
for k := 1 to b.m do
if a.E( i, i )^ <> 0 then
E( i, k )^ := b.E( i, k )^ / a.E( i, i )^
else
E( i, k )^ := 0;
a.Free;
b.Free;
end;
procedure Vector.Diag( A : Matrix );
{
= Diag( A );
}
var
i : LongWord;
P : ArrayPtr;
begin
if FInit <> Indicator then { Новый вектор }
Error( 106 );
P := Addr;
for i := 1 to n do
P^[ i ] := A.E( i, i )^;
end;
procedure Vector.Col( i : LongWord; A : Matrix );
{
= A( *, i )
}
var
j : LongWord;
P : ArrayPtr;
begin
if FInit <> Indicator then { Проверк инициализации }
Error( 107 );
P := Addr;
for j := 1 to A.n do
P^[ j ] := A.E( j, i )^;
end;
procedure Vector.Row( i : LongWord; A : Matrix );
{
= A( i, * );
}
begin
Copy( A.Addr^[ i ] );
end;
procedure VectorPrim.Addition( x, y : VectorPrim );
{
= x.e(*)^ + y.e(*)^;
}
var
j : LongWord;
xP, yP, sP : ArrayPtr;
begin
if ( x.n <> y.n ) then
Error( 9 );
if FInit <> Indicator then { }
Error( 108 );
xP := x.Addr;
yP := y.Addr;
sP := Addr;
for j := 1 to n do
sP^[ j ] := xP^[ j ] + yP^[ j ];
end;
procedure VectorPrim.Substrac( x, y : VectorPrim );
{
= x.e(*)^ - y.e(*)^;
}
var
j : LongWord;
xP, yP, sP : ArrayPtr;
begin
if ( x.n <> y.n ) then
Error( 10 );
if FInit <> Indicator then
Error( 109 );
xP := x.Addr;
yP := y.Addr;
sP := Addr;
for j := 1 to n do
sP^[ j ] := xP^[ j ] - yP^[ j ];
end;
function VectorPrim.Summ : Real;
{
Сумма эл-тов вектора
}
var
i : LongWord;
S : Real;
T : VectorPrim;
AP : ArrayPtr;
begin
S := 0.0;
T.Init( n );
AP := T.Addr;
Move( Addr^, AP^, n * SizeOf( Real ) );
T.SortAbs( T ); { Сортировка по возрастанию }
for i := 1 to n do { Суммируем начиная с меньших эл-тов }
S := S + AP^[ i ];
Summ := S;
T.Free;
end;
function VectorPrim.SummSqr : Real;
{
Сумма квадратов эл-тов вектора
}
var
i : LongWord;
S : Real;
T : VectorPrim;
TP : ArrayPtr;
begin
S := 0.0;
T.Init( n );
TP := T.Addr;
Move( Addr^, TP^, SizeOf( Real ) * n );
T.SortAbs( T ); { сортировка по возрастанию }
for i := 1 to n do
S := S + Sqr( TP^[ i ] );
SummSqr := S;
T.Free;
end;
procedure Matrix.Addition( A, B : Matrix );
{
= A( *, * ) + B( *, * );
}
var
i : LongWord;
begin
if ( A.n <> B.n ) or ( A.m <> B.m ) then
Error( 11 );
if FInit <> Indicator then
Error( 110 );
for i := 1 to n do
Addr^[ i ].Addition( A.Addr^[ i ], B.Addr^[ i ] );
end;
procedure Matrix.Addition( A : Matrix; B : VectorPrim );
{
= A( *, * ) + B( *, * );
}
var
i : LongWord;
begin
if ( A.n <> n ) or ( n <> m ) then
Error( 11 );
if FInit <> Indicator then
Error( 110 );
for i := 1 to n do
E( i, i )^ := A.E( i, i )^ + B.E( i )^;
end;
procedure Matrix.Addition( A : Matrix; B : Real );
{
= A( *, * ) + B( *, * );
}
var
i : LongWord;
begin
if ( A.n <> A.m ) then
Error( 11 );
if FInit <> Indicator then
Error( 110 );
Copy( A );
for i := 1 to n do
E( i, i )^ := A.E( i, i )^ + B;
end;
procedure Matrix.Substrac( A, B : Matrix );
{
= A( *, * ) - B( *, * );
}
var
i : LongWord;
begin
if ( A.n <> B.n ) or ( A.m <> B.m ) then
Error( 11 );
if FInit <> Indicator then
Error( 111 );
for i := 1 to n do
Addr^[ i ].Substrac( A.Addr^[ i ], B.Addr^[ i ] );
end;
procedure Matrix.Diag( b : VectorPrim );
{
Diag(*) = b(*);
}
var
i : LongWord;
begin
if m <> b.n then
Error( 12 );
for i := 1 to n do
E( i, i )^ := b.E( i )^;
end;
procedure Matrix.Diag( r : Real );
{
Diag(*) = r;
}
var
i : LongWord;
begin
for i := 1 to n do
E( i, i )^ := r;
end;
procedure Matrix.Col( i : LongWord; b : VectorPrim );
{
.e( *, i ) = b( * );
}
var
j : LongWord;
begin
if n <> b.n then
Error( 13 );
for j := 1 to n do
E( j, i )^ := b.E( j )^;
end;
procedure Matrix.Row( i : LongWord; b : VectorPrim );
{
.e( i, * ) = b( * );
}
begin
if m <> b.n then
Error( 13 );
Addr^[ i ].Copy( b );
end;
procedure Matrix.Col( i : LongWord; r : Real );
{
.e( *, i ) = r;
}
var
j : LongWord;
begin
for j := 1 to n do
E( j, i )^ := r;
end;
procedure Matrix.Row( i : LongWord; r : Real );
{
.e( i, * ) = r;
}
var
j : LongWord;
begin
for j := 1 to m do
E( i, j )^ := r;
end;
function Spline.Addr : SplineCoeffPtr;
begin
Addr := VAddr.Ptr;
//Addr := VirtualToPtr( VAddr );
end;
procedure VectorPrim.Sort( a1 : VectorPrim );
{
Quick-сортировка по возрастанию.
}
var
a : ArrayPtr;
t : Vector;
procedure SortPrim( l, r : LongWord );
var
i, j : LongWord;
x, y : Real;
begin
i := l;
j := r;
x := a^[ ( l + r ) div 2 ];
repeat
while a^[ i ] < x do
i := i + 1;
while x < a^[ j ] do
j := j - 1;
if i <= j then
begin
y := a^[ i ];
a^[ i ] := a^[ j ];
a^[ j ] := y;
i := i + 1;
j := j - 1;
end;
until i > j;
if l < j then
SortPrim( l, j );
if i < r then
SortPrim( i, r );
end;
begin {quicksort}
;
t.Init( a1.n );
t.Copy( a1 );
a := t.Addr;
SortPrim( 1, N );
Copy( t );
t.Free;
end;
procedure VectorPrim.SortBy( a1 : VectorPrim );
{
Quick-сортировка по возрастанию.
}
var
a, b : ArrayPtr;
t : Vector;
procedure SortPrim( l, r : LongWord );
var
i, j : LongWord;
x, y : Real;
begin
i := l;
j := r;
x := a^[ ( l + r ) div 2 ];
repeat
while a^[ i ] < x do
i := i + 1;
while x < a^[ j ] do
j := j - 1;
if i <= j then
begin
y := a^[ i ];
a^[ i ] := a^[ j ];
a^[ j ] := y;
y := b^[ i ];
b^[ i ] := b^[ j ];
b^[ j ] := y;
i := i + 1;
j := j - 1;
end;
until i > j;
if l < j then
SortPrim( l, j );
if i < r then
SortPrim( i, r );
end;
begin {quicksort}
t.Init( a1.n );
t.Copy( a1 );
a := t.Addr;
b := Addr;
SortPrim( 1, N );
{ Copy( t );}
t.Free;
end;
procedure VectorPrim.SortAbs( a1 : VectorPrim );
{
Quick-сортировка по возрастанию ABS.
}
var
a : ArrayPtr;
t : Vector;
procedure SortPrim( l, r : LongWord );
var
i, j : LongWord;
x, y : Real;
begin
i := l;
j := r;
x := Abs( a^[ ( l + r ) div 2 ] );
repeat
while Abs( a^[ i ] ) < x do
i := i + 1;
while x < Abs( a^[ j ] ) do
j := j - 1;
if i <= j then
begin
y := a^[ i ];
a^[ i ] := a^[ j ];
a^[ j ] := y;
i := i + 1;
j := j - 1;
end;
until i > j;
if l < j then
SortPrim( l, j );
if i < r then
SortPrim( i, r );
end;
begin {quicksort}
t.Init( a1.n );
t.Copy( a1 );
a := t.Addr;
SortPrim( 1, N );
Copy( t );
t.Free;
end;
procedure VectorPrim.Clear;
begin
SetAll( 0 );
end;
procedure Matrix.Clear;
var
i : LongWord;
begin
for i := 1 to n do
Addr^[ i ].Clear;
end;
function Matrix.Alpha : Real;
var
QCond, xZ, HNorm : Real;
Temp : Vector;
begin
Temp.Init( n );
QCond := SELF.Cond;
Temp.Diag( SELF );
HNorm := Sqrt( Temp.SummSqr );
xZ := Ln( MathEps ) * ( Ln( 1 / MathEps ) / ( Ln( QCond ) + Ln( 1 / MathEps ) ) );
Alpha := Exp( xZ ) * HNorm;
Temp.Free;
end;
procedure Matrix.Invert( A : Matrix );
{
Метод деления для вычисления обратной/псевдообратной матрицы 'A'.
}
var
B : Matrix;
Q : Matrix;
R : Matrix;
QCond, RCond : Real;
begin
Q.InitSqr( A );
//
// Комбинированный метод корня и понижениея числа обусловленности
//
Q.Addition( Q, Q.Alpha );
R.Init( Q );
B.InitTrans( A );
QCond := Q.Cond;
//
// WriteLn('Cond(Q)=', QCond );
//
R.MSqrt( Q ); // квадратный корень Q
RCond := R.Cond;
//
// WriteLn('Cond(R)=', RCond );
//
// Вычисление псевдообратной матрицы
//
B.Divide( B, R );
R.Trans( R );
Divide( B, R );
Q.Free;
R.Free;
B.Free;
end;
procedure VectorPrim.Print;
{ (tail of DOS) }
var
i : LongWord;
l : Integer;
begin
l := Trunc( ( 79 - n ) / n );
if l < 9 then
begin
WriteLn( 'Warning, length of output digit < 9. ' );
for i := 1 to n do
WriteLn( i : 5, ' ', E( i )^ );
exit;
end;
for i := 1 to n do
Write( E( i )^ : l, ' ' );
WriteLn;
end;
procedure VectorPrim.PrintF( M : Byte );
{
(tail of DOS)
}
var
i : LongWord;
l : Byte;
begin
l := Trunc( ( 79 - n ) / n );
if l - M < 2 then
begin
WriteLn( 'Warning, invalid format' );
exit;
end;
if l < 7 then
begin
WriteLn( 'Warning, length of fixed digit < 7. ' );
exit;
end;
if l > 18 then
l := 18;
for i := 1 to n do
Write( E( i )^ : l : M, ' ' );
WriteLn;
end;
procedure Matrix.Print;
{
(tail of DOS)
}
var
i : LongWord;
begin
for i := 1 to n do
Addr^[ i ].Print;
WriteLn;
end;
procedure Matrix.PrintF( M2 : Byte );
{
(tail of DOS)
}
var
i : LongWord;
begin
for i := 1 to n do
Addr^[ i ].PrintF( M2 );
WriteLn;
end;
procedure VectorPrim.ScMultiple( X : Real; y : VectorPrim );
var
i : LongWord;
t : ArrayPtr;
yp : ArrayPtr;
begin
t := Addr;
yp := y.Addr;
for i := 1 to n do
t^[ i ] := X * yp^[ i ]; { Быстрое умножение }
end;
procedure VectorPrim.ScDivide( X : Real; y : VectorPrim );
var
i : LongWord;
t : ArrayPtr;
yp : ArrayPtr;
begin
t := Addr;
yp := y.Addr;
for i := 1 to n do
t^[ i ] := yp^[ i ] / X; { Быстрое умножение }
end;
procedure Matrix.ScMultiple( X : Real; Y : Matrix );
var
i : LongWord;
begin
for i := 1 to n do
Addr^[ i ].ScMultiple( X, Y.Addr^[ i ] );
end;
begin
{
Вычисление точности:
MathEps = относительная машинная точность.
( -log( MathEps ) ~= к-во знаков в мантиссе. )
SqrtEps = MathEps ^ 1/2;
( - точность половина знаков мантиссы. )
Eps = MathEps ^ 3/4;
( --//-- 3/4 знаков мантиссы. )
}
MathEps := 1;
repeat
MathEps := MathEps / 2;
Temp := 1 + MathEps;
until Temp = 1;
SqrtEps := Sqrt( MathEps );
Eps := Sqrt( SqrtEps ) * SqrtEps;
MinEps := 1;
Randomize;
Indicator := Random( $7FFF );
//InitVHeap( '$$Matr.vhp', true );
end.
Этот модуль используется почти во всех реализованных мной численных алгоритмах и методах. Те части, которые писал не я – приводятся без изменений(по возможности) стиля и комментариев.
unit HNVString;
interface
{*********************************************************}
{* OPSTRING.PAS 1.20 *}
{* Copyright (c) TurboPower Software 1987, 1992. *}
{* All rights reserved. *}
{*********************************************************}
Type
CharSet =
Set of Char;
function WordCount(S : string; WordDelims : CharSet) : Byte;
{-Given a set of word delimiters, return number of words in S}
function WordPosition(N : Byte; S : string; WordDelims : CharSet) : Byte;
{-Given a set of word delimiters, return start position of N'th word in S}
function ExtractWord(N : Byte; S : string; WordDelims : CharSet) : string;
{-Given a set of word delimiters, return the N'th word in S}
function RightJust( S : String; N : Word ) : String;
Function HexB( B : Byte ):String;
Function HexText( Var Buff; N : integer ) : String;
implementation
Const
Dig : Array[0..$F]of Char = '0123456789ABCDEF';
{
Convert BYTE to Hex String
}
Function HexB( B : Byte ):String;
Var
T : String;
begin
T := '';
T := T + Dig[ B shr 4 ];
T := T + Dig[ B and $0F ];
HexB := T;
end;
{
Convert BUFFER to HEX String
}
Function HexText( Var Buff; N : integer ) : String;
Type
ByteArray =
Array of Byte;
Var
i : integer;
S : String;
B : ByteArray Absolute Buff;
begin
S := '';
for i:=1 to N do
S := S + HexB( B[i] );
HexText := S;
end;
function RightJust( S : String; N : Word ) : String;
Var
T : String;
i : Integer;
j : Integer;
begin
T := '';
j := N;
if Length( S ) > j then
T := S
else
begin
j := j - Length( S );
for i:=1 to j do
T := T + ' ';
T := T + S;
end;
RightJust := T;
end;
function WordCount(S : string; WordDelims : CharSet) : Byte;
{-Given a set of word delimiters, return number of words in S}
var
Count : Byte; {!!.02}
I : Word; {!!.02}
SLen : Integer;
begin
SLen := Length( S );
Count := 0;
I := 1;
while I <= SLen do
begin
{skip over delimiters}
while (I <= SLen) and (S[I] in WordDelims) do
Inc(I);
{if we're not beyond end of S, we're at the start of a word}
if I <= SLen then
Inc(Count);
{find the end of the current word}
while (I <= SLen) and not(S[I] in WordDelims) do
Inc(I);
end;
WordCount := Count;
end;
function WordPosition(N : Byte; S : string; WordDelims : CharSet) : Byte;
{-Given a set of word delimiters, return start position of N'th word in S}
var
Count : Byte; {!!.02}
I : Word; {!!.02}
SLen : Word;
begin
Count := 0;
I := 1;
SLen := Length( S );
WordPosition := 0;
while (I <= SLen) and (Count <> N) do
begin
{skip over delimiters}
while (I <= SLen) and (S[I] in WordDelims) do
Inc(I);
{if we're not beyond end of S, we're at the start of a word}
if I <= SLen then
Inc(Count);
{if not finished, find the end of the current word}
if Count <> N then
while (I <= SLen) and not(S[I] in WordDelims) do
Inc(I)
else
WordPosition := I;
end;
end;
function ExtractWord(N : Byte; S : string; WordDelims : CharSet) : string;
{-Given a set of word delimiters, return the N'th word in S}
var
I : Word; {!!.12}
SLen : Integer;
Temp : String;
begin
SLen := Length( S );
Temp := '';
I := WordPosition(N, S, WordDelims);
if I <> 0 then
{find the end of the current word}
while (I <= SLen) and not(S[I] in WordDelims) do
begin
{add the I'th character to result}
Temp := Temp + S[i];
Inc(I);
end;
ExtractWord := Temp;
end;
end.
DelphiWorld 6.0