~ubuntu-branches/ubuntu/utopic/mricron/utopic

« back to all changes in this revision

Viewing changes to npm/dmath/eigen.pas

  • Committer: Bazaar Package Importer
  • Author(s): Michael Hanke
  • Date: 2010-07-29 22:07:43 UTC
  • Revision ID: james.westby@ubuntu.com-20100729220743-q621ts2zj806gu0n
Tags: upstream-0.20100725.1~dfsg.1
ImportĀ upstreamĀ versionĀ 0.20100725.1~dfsg.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
{ **********************************************************************
 
2
  *                           Unit EIGEN.PAS                           *
 
3
  *                            Version 1.8                             *
 
4
  *                      (c) J. Debord, May 2001                       *
 
5
  **********************************************************************
 
6
          Procedures for computing eigenvalues and eigenvectors
 
7
  **********************************************************************
 
8
  References:
 
9
  1) Borland's Numerical Methods Toolbox : Jacobi
 
10
  2) 'Numerical Recipes' by Press et al. : EigenVals, RootPol
 
11
  ********************************************************************** }
 
12
 
 
13
unit Eigen;
 
14
 
 
15
interface
 
16
 
 
17
uses
 
18
  FMath, Matrices;
 
19
 
 
20
function Jacobi(A : PMatrix; Lbound, Ubound, MaxIter : Integer;
 
21
                Tol : Float; V : PMatrix; Lambda : PVector) : Integer;
 
22
{ ----------------------------------------------------------------------
 
23
  Eigenvalues and eigenvectors of a symmetric matrix by the iterative
 
24
  method of Jacobi
 
25
  ----------------------------------------------------------------------
 
26
  Input parameters  : A       = matrix
 
27
                      Lbound  = index of first matrix element
 
28
                      Ubound  = index of last matrix element
 
29
                      MaxIter = maximum number of iterations
 
30
                      Tol     = required precision
 
31
  ----------------------------------------------------------------------
 
32
  Output parameters : V      = matrix of eigenvectors (stored by lines)
 
33
                      Lambda = eigenvalues in decreasing order
 
34
  ----------------------------------------------------------------------
 
35
  Possible results  : MAT_OK
 
36
                      MAT_NON_CONV
 
37
  ----------------------------------------------------------------------
 
38
  NB : 1. The eigenvectors are normalized, with their first component > 0
 
39
       2. This procedure destroys the original matrix A
 
40
  ---------------------------------------------------------------------- }
 
41
 
 
42
function EigenVals(A : PMatrix; Lbound, Ubound : Integer;
 
43
                   Lambda_Re, Lambda_Im : PVector) : Integer;
 
44
{ ----------------------------------------------------------------------
 
45
  Eigenvalues of a general square matrix
 
46
  ----------------------------------------------------------------------
 
47
  Input parameters  : A      = matrix
 
48
                      Lbound = index of first matrix element
 
49
                      Ubound = index of last matrix element
 
50
  ----------------------------------------------------------------------
 
51
  Output parameters : Lambda_Re = real part of eigenvalues
 
52
                      Lambda_Im = imaginary part of eigenvalues
 
53
  ----------------------------------------------------------------------
 
54
  Possible results  : MAT_OK
 
55
                      MAT_NON_CONV
 
56
  ----------------------------------------------------------------------
 
57
  NB : This procedure destroys the original matrix A
 
58
  ---------------------------------------------------------------------- }
 
59
 
 
60
function EigenVect(A : PMatrix; Lbound, Ubound : Integer;
 
61
                   Lambda, Tol : Float; V : PVector) : Integer;
 
62
{ ----------------------------------------------------------------------
 
63
  Computes the eigenvector associated to a real eigenvalue
 
64
  ----------------------------------------------------------------------
 
65
  Input parameters  : A       = matrix
 
66
                      Lbound  = index of first matrix element
 
67
                      Ubound  = index of last matrix element
 
68
                      Lambda  = eigenvalue
 
69
                      Tol     = required precision
 
70
  ----------------------------------------------------------------------
 
71
  Output parameters : V       = eigenvector
 
72
  ----------------------------------------------------------------------
 
73
  Possible results  : MAT_OK
 
74
                      MAT_NON_CONV
 
75
  ----------------------------------------------------------------------
 
76
  NB : 1. The eigenvector is normalized, with its first component > 0
 
77
       2. The function returns only one eigenvector, even if the
 
78
          eigenvalue has a multiplicity greater than 1.
 
79
  ---------------------------------------------------------------------- }
 
80
 
 
81
procedure DivLargest(V : PVector; Lbound, Ubound : Integer;
 
82
                     var Largest : Float);
 
83
{ ----------------------------------------------------------------------
 
84
  Normalizes an eigenvector V by dividing by the element with the
 
85
  largest absolute value
 
86
  ---------------------------------------------------------------------- }
 
87
 
 
88
function RootPol(Coef : PVector; Deg : Integer;
 
89
                 X_Re, X_Im : PVector) : Integer;
 
90
{ ----------------------------------------------------------------------
 
91
  Real and complex roots of a real polynomial by the method of the
 
92
  companion matrix
 
93
  ----------------------------------------------------------------------
 
94
  Input parameters  : Coef = coefficients of polynomial
 
95
                      Deg  = degree of polynomial
 
96
  ----------------------------------------------------------------------
 
97
  Output parameters : X_Re = real parts of root (in increasing order)
 
98
                      X_Im = imaginary parts of root
 
99
  ----------------------------------------------------------------------
 
100
  Possible results  : MAT_OK
 
101
                      MAT_NON_CONV
 
102
  ---------------------------------------------------------------------- }
 
103
 
 
104
implementation
 
105
 
 
106
  function Jacobi(A : PMatrix; Lbound, Ubound, MaxIter : Integer;
 
107
                  Tol : Float; V : PMatrix; Lambda : PVector) : Integer;
 
108
  var
 
109
    SinTheta, CosTheta, TanTheta, Tan2Theta : Float;
 
110
    CosSqr, SinSqr, SinCos, SumSqrDiag : Float;
 
111
    AII, AJJ, AIJ, AIK, AJK, VIK, VJK, D : Float;
 
112
    I, J, K, Iter : Integer;
 
113
    Done : Boolean;
 
114
  begin
 
115
    Iter := 0;
 
116
    for I := Lbound to Ubound do
 
117
      for J := Lbound to Ubound do
 
118
        if I = J then
 
119
          V^[I]^[J] := 1.0
 
120
        else
 
121
          V^[I]^[J] := 0.0;
 
122
 
 
123
    repeat
 
124
      Iter := Succ(Iter);
 
125
      SumSqrDiag := 0.0;
 
126
      for I := Lbound to Ubound do
 
127
        SumSqrDiag := SumSqrDiag + Sqr(A^[I]^[I]);
 
128
      Done := True;
 
129
 
 
130
      for I := Lbound to Pred(Ubound) do
 
131
        for J := Succ(I) to Ubound do
 
132
          if Abs(A^[I]^[J]) > Tol * SumSqrDiag then
 
133
            begin
 
134
              Done := False;
 
135
 
 
136
              { Calculate rotation }
 
137
              D := A^[I]^[I] - A^[J]^[J];
 
138
              if Abs(D) > MACHEP then
 
139
                begin
 
140
                  Tan2Theta := D / (2.0 * A^[I]^[J]);
 
141
                  TanTheta := - Tan2Theta + Sgn(Tan2Theta) *
 
142
                  Sqrt(1.0 + Sqr(Tan2Theta));
 
143
                  CosTheta := 1.0 / Sqrt(1.0 + Sqr(TanTheta));
 
144
                  SinTheta := CosTheta * TanTheta;
 
145
                end
 
146
              else
 
147
                begin
 
148
                  CosTheta := SQRT2DIV2;                   { Sqrt(2)/2 }
 
149
                  SinTheta := Sgn(A^[I]^[J]) * SQRT2DIV2;
 
150
                end;
 
151
 
 
152
              { Rotate matrix }
 
153
              CosSqr := Sqr(CosTheta);
 
154
              SinSqr := Sqr(SinTheta);
 
155
              SinCos := SinTheta * CosTheta;
 
156
              AII := A^[I]^[I] * CosSqr + 2.0 * A^[I]^[J] * SinCos
 
157
              + A^[J]^[J] * SinSqr;
 
158
              AJJ := A^[I]^[I] * SinSqr - 2.0 * A^[I]^[J] * SinCos
 
159
              + A^[J]^[J] * CosSqr;
 
160
              AIJ := (A^[J]^[J] - A^[I]^[I]) * SinCos
 
161
              + A^[I]^[J] * (CosSqr - SinSqr);
 
162
              for K := Lbound to Ubound do
 
163
                if not(K in [I, J]) then
 
164
                  begin
 
165
                    AIK := A^[I]^[K] * CosTheta + A^[J]^[K] * SinTheta;
 
166
                    AJK := - A^[I]^[K] * SinTheta + A^[J]^[K] * CosTheta;
 
167
                    A^[I]^[K] := AIK;
 
168
                    A^[K]^[I] := AIK;
 
169
                    A^[J]^[K] := AJK;
 
170
                    A^[K]^[J] := AJK;
 
171
                  end;
 
172
              A^[I]^[I] := AII;
 
173
              A^[J]^[J] := AJJ;
 
174
              A^[I]^[J] := AIJ;
 
175
              A^[J]^[I] := AIJ;
 
176
 
 
177
              { Rotate eigenvectors }
 
178
              for K := Lbound to Ubound do
 
179
                begin
 
180
                  VIK := CosTheta * V^[I]^[K] + SinTheta * V^[J]^[K];
 
181
                  VJK := - SinTheta * V^[I]^[K] + CosTheta * V^[J]^[K];
 
182
                  V^[I]^[K] := VIK;
 
183
                  V^[J]^[K] := VJK;
 
184
                end;
 
185
            end;
 
186
    until Done or (Iter > MaxIter);
 
187
 
 
188
    { The diagonal terms of the transformed matrix are the eigenvalues }
 
189
    for I := Lbound to Ubound do
 
190
      Lambda^[I] := A^[I]^[I];
 
191
 
 
192
    if Iter > MaxIter then
 
193
      begin
 
194
        Jacobi := MAT_NON_CONV;
 
195
        Exit;
 
196
      end;
 
197
 
 
198
    { Sort eigenvalues and eigenvectors }
 
199
    for I := Lbound to Pred(Ubound) do
 
200
      begin
 
201
        K := I;
 
202
        D := Lambda^[I];
 
203
        for J := Succ(I) to Ubound do
 
204
          if Lambda^[J] > D then
 
205
            begin
 
206
              K := J;
 
207
              D := Lambda^[J];
 
208
            end;
 
209
        FSwap(Lambda^[I], Lambda^[K]);
 
210
        SwapRows(I, K, V, Lbound, Ubound);
 
211
      end;
 
212
 
 
213
    { Make sure that the first component of each eigenvector is > 0 }
 
214
    for I := Lbound to Ubound do
 
215
      if V^[I]^[Lbound] < 0.0 then
 
216
        for J := Lbound to Ubound do
 
217
          V^[I]^[J] := - V^[I]^[J];
 
218
 
 
219
    Jacobi := MAT_OK;
 
220
  end;
 
221
 
 
222
  procedure Balance(A : PMatrix; Lbound, Ubound : Integer);
 
223
  { Balances the matrix, i.e. reduces norm without affecting eigenvalues }
 
224
  const
 
225
    RADIX = 2;  { Base used for machine computations }
 
226
  var
 
227
    I, J, Last : Integer;
 
228
    C, F, G, R, S, Sqrdx : Float;
 
229
  begin
 
230
    Sqrdx := Sqr(RADIX);
 
231
    repeat
 
232
      Last := 1;
 
233
      for I := Lbound to Ubound do
 
234
        begin
 
235
          C := 0.0;
 
236
          R := 0.0;
 
237
          for J := Lbound to Ubound do
 
238
            if J <> I then
 
239
              begin
 
240
                C := C + Abs(A^[J]^[I]);
 
241
                R := R + Abs(A^[I]^[J]);
 
242
              end;
 
243
          if (C <> 0.0) and (R <> 0.0) then
 
244
            begin
 
245
              G := R / RADIX;
 
246
              F := 1.0;
 
247
              S := C + R;
 
248
              while C < G do
 
249
                begin
 
250
                  F := F * RADIX;
 
251
                  C := C * Sqrdx;
 
252
                end;
 
253
              G := R * RADIX;
 
254
              while C > G do
 
255
                begin
 
256
                  F := F / RADIX;
 
257
                  C := C / Sqrdx;
 
258
                end;
 
259
              if (C + R) / F < 0.95 * S then
 
260
                begin
 
261
                  Last := 0;
 
262
                  G := 1.0 / F;
 
263
                  for J := Lbound to Ubound do
 
264
                    A^[I]^[J] := A^[I]^[J] * G;
 
265
                  for J := Lbound to Ubound do
 
266
                    A^[J]^[I] := A^[J]^[I] * F;
 
267
                end;
 
268
            end;
 
269
        end;
 
270
    until Last <> 0;
 
271
  end;
 
272
 
 
273
  procedure ElmHes(A : PMatrix; Lbound, Ubound : Integer);
 
274
  { Reduces the matrix to upper Hessenberg form by elimination }
 
275
  var
 
276
    I, J, M : Integer;
 
277
    X, Y : Float;
 
278
  begin
 
279
    for M := Succ(Lbound) to Pred(Ubound) do
 
280
      begin
 
281
        X := 0.0;
 
282
        I := M;
 
283
        for J := M to Ubound do
 
284
          if Abs(A^[J]^[M - 1]) > Abs(X) then
 
285
            begin
 
286
              X := A^[J]^[M - 1];
 
287
              I := J;
 
288
            end;
 
289
        if I <> M then
 
290
          begin
 
291
            for J := Pred(M) to Ubound do
 
292
              FSwap(A^[I]^[J], A^[M]^[J]);
 
293
            for J := Lbound to Ubound do
 
294
              FSwap(A^[J]^[I], A^[J]^[M]);
 
295
          end;
 
296
        if X <> 0.0 then
 
297
          for I := Succ(M) to Ubound do
 
298
            begin
 
299
              Y := A^[I]^[M - 1];
 
300
              if Y <> 0.0 then
 
301
                begin
 
302
                  Y := Y / X;
 
303
                  A^[I]^[M - 1] := Y;
 
304
                  for J := M to Ubound do
 
305
                    A^[I]^[J] := A^[I]^[J] - Y * A^[M]^[J];
 
306
                  for J := Lbound to Ubound do
 
307
                    A^[J]^[M] := A^[J]^[M] + Y * A^[J]^[I];
 
308
                end;
 
309
            end;
 
310
      end;
 
311
    for I := (Lbound + 2) to Ubound do
 
312
      for J := Lbound to (I - 2) do
 
313
        A^[I]^[J] := 0.0;
 
314
  end;
 
315
 
 
316
  function Hqr(A : PMatrix; Lbound, Ubound : Integer;
 
317
               Lambda_Re, Lambda_Im : PVector) : Integer;
 
318
  { Finds the eigenvalues of an upper Hessenberg matrix }
 
319
  label 2, 3, 4;
 
320
  var
 
321
    I, Its, J, K, L, M, N : Integer;
 
322
    Anorm, P, Q, R, S, T, U, V, W, X, Y, Z : Float;
 
323
 
 
324
    function Sign(A, B : Float) : Float;
 
325
    begin
 
326
      if B < 0.0 then Sign := - Abs(A) else Sign := Abs(A)
 
327
    end;
 
328
 
 
329
  begin
 
330
    Anorm := Abs(A^[1]^[1]);
 
331
    for I := Succ(Lbound) to Ubound do
 
332
      for J := I - 1 to Ubound do
 
333
        Anorm := Anorm + Abs(A^[I]^[J]);
 
334
    N := Ubound;
 
335
    T := 0.0;
 
336
    while N >= Lbound do
 
337
      begin
 
338
        Its := 0;
 
339
2:      for L := N downto Succ(Lbound) do
 
340
          begin
 
341
            S := Abs(A^[L - 1]^[L - 1]) + Abs(A^[L]^[L]);
 
342
            if S = 0.0 then S := Anorm;
 
343
            if Abs(A^[L]^[L - 1]) <= MACHEP * S then goto 3
 
344
          end;
 
345
        L := Lbound;
 
346
3:      X := A^[N]^[N];
 
347
        if L = N then
 
348
          begin
 
349
            Lambda_Re^[N] := X + T;
 
350
            Lambda_Im^[N] := 0.0;
 
351
            N := N - 1
 
352
          end
 
353
        else
 
354
          begin
 
355
            Y := A^[N - 1]^[N - 1];
 
356
            W := A^[N]^[N - 1] * A^[N - 1]^[N];
 
357
            if L = N - 1 then
 
358
              begin
 
359
                P := 0.5 * (Y - X);
 
360
                Q := Sqr(P) + W;
 
361
                Z := Sqrt(Abs(Q));
 
362
                X := X + T;
 
363
                if Q >= 0.0 then
 
364
                  begin
 
365
                    Z := P + Sign(Z, P);
 
366
                    Lambda_Re^[N] := X + Z;
 
367
                    Lambda_Re^[N - 1] := Lambda_Re^[N];
 
368
                    if Z <> 0.0 then Lambda_Re^[N] := X - W / Z;
 
369
                    Lambda_Im^[N] := 0.0;
 
370
                    Lambda_Im^[N - 1] := 0.0
 
371
                  end
 
372
                else
 
373
                  begin
 
374
                    Lambda_Re^[N] := X + P;
 
375
                    Lambda_Re^[N - 1] := Lambda_Re^[N];
 
376
                    Lambda_Im^[N] := Z;
 
377
                    Lambda_Im^[N - 1] := - Z
 
378
                  end;
 
379
                N := N - 2
 
380
              end
 
381
            else
 
382
              begin
 
383
                if Its = 30 then
 
384
                  begin
 
385
                    Hqr := MAT_NON_CONV;
 
386
                    Exit;
 
387
                  end;
 
388
                if (Its = 10) or (Its = 20) then
 
389
                  begin
 
390
                    T := T + X;
 
391
                    for I := Lbound to N do
 
392
                      A^[I]^[I] := A^[I]^[I] - X;
 
393
                    S := Abs(A^[N]^[N - 1]) + Abs(A^[N - 1]^[N - 2]);
 
394
                    X := 0.75 * S;
 
395
                    Y := X;
 
396
                    W := - 0.4375 * Sqr(S)
 
397
                  end;
 
398
                Its := Its + 1;
 
399
                for M := N - 2 downto L do
 
400
                  begin
 
401
                    Z := A^[M]^[M];
 
402
                    R := X - Z;
 
403
                    S := Y - Z;
 
404
                    P := (R * S - W) / A^[M + 1]^[M] + A^[M]^[M + 1];
 
405
                    Q := A^[M + 1]^[M + 1] - Z - R - S;
 
406
                    R := A^[M + 2]^[M + 1];
 
407
                    S := Abs(P) + Abs(Q) + Abs(R);
 
408
                    P := P / S;
 
409
                    Q := Q / S;
 
410
                    R := R / S;
 
411
                    if M = L then goto 4;
 
412
                    U := Abs(A^[M]^[M - 1]) * (Abs(Q) + Abs(R));
 
413
                    V := Abs(P) * (Abs(A^[M - 1]^[M - 1]) + Abs(Z)
 
414
                                   + Abs(A^[M + 1]^[M + 1]));
 
415
                    if U <= MACHEP * V then goto 4
 
416
                  end;
 
417
4:              for I := M + 2 to N do
 
418
                  begin
 
419
                    A^[I]^[I - 2] := 0.0;
 
420
                    if I <> (M + 2) then A^[I]^[I - 3] := 0.0
 
421
                  end;
 
422
                for K := M to N - 1 do
 
423
                  begin
 
424
                    if K <> M then
 
425
                      begin
 
426
                        P := A^[K]^[K - 1];
 
427
                        Q := A^[K + 1]^[K - 1];
 
428
                        R := 0.0;
 
429
                        if K <> (N - 1) then
 
430
                          R := A^[K + 2]^[K - 1];
 
431
                        X := Abs(P) + Abs(Q) + Abs(R);
 
432
                        if X <> 0.0 then
 
433
                          begin
 
434
                            P := P / X;
 
435
                            Q := Q / X;
 
436
                            R := R / X
 
437
                          end
 
438
                      end;
 
439
                    S := Sign(Sqrt(Sqr(P) + Sqr(Q) + Sqr(R)), P);
 
440
                    if S <> 0.0 then
 
441
                      begin
 
442
                        if K = M then
 
443
                          begin
 
444
                            if L <> M then
 
445
                              A^[K]^[K - 1] := - A^[K]^[K - 1];
 
446
                          end
 
447
                        else
 
448
                          begin
 
449
                            A^[K]^[K - 1] := - S * X
 
450
                          end;
 
451
                        P := P + S;
 
452
                        X := P / S;
 
453
                        Y := Q / S;
 
454
                        Z := R / S;
 
455
                        Q := Q / P;
 
456
                        R := R / P;
 
457
                        for J := K to N do
 
458
                          begin
 
459
                            P := A^[K]^[J] + Q * A^[K + 1]^[J];
 
460
                            if K <> (N - 1) then
 
461
                              begin
 
462
                                P := P + R * A^[K + 2]^[J];
 
463
                                A^[K + 2]^[J] := A^[K + 2]^[J] - P * Z
 
464
                              end;
 
465
                            A^[K + 1]^[J] := A^[K + 1]^[J] - P * Y;
 
466
                            A^[K]^[J] := A^[K]^[J] - P * X
 
467
                          end;
 
468
                        for I := L to IMin(N, K + 3) do
 
469
                          begin
 
470
                            P := X * A^[I]^[K] + Y * A^[I]^[K + 1];
 
471
                            if K <> (N - 1) then
 
472
                              begin
 
473
                                P := P + Z * A^[I]^[K + 2];
 
474
                                A^[I]^[K + 2] := A^[I]^[K + 2] - P * R
 
475
                              end;
 
476
                            A^[I]^[K + 1] := A^[I]^[K + 1] - P * Q;
 
477
                            A^[I]^[K] := A^[I]^[K] - P
 
478
                          end
 
479
                      end
 
480
                  end;
 
481
                goto 2
 
482
              end
 
483
          end
 
484
      end;
 
485
    Hqr := MAT_OK;
 
486
  end;
 
487
 
 
488
  function EigenVals(A : PMatrix; Lbound, Ubound : Integer;
 
489
                     Lambda_Re, Lambda_Im : PVector) : Integer;
 
490
  begin
 
491
    Balance(A, Lbound, Ubound);
 
492
    ElmHes(A, Lbound, Ubound);
 
493
    EigenVals := Hqr(A, Lbound, Ubound, Lambda_Re, Lambda_Im);
 
494
  end;
 
495
 
 
496
  procedure DivLargest(V : PVector; Lbound, Ubound : Integer;
 
497
                       var Largest : Float);
 
498
  var
 
499
    I : Integer;
 
500
  begin
 
501
    Largest := V^[Lbound];
 
502
    for I := Succ(Lbound) to Ubound do
 
503
      if Abs(V^[I]) > Abs(Largest) then
 
504
        Largest := V^[I];
 
505
    for I := Lbound to Ubound do
 
506
      V^[I] := V^[I] / Largest;
 
507
  end;
 
508
 
 
509
  function EigenVect(A : PMatrix; Lbound, Ubound : Integer;
 
510
                     Lambda, Tol : Float; V : PVector) : Integer;
 
511
 
 
512
  procedure SetMatrix(A, A1 : PMatrix; Lbound, Ubound : Integer; Lambda : Float);
 
513
  { Form A1 = A - Lambda * I }
 
514
  var
 
515
    I : Integer;
 
516
  begin
 
517
    CopyMatrix(A1, A, Lbound, Lbound, Ubound, Ubound);
 
518
    for I := Lbound to Ubound do
 
519
      A1^[I]^[I] := A^[I]^[I] - Lambda;
 
520
  end;
 
521
 
 
522
  function Solve(A : PMatrix; Lbound, Ubound, N : Integer;
 
523
                 Tol : Float; V : PVector) : Integer;
 
524
  { Solve the system A*X = 0 after fixing the N-th unknown to 1 }
 
525
  var
 
526
    A1, W                          : PMatrix;
 
527
    B, S, X                        : PVector;
 
528
    ErrCode, I, I1, J, J1, Ubound1 : Integer;
 
529
  begin
 
530
    Ubound1 := Pred(Ubound);
 
531
 
 
532
    DimMatrix(A1, Ubound1, Ubound1);
 
533
    DimMatrix(W, Ubound1, Ubound1);
 
534
    DimVector(B, Ubound1);
 
535
    DimVector(S, Ubound1);
 
536
    DimVector(X, Ubound1);
 
537
 
 
538
    I1 := Pred(Lbound);
 
539
    for I := Lbound to Ubound do
 
540
      if I <> N then
 
541
        begin
 
542
          Inc(I1);
 
543
          J1 := 0;
 
544
          for J := Lbound to Ubound do
 
545
            if J <> N then
 
546
              begin
 
547
                Inc(J1);
 
548
                A1^[I1]^[J1] := A^[I]^[J];
 
549
              end
 
550
            else
 
551
              B^[I1] := - A^[I]^[J];
 
552
        end;
 
553
 
 
554
    ErrCode :=  SV_Decomp(A1, Lbound, Ubound1, Ubound1, S, W);
 
555
 
 
556
    if ErrCode = 0 then
 
557
      begin
 
558
        SV_SetZero(S, Lbound, Ubound1, Tol);
 
559
        SV_Solve(A1, S, W, B, Lbound, Ubound1, Ubound1, X);
 
560
 
 
561
        { Update eigenvector }
 
562
        I1 := 0;
 
563
        for I := Lbound to Ubound do
 
564
          if I = N then
 
565
            V^[I] := 1.0
 
566
          else
 
567
            begin
 
568
              Inc(I1);
 
569
              V^[I] := X^[I1];
 
570
            end;
 
571
      end;
 
572
 
 
573
    DelMatrix(A1, Ubound1, Ubound1);
 
574
    DelMatrix(W, Ubound1, Ubound1);
 
575
    DelVector(B, Ubound1);
 
576
    DelVector(S, Ubound1);
 
577
    DelVector(X, Ubound1);
 
578
 
 
579
    Solve := ErrCode;
 
580
  end;
 
581
 
 
582
  function ZeroVector(B : PVector; Lbound, Ubound : Integer; Tol : Float) : Boolean;
 
583
  { Check if vector B is zero }
 
584
  var
 
585
    I : Integer;
 
586
    Z : Boolean;
 
587
  begin
 
588
    Z := True;
 
589
    for I := Lbound to Ubound do
 
590
      Z := Z and (Abs(B^[I]) < Tol);
 
591
    ZeroVector := Z;
 
592
  end;
 
593
 
 
594
  function CheckEigenVector(A1 : PMatrix; V : PVector;
 
595
                            Lbound, Ubound : Integer; Tol : Float) : Boolean;
 
596
  { Check if the equation A1 * V = 0 holds }
 
597
  var
 
598
    I, K : Integer;
 
599
    B    : PVector;
 
600
  begin
 
601
    DimVector(B, Ubound);
 
602
 
 
603
    { Form B = A1 * V }
 
604
    for I := Lbound to Ubound do
 
605
      for K := Lbound to Ubound do
 
606
        B^[I] := B^[I] + A1^[I]^[K] * V^[K];
 
607
 
 
608
    { Check if B is zero }
 
609
    CheckEigenVector := ZeroVector(B, Lbound, Ubound, Tol);
 
610
 
 
611
    DelVector(B, Ubound);
 
612
  end;
 
613
 
 
614
  procedure Normalize(V : PVector; Lbound, Ubound : Integer);
 
615
  { Normalize eigenvector and make sure that the first component is >= 0 }
 
616
  var
 
617
    Sum, Norm : Float;
 
618
    I         : Integer;
 
619
  begin
 
620
    Sum := 0.0;
 
621
    for I := Lbound to Ubound do
 
622
      Sum := Sum + Sqr(V^[I]);
 
623
    Norm := Sqrt(Sum);
 
624
    for I := Lbound to Ubound do
 
625
      if V^[I] <> 0.0 then V^[I] := V^[I] / Norm;
 
626
    if V^[Lbound] < 0.0 then
 
627
      for I := Lbound to Ubound do
 
628
        if V^[I] <> 0.0 then V^[I] := - V^[I];
 
629
  end;
 
630
 
 
631
  var
 
632
    ErrCode, I : Integer;
 
633
    A1         : PMatrix;
 
634
 
 
635
  begin
 
636
    DimMatrix(A1, Ubound, Ubound);
 
637
 
 
638
    { Form A1 = A - Lambda * I }
 
639
    SetMatrix(A, A1, Lbound, Ubound, Lambda);
 
640
 
 
641
    { Try to solve the system A1*V=0 by eliminating 1 equation }
 
642
    I := Lbound;
 
643
    repeat
 
644
      if (Solve(A1, Lbound, Ubound, I, Tol, V) = 0) and
 
645
          CheckEigenVector(A1, V, Lbound, Ubound, Tol)
 
646
      then
 
647
        ErrCode := 0
 
648
      else
 
649
        ErrCode := - 1;
 
650
      Inc(I);
 
651
    until (ErrCode = 0) or (I > Ubound);
 
652
 
 
653
    if ErrCode = 0 then
 
654
      begin
 
655
        Normalize(V, Lbound, Ubound);
 
656
        EigenVect := MAT_OK;
 
657
      end
 
658
    else
 
659
      EigenVect := MAT_NON_CONV;
 
660
 
 
661
    DelMatrix(A1, Ubound, Ubound);
 
662
  end;
 
663
 
 
664
  function RootPol(Coef : PVector; Deg : Integer;
 
665
                   X_Re, X_Im : PVector) : Integer;
 
666
  var
 
667
    A : PMatrix;        { Companion matrix }
 
668
    N : Integer;        { Size of matrix }
 
669
    I, J, K : Integer;  { Loop variables }
 
670
    ErrCode : Integer;  { Error code }
 
671
    Temp : Float;
 
672
  begin
 
673
    N := Pred(Deg);
 
674
    DimMatrix(A, N, N);
 
675
 
 
676
    { Set up the companion matrix (to save space, begin at index 0) }
 
677
    for J := 0 to N do
 
678
      A^[0]^[J] := - Coef^[Deg - J - 1] / Coef^[Deg];
 
679
    for J := 0 to Pred(N) do
 
680
      A^[J + 1]^[J] := 1.0;
 
681
 
 
682
    { The roots of the polynomial are the eigenvalues of the companion matrix }
 
683
    Balance(A, 0, N);
 
684
    ErrCode := Hqr(A, 0, N, X_Re, X_Im);
 
685
 
 
686
    if ErrCode = MAT_OK then
 
687
      begin
 
688
        { Sort roots in increasing order of real parts }
 
689
        for I := 0 to N - 1 do
 
690
          begin
 
691
            K := I;
 
692
            Temp := X_Re^[I];
 
693
            for J := Succ(I) to N do
 
694
              if X_Re^[J] < Temp then
 
695
                begin
 
696
                  K := J;
 
697
                  Temp := X_Re^[J];
 
698
                end;
 
699
            FSwap(X_Re^[I], X_Re^[K]);
 
700
            FSwap(X_Im^[I], X_Im^[K]);
 
701
          end;
 
702
 
 
703
        { Transfer roots from 0..(Deg - 1) to 1..Deg }
 
704
        for J := N downto 0 do
 
705
          begin
 
706
            X_Re^[J + 1] := X_Re^[J];
 
707
            X_Im^[J + 1] := X_Im^[J];
 
708
          end;
 
709
      end;
 
710
 
 
711
    DelMatrix(A, N, N);
 
712
    RootPol := ErrCode;
 
713
  end;
 
714
 
 
715
end.