Mercurial > hg > CbC > CbC_gcc
comparison gcc/ada/libgnat/a-ngrear.adb @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 ------------------------------------------------------------------------------ | |
2 -- -- | |
3 -- GNAT RUN-TIME COMPONENTS -- | |
4 -- -- | |
5 -- ADA.NUMERICS.GENERIC_REAL_ARRAYS -- | |
6 -- -- | |
7 -- B o d y -- | |
8 -- -- | |
9 -- Copyright (C) 2006-2017, Free Software Foundation, Inc. -- | |
10 -- -- | |
11 -- GNAT is free software; you can redistribute it and/or modify it under -- | |
12 -- terms of the GNU General Public License as published by the Free Soft- -- | |
13 -- ware Foundation; either version 3, or (at your option) any later ver- -- | |
14 -- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- | |
15 -- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- | |
16 -- or FITNESS FOR A PARTICULAR PURPOSE. -- | |
17 -- -- | |
18 -- As a special exception under Section 7 of GPL version 3, you are granted -- | |
19 -- additional permissions described in the GCC Runtime Library Exception, -- | |
20 -- version 3.1, as published by the Free Software Foundation. -- | |
21 -- -- | |
22 -- You should have received a copy of the GNU General Public License and -- | |
23 -- a copy of the GCC Runtime Library Exception along with this program; -- | |
24 -- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- | |
25 -- <http://www.gnu.org/licenses/>. -- | |
26 -- -- | |
27 -- GNAT was originally developed by the GNAT team at New York University. -- | |
28 -- Extensive contributions were provided by Ada Core Technologies Inc. -- | |
29 -- -- | |
30 ------------------------------------------------------------------------------ | |
31 | |
32 -- This version of Generic_Real_Arrays avoids the use of BLAS and LAPACK. One | |
33 -- reason for this is new Ada 2012 requirements that prohibit algorithms such | |
34 -- as Strassen's algorithm, which may be used by some BLAS implementations. In | |
35 -- addition, some platforms lacked suitable compilers to compile the reference | |
36 -- BLAS/LAPACK implementation. Finally, on some platforms there are more | |
37 -- floating point types than supported by BLAS/LAPACK. | |
38 | |
39 with Ada.Containers.Generic_Anonymous_Array_Sort; use Ada.Containers; | |
40 | |
41 with System; use System; | |
42 with System.Generic_Array_Operations; use System.Generic_Array_Operations; | |
43 | |
44 package body Ada.Numerics.Generic_Real_Arrays is | |
45 | |
46 package Ops renames System.Generic_Array_Operations; | |
47 | |
48 function Is_Non_Zero (X : Real'Base) return Boolean is (X /= 0.0); | |
49 | |
50 procedure Back_Substitute is new Ops.Back_Substitute | |
51 (Scalar => Real'Base, | |
52 Matrix => Real_Matrix, | |
53 Is_Non_Zero => Is_Non_Zero); | |
54 | |
55 function Diagonal is new Ops.Diagonal | |
56 (Scalar => Real'Base, | |
57 Vector => Real_Vector, | |
58 Matrix => Real_Matrix); | |
59 | |
60 procedure Forward_Eliminate is new Ops.Forward_Eliminate | |
61 (Scalar => Real'Base, | |
62 Real => Real'Base, | |
63 Matrix => Real_Matrix, | |
64 Zero => 0.0, | |
65 One => 1.0); | |
66 | |
67 procedure Swap_Column is new Ops.Swap_Column | |
68 (Scalar => Real'Base, | |
69 Matrix => Real_Matrix); | |
70 | |
71 procedure Transpose is new Ops.Transpose | |
72 (Scalar => Real'Base, | |
73 Matrix => Real_Matrix); | |
74 | |
75 function Is_Symmetric (A : Real_Matrix) return Boolean is | |
76 (Transpose (A) = A); | |
77 -- Return True iff A is symmetric, see RM G.3.1 (90). | |
78 | |
79 function Is_Tiny (Value, Compared_To : Real) return Boolean is | |
80 (abs Compared_To + 100.0 * abs (Value) = abs Compared_To); | |
81 -- Return True iff the Value is much smaller in magnitude than the least | |
82 -- significant digit of Compared_To. | |
83 | |
84 procedure Jacobi | |
85 (A : Real_Matrix; | |
86 Values : out Real_Vector; | |
87 Vectors : out Real_Matrix; | |
88 Compute_Vectors : Boolean := True); | |
89 -- Perform Jacobi's eigensystem algorithm on real symmetric matrix A | |
90 | |
91 function Length is new Square_Matrix_Length (Real'Base, Real_Matrix); | |
92 -- Helper function that raises a Constraint_Error is the argument is | |
93 -- not a square matrix, and otherwise returns its length. | |
94 | |
95 procedure Rotate (X, Y : in out Real; Sin, Tau : Real); | |
96 -- Perform a Givens rotation | |
97 | |
98 procedure Sort_Eigensystem | |
99 (Values : in out Real_Vector; | |
100 Vectors : in out Real_Matrix); | |
101 -- Sort Values and associated Vectors by decreasing absolute value | |
102 | |
103 procedure Swap (Left, Right : in out Real); | |
104 -- Exchange Left and Right | |
105 | |
106 function Sqrt is new Ops.Sqrt (Real); | |
107 -- Instant a generic square root implementation here, in order to avoid | |
108 -- instantiating a complete copy of Generic_Elementary_Functions. | |
109 -- Speed of the square root is not a big concern here. | |
110 | |
111 ------------ | |
112 -- Rotate -- | |
113 ------------ | |
114 | |
115 procedure Rotate (X, Y : in out Real; Sin, Tau : Real) is | |
116 Old_X : constant Real := X; | |
117 Old_Y : constant Real := Y; | |
118 begin | |
119 X := Old_X - Sin * (Old_Y + Old_X * Tau); | |
120 Y := Old_Y + Sin * (Old_X - Old_Y * Tau); | |
121 end Rotate; | |
122 | |
123 ---------- | |
124 -- Swap -- | |
125 ---------- | |
126 | |
127 procedure Swap (Left, Right : in out Real) is | |
128 Temp : constant Real := Left; | |
129 begin | |
130 Left := Right; | |
131 Right := Temp; | |
132 end Swap; | |
133 | |
134 -- Instantiating the following subprograms directly would lead to | |
135 -- name clashes, so use a local package. | |
136 | |
137 package Instantiations is | |
138 | |
139 function "+" is new | |
140 Vector_Elementwise_Operation | |
141 (X_Scalar => Real'Base, | |
142 Result_Scalar => Real'Base, | |
143 X_Vector => Real_Vector, | |
144 Result_Vector => Real_Vector, | |
145 Operation => "+"); | |
146 | |
147 function "+" is new | |
148 Matrix_Elementwise_Operation | |
149 (X_Scalar => Real'Base, | |
150 Result_Scalar => Real'Base, | |
151 X_Matrix => Real_Matrix, | |
152 Result_Matrix => Real_Matrix, | |
153 Operation => "+"); | |
154 | |
155 function "+" is new | |
156 Vector_Vector_Elementwise_Operation | |
157 (Left_Scalar => Real'Base, | |
158 Right_Scalar => Real'Base, | |
159 Result_Scalar => Real'Base, | |
160 Left_Vector => Real_Vector, | |
161 Right_Vector => Real_Vector, | |
162 Result_Vector => Real_Vector, | |
163 Operation => "+"); | |
164 | |
165 function "+" is new | |
166 Matrix_Matrix_Elementwise_Operation | |
167 (Left_Scalar => Real'Base, | |
168 Right_Scalar => Real'Base, | |
169 Result_Scalar => Real'Base, | |
170 Left_Matrix => Real_Matrix, | |
171 Right_Matrix => Real_Matrix, | |
172 Result_Matrix => Real_Matrix, | |
173 Operation => "+"); | |
174 | |
175 function "-" is new | |
176 Vector_Elementwise_Operation | |
177 (X_Scalar => Real'Base, | |
178 Result_Scalar => Real'Base, | |
179 X_Vector => Real_Vector, | |
180 Result_Vector => Real_Vector, | |
181 Operation => "-"); | |
182 | |
183 function "-" is new | |
184 Matrix_Elementwise_Operation | |
185 (X_Scalar => Real'Base, | |
186 Result_Scalar => Real'Base, | |
187 X_Matrix => Real_Matrix, | |
188 Result_Matrix => Real_Matrix, | |
189 Operation => "-"); | |
190 | |
191 function "-" is new | |
192 Vector_Vector_Elementwise_Operation | |
193 (Left_Scalar => Real'Base, | |
194 Right_Scalar => Real'Base, | |
195 Result_Scalar => Real'Base, | |
196 Left_Vector => Real_Vector, | |
197 Right_Vector => Real_Vector, | |
198 Result_Vector => Real_Vector, | |
199 Operation => "-"); | |
200 | |
201 function "-" is new | |
202 Matrix_Matrix_Elementwise_Operation | |
203 (Left_Scalar => Real'Base, | |
204 Right_Scalar => Real'Base, | |
205 Result_Scalar => Real'Base, | |
206 Left_Matrix => Real_Matrix, | |
207 Right_Matrix => Real_Matrix, | |
208 Result_Matrix => Real_Matrix, | |
209 Operation => "-"); | |
210 | |
211 function "*" is new | |
212 Scalar_Vector_Elementwise_Operation | |
213 (Left_Scalar => Real'Base, | |
214 Right_Scalar => Real'Base, | |
215 Result_Scalar => Real'Base, | |
216 Right_Vector => Real_Vector, | |
217 Result_Vector => Real_Vector, | |
218 Operation => "*"); | |
219 | |
220 function "*" is new | |
221 Scalar_Matrix_Elementwise_Operation | |
222 (Left_Scalar => Real'Base, | |
223 Right_Scalar => Real'Base, | |
224 Result_Scalar => Real'Base, | |
225 Right_Matrix => Real_Matrix, | |
226 Result_Matrix => Real_Matrix, | |
227 Operation => "*"); | |
228 | |
229 function "*" is new | |
230 Vector_Scalar_Elementwise_Operation | |
231 (Left_Scalar => Real'Base, | |
232 Right_Scalar => Real'Base, | |
233 Result_Scalar => Real'Base, | |
234 Left_Vector => Real_Vector, | |
235 Result_Vector => Real_Vector, | |
236 Operation => "*"); | |
237 | |
238 function "*" is new | |
239 Matrix_Scalar_Elementwise_Operation | |
240 (Left_Scalar => Real'Base, | |
241 Right_Scalar => Real'Base, | |
242 Result_Scalar => Real'Base, | |
243 Left_Matrix => Real_Matrix, | |
244 Result_Matrix => Real_Matrix, | |
245 Operation => "*"); | |
246 | |
247 function "*" is new | |
248 Outer_Product | |
249 (Left_Scalar => Real'Base, | |
250 Right_Scalar => Real'Base, | |
251 Result_Scalar => Real'Base, | |
252 Left_Vector => Real_Vector, | |
253 Right_Vector => Real_Vector, | |
254 Matrix => Real_Matrix); | |
255 | |
256 function "*" is new | |
257 Inner_Product | |
258 (Left_Scalar => Real'Base, | |
259 Right_Scalar => Real'Base, | |
260 Result_Scalar => Real'Base, | |
261 Left_Vector => Real_Vector, | |
262 Right_Vector => Real_Vector, | |
263 Zero => 0.0); | |
264 | |
265 function "*" is new | |
266 Matrix_Vector_Product | |
267 (Left_Scalar => Real'Base, | |
268 Right_Scalar => Real'Base, | |
269 Result_Scalar => Real'Base, | |
270 Matrix => Real_Matrix, | |
271 Right_Vector => Real_Vector, | |
272 Result_Vector => Real_Vector, | |
273 Zero => 0.0); | |
274 | |
275 function "*" is new | |
276 Vector_Matrix_Product | |
277 (Left_Scalar => Real'Base, | |
278 Right_Scalar => Real'Base, | |
279 Result_Scalar => Real'Base, | |
280 Left_Vector => Real_Vector, | |
281 Matrix => Real_Matrix, | |
282 Result_Vector => Real_Vector, | |
283 Zero => 0.0); | |
284 | |
285 function "*" is new | |
286 Matrix_Matrix_Product | |
287 (Left_Scalar => Real'Base, | |
288 Right_Scalar => Real'Base, | |
289 Result_Scalar => Real'Base, | |
290 Left_Matrix => Real_Matrix, | |
291 Right_Matrix => Real_Matrix, | |
292 Result_Matrix => Real_Matrix, | |
293 Zero => 0.0); | |
294 | |
295 function "/" is new | |
296 Vector_Scalar_Elementwise_Operation | |
297 (Left_Scalar => Real'Base, | |
298 Right_Scalar => Real'Base, | |
299 Result_Scalar => Real'Base, | |
300 Left_Vector => Real_Vector, | |
301 Result_Vector => Real_Vector, | |
302 Operation => "/"); | |
303 | |
304 function "/" is new | |
305 Matrix_Scalar_Elementwise_Operation | |
306 (Left_Scalar => Real'Base, | |
307 Right_Scalar => Real'Base, | |
308 Result_Scalar => Real'Base, | |
309 Left_Matrix => Real_Matrix, | |
310 Result_Matrix => Real_Matrix, | |
311 Operation => "/"); | |
312 | |
313 function "abs" is new | |
314 L2_Norm | |
315 (X_Scalar => Real'Base, | |
316 Result_Real => Real'Base, | |
317 X_Vector => Real_Vector, | |
318 "abs" => "+"); | |
319 -- While the L2_Norm by definition uses the absolute values of the | |
320 -- elements of X_Vector, for real values the subsequent squaring | |
321 -- makes this unnecessary, so we substitute the "+" identity function | |
322 -- instead. | |
323 | |
324 function "abs" is new | |
325 Vector_Elementwise_Operation | |
326 (X_Scalar => Real'Base, | |
327 Result_Scalar => Real'Base, | |
328 X_Vector => Real_Vector, | |
329 Result_Vector => Real_Vector, | |
330 Operation => "abs"); | |
331 | |
332 function "abs" is new | |
333 Matrix_Elementwise_Operation | |
334 (X_Scalar => Real'Base, | |
335 Result_Scalar => Real'Base, | |
336 X_Matrix => Real_Matrix, | |
337 Result_Matrix => Real_Matrix, | |
338 Operation => "abs"); | |
339 | |
340 function Solve is new | |
341 Matrix_Vector_Solution (Real'Base, 0.0, Real_Vector, Real_Matrix); | |
342 | |
343 function Solve is new | |
344 Matrix_Matrix_Solution (Real'Base, 0.0, Real_Matrix); | |
345 | |
346 function Unit_Matrix is new | |
347 Generic_Array_Operations.Unit_Matrix | |
348 (Scalar => Real'Base, | |
349 Matrix => Real_Matrix, | |
350 Zero => 0.0, | |
351 One => 1.0); | |
352 | |
353 function Unit_Vector is new | |
354 Generic_Array_Operations.Unit_Vector | |
355 (Scalar => Real'Base, | |
356 Vector => Real_Vector, | |
357 Zero => 0.0, | |
358 One => 1.0); | |
359 | |
360 end Instantiations; | |
361 | |
362 --------- | |
363 -- "+" -- | |
364 --------- | |
365 | |
366 function "+" (Right : Real_Vector) return Real_Vector | |
367 renames Instantiations."+"; | |
368 | |
369 function "+" (Right : Real_Matrix) return Real_Matrix | |
370 renames Instantiations."+"; | |
371 | |
372 function "+" (Left, Right : Real_Vector) return Real_Vector | |
373 renames Instantiations."+"; | |
374 | |
375 function "+" (Left, Right : Real_Matrix) return Real_Matrix | |
376 renames Instantiations."+"; | |
377 | |
378 --------- | |
379 -- "-" -- | |
380 --------- | |
381 | |
382 function "-" (Right : Real_Vector) return Real_Vector | |
383 renames Instantiations."-"; | |
384 | |
385 function "-" (Right : Real_Matrix) return Real_Matrix | |
386 renames Instantiations."-"; | |
387 | |
388 function "-" (Left, Right : Real_Vector) return Real_Vector | |
389 renames Instantiations."-"; | |
390 | |
391 function "-" (Left, Right : Real_Matrix) return Real_Matrix | |
392 renames Instantiations."-"; | |
393 | |
394 --------- | |
395 -- "*" -- | |
396 --------- | |
397 | |
398 -- Scalar multiplication | |
399 | |
400 function "*" (Left : Real'Base; Right : Real_Vector) return Real_Vector | |
401 renames Instantiations."*"; | |
402 | |
403 function "*" (Left : Real_Vector; Right : Real'Base) return Real_Vector | |
404 renames Instantiations."*"; | |
405 | |
406 function "*" (Left : Real'Base; Right : Real_Matrix) return Real_Matrix | |
407 renames Instantiations."*"; | |
408 | |
409 function "*" (Left : Real_Matrix; Right : Real'Base) return Real_Matrix | |
410 renames Instantiations."*"; | |
411 | |
412 -- Vector multiplication | |
413 | |
414 function "*" (Left, Right : Real_Vector) return Real'Base | |
415 renames Instantiations."*"; | |
416 | |
417 function "*" (Left, Right : Real_Vector) return Real_Matrix | |
418 renames Instantiations."*"; | |
419 | |
420 function "*" (Left : Real_Vector; Right : Real_Matrix) return Real_Vector | |
421 renames Instantiations."*"; | |
422 | |
423 function "*" (Left : Real_Matrix; Right : Real_Vector) return Real_Vector | |
424 renames Instantiations."*"; | |
425 | |
426 -- Matrix Multiplication | |
427 | |
428 function "*" (Left, Right : Real_Matrix) return Real_Matrix | |
429 renames Instantiations."*"; | |
430 | |
431 --------- | |
432 -- "/" -- | |
433 --------- | |
434 | |
435 function "/" (Left : Real_Vector; Right : Real'Base) return Real_Vector | |
436 renames Instantiations."/"; | |
437 | |
438 function "/" (Left : Real_Matrix; Right : Real'Base) return Real_Matrix | |
439 renames Instantiations."/"; | |
440 | |
441 ----------- | |
442 -- "abs" -- | |
443 ----------- | |
444 | |
445 function "abs" (Right : Real_Vector) return Real'Base | |
446 renames Instantiations."abs"; | |
447 | |
448 function "abs" (Right : Real_Vector) return Real_Vector | |
449 renames Instantiations."abs"; | |
450 | |
451 function "abs" (Right : Real_Matrix) return Real_Matrix | |
452 renames Instantiations."abs"; | |
453 | |
454 ----------------- | |
455 -- Determinant -- | |
456 ----------------- | |
457 | |
458 function Determinant (A : Real_Matrix) return Real'Base is | |
459 M : Real_Matrix := A; | |
460 B : Real_Matrix (A'Range (1), 1 .. 0); | |
461 R : Real'Base; | |
462 begin | |
463 Forward_Eliminate (M, B, R); | |
464 return R; | |
465 end Determinant; | |
466 | |
467 ----------------- | |
468 -- Eigensystem -- | |
469 ----------------- | |
470 | |
471 procedure Eigensystem | |
472 (A : Real_Matrix; | |
473 Values : out Real_Vector; | |
474 Vectors : out Real_Matrix) | |
475 is | |
476 begin | |
477 Jacobi (A, Values, Vectors, Compute_Vectors => True); | |
478 Sort_Eigensystem (Values, Vectors); | |
479 end Eigensystem; | |
480 | |
481 ----------------- | |
482 -- Eigenvalues -- | |
483 ----------------- | |
484 | |
485 function Eigenvalues (A : Real_Matrix) return Real_Vector is | |
486 begin | |
487 return Values : Real_Vector (A'Range (1)) do | |
488 declare | |
489 Vectors : Real_Matrix (1 .. 0, 1 .. 0); | |
490 begin | |
491 Jacobi (A, Values, Vectors, Compute_Vectors => False); | |
492 Sort_Eigensystem (Values, Vectors); | |
493 end; | |
494 end return; | |
495 end Eigenvalues; | |
496 | |
497 ------------- | |
498 -- Inverse -- | |
499 ------------- | |
500 | |
501 function Inverse (A : Real_Matrix) return Real_Matrix is | |
502 (Solve (A, Unit_Matrix (Length (A), | |
503 First_1 => A'First (2), | |
504 First_2 => A'First (1)))); | |
505 | |
506 ------------ | |
507 -- Jacobi -- | |
508 ------------ | |
509 | |
510 procedure Jacobi | |
511 (A : Real_Matrix; | |
512 Values : out Real_Vector; | |
513 Vectors : out Real_Matrix; | |
514 Compute_Vectors : Boolean := True) | |
515 is | |
516 -- This subprogram uses Carl Gustav Jacob Jacobi's iterative method | |
517 -- for computing eigenvalues and eigenvectors and is based on | |
518 -- Rutishauser's implementation. | |
519 | |
520 -- The given real symmetric matrix is transformed iteratively to | |
521 -- diagonal form through a sequence of appropriately chosen elementary | |
522 -- orthogonal transformations, called Jacobi rotations here. | |
523 | |
524 -- The Jacobi method produces a systematic decrease of the sum of the | |
525 -- squares of off-diagonal elements. Convergence to zero is quadratic, | |
526 -- both for this implementation, as for the classic method that doesn't | |
527 -- use row-wise scanning for pivot selection. | |
528 | |
529 -- The numerical stability and accuracy of Jacobi's method make it the | |
530 -- best choice here, even though for large matrices other methods will | |
531 -- be significantly more efficient in both time and space. | |
532 | |
533 -- While the eigensystem computations are absolutely foolproof for all | |
534 -- real symmetric matrices, in presence of invalid values, or similar | |
535 -- exceptional situations it might not. In such cases the results cannot | |
536 -- be trusted and Constraint_Error is raised. | |
537 | |
538 -- Note: this implementation needs temporary storage for 2 * N + N**2 | |
539 -- values of type Real. | |
540 | |
541 Max_Iterations : constant := 50; | |
542 N : constant Natural := Length (A); | |
543 | |
544 subtype Square_Matrix is Real_Matrix (1 .. N, 1 .. N); | |
545 | |
546 -- In order to annihilate the M (Row, Col) element, the | |
547 -- rotation parameters Cos and Sin are computed as | |
548 -- follows: | |
549 | |
550 -- Theta = Cot (2.0 * Phi) | |
551 -- = (Diag (Col) - Diag (Row)) / (2.0 * M (Row, Col)) | |
552 | |
553 -- Then Tan (Phi) as the smaller root (in modulus) of | |
554 | |
555 -- T**2 + 2 * T * Theta = 1 (or 0.5 / Theta, if Theta is large) | |
556 | |
557 function Compute_Tan (Theta : Real) return Real is | |
558 (Real'Copy_Sign (1.0 / (abs Theta + Sqrt (1.0 + Theta**2)), Theta)); | |
559 | |
560 function Compute_Tan (P, H : Real) return Real is | |
561 (if Is_Tiny (P, Compared_To => H) then P / H | |
562 else Compute_Tan (Theta => H / (2.0 * P))); | |
563 | |
564 function Sum_Strict_Upper (M : Square_Matrix) return Real; | |
565 -- Return the sum of all elements in the strict upper triangle of M | |
566 | |
567 ---------------------- | |
568 -- Sum_Strict_Upper -- | |
569 ---------------------- | |
570 | |
571 function Sum_Strict_Upper (M : Square_Matrix) return Real is | |
572 Sum : Real := 0.0; | |
573 | |
574 begin | |
575 for Row in 1 .. N - 1 loop | |
576 for Col in Row + 1 .. N loop | |
577 Sum := Sum + abs M (Row, Col); | |
578 end loop; | |
579 end loop; | |
580 | |
581 return Sum; | |
582 end Sum_Strict_Upper; | |
583 | |
584 M : Square_Matrix := A; -- Work space for solving eigensystem | |
585 Threshold : Real; | |
586 Sum : Real; | |
587 Diag : Real_Vector (1 .. N); | |
588 Diag_Adj : Real_Vector (1 .. N); | |
589 | |
590 -- The vector Diag_Adj indicates the amount of change in each value, | |
591 -- while Diag tracks the value itself and Values holds the values as | |
592 -- they were at the beginning. As the changes typically will be small | |
593 -- compared to the absolute value of Diag, at the end of each iteration | |
594 -- Diag is computed as Diag + Diag_Adj thus avoiding accumulating | |
595 -- rounding errors. This technique is due to Rutishauser. | |
596 | |
597 begin | |
598 if Compute_Vectors | |
599 and then (Vectors'Length (1) /= N or else Vectors'Length (2) /= N) | |
600 then | |
601 raise Constraint_Error with "incompatible matrix dimensions"; | |
602 | |
603 elsif Values'Length /= N then | |
604 raise Constraint_Error with "incompatible vector length"; | |
605 | |
606 elsif not Is_Symmetric (M) then | |
607 raise Constraint_Error with "matrix not symmetric"; | |
608 end if; | |
609 | |
610 -- Note: Only the locally declared matrix M and vectors (Diag, Diag_Adj) | |
611 -- have lower bound equal to 1. The Vectors matrix may have | |
612 -- different bounds, so take care indexing elements. Assignment | |
613 -- as a whole is fine as sliding is automatic in that case. | |
614 | |
615 Vectors := (if not Compute_Vectors then (1 .. 0 => (1 .. 0 => 0.0)) | |
616 else Unit_Matrix (Vectors'Length (1), Vectors'Length (2))); | |
617 Values := Diagonal (M); | |
618 | |
619 Sweep : for Iteration in 1 .. Max_Iterations loop | |
620 | |
621 -- The first three iterations, perform rotation for any non-zero | |
622 -- element. After this, rotate only for those that are not much | |
623 -- smaller than the average off-diagnal element. After the fifth | |
624 -- iteration, additionally zero out off-diagonal elements that are | |
625 -- very small compared to elements on the diagonal with the same | |
626 -- column or row index. | |
627 | |
628 Sum := Sum_Strict_Upper (M); | |
629 | |
630 exit Sweep when Sum = 0.0; | |
631 | |
632 Threshold := (if Iteration < 4 then 0.2 * Sum / Real (N**2) else 0.0); | |
633 | |
634 -- Iterate over all off-diagonal elements, rotating any that have | |
635 -- an absolute value that exceeds the threshold. | |
636 | |
637 Diag := Values; | |
638 Diag_Adj := (others => 0.0); -- Accumulates adjustments to Diag | |
639 | |
640 for Row in 1 .. N - 1 loop | |
641 for Col in Row + 1 .. N loop | |
642 | |
643 -- If, before the rotation M (Row, Col) is tiny compared to | |
644 -- Diag (Row) and Diag (Col), rotation is skipped. This is | |
645 -- meaningful, as it produces no larger error than would be | |
646 -- produced anyhow if the rotation had been performed. | |
647 -- Suppress this optimization in the first four sweeps, so | |
648 -- that this procedure can be used for computing eigenvectors | |
649 -- of perturbed diagonal matrices. | |
650 | |
651 if Iteration > 4 | |
652 and then Is_Tiny (M (Row, Col), Compared_To => Diag (Row)) | |
653 and then Is_Tiny (M (Row, Col), Compared_To => Diag (Col)) | |
654 then | |
655 M (Row, Col) := 0.0; | |
656 | |
657 elsif abs M (Row, Col) > Threshold then | |
658 Perform_Rotation : declare | |
659 Tan : constant Real := Compute_Tan (M (Row, Col), | |
660 Diag (Col) - Diag (Row)); | |
661 Cos : constant Real := 1.0 / Sqrt (1.0 + Tan**2); | |
662 Sin : constant Real := Tan * Cos; | |
663 Tau : constant Real := Sin / (1.0 + Cos); | |
664 Adj : constant Real := Tan * M (Row, Col); | |
665 | |
666 begin | |
667 Diag_Adj (Row) := Diag_Adj (Row) - Adj; | |
668 Diag_Adj (Col) := Diag_Adj (Col) + Adj; | |
669 Diag (Row) := Diag (Row) - Adj; | |
670 Diag (Col) := Diag (Col) + Adj; | |
671 | |
672 M (Row, Col) := 0.0; | |
673 | |
674 for J in 1 .. Row - 1 loop -- 1 <= J < Row | |
675 Rotate (M (J, Row), M (J, Col), Sin, Tau); | |
676 end loop; | |
677 | |
678 for J in Row + 1 .. Col - 1 loop -- Row < J < Col | |
679 Rotate (M (Row, J), M (J, Col), Sin, Tau); | |
680 end loop; | |
681 | |
682 for J in Col + 1 .. N loop -- Col < J <= N | |
683 Rotate (M (Row, J), M (Col, J), Sin, Tau); | |
684 end loop; | |
685 | |
686 for J in Vectors'Range (1) loop | |
687 Rotate (Vectors (J, Row - 1 + Vectors'First (2)), | |
688 Vectors (J, Col - 1 + Vectors'First (2)), | |
689 Sin, Tau); | |
690 end loop; | |
691 end Perform_Rotation; | |
692 end if; | |
693 end loop; | |
694 end loop; | |
695 | |
696 Values := Values + Diag_Adj; | |
697 end loop Sweep; | |
698 | |
699 -- All normal matrices with valid values should converge perfectly. | |
700 | |
701 if Sum /= 0.0 then | |
702 raise Constraint_Error with "eigensystem solution does not converge"; | |
703 end if; | |
704 end Jacobi; | |
705 | |
706 ----------- | |
707 -- Solve -- | |
708 ----------- | |
709 | |
710 function Solve (A : Real_Matrix; X : Real_Vector) return Real_Vector | |
711 renames Instantiations.Solve; | |
712 | |
713 function Solve (A, X : Real_Matrix) return Real_Matrix | |
714 renames Instantiations.Solve; | |
715 | |
716 ---------------------- | |
717 -- Sort_Eigensystem -- | |
718 ---------------------- | |
719 | |
720 procedure Sort_Eigensystem | |
721 (Values : in out Real_Vector; | |
722 Vectors : in out Real_Matrix) | |
723 is | |
724 procedure Swap (Left, Right : Integer); | |
725 -- Swap Values (Left) with Values (Right), and also swap the | |
726 -- corresponding eigenvectors. Note that lowerbounds may differ. | |
727 | |
728 function Less (Left, Right : Integer) return Boolean is | |
729 (Values (Left) > Values (Right)); | |
730 -- Sort by decreasing eigenvalue, see RM G.3.1 (76). | |
731 | |
732 procedure Sort is new Generic_Anonymous_Array_Sort (Integer); | |
733 -- Sorts eigenvalues and eigenvectors by decreasing value | |
734 | |
735 procedure Swap (Left, Right : Integer) is | |
736 begin | |
737 Swap (Values (Left), Values (Right)); | |
738 Swap_Column (Vectors, Left - Values'First + Vectors'First (2), | |
739 Right - Values'First + Vectors'First (2)); | |
740 end Swap; | |
741 | |
742 begin | |
743 Sort (Values'First, Values'Last); | |
744 end Sort_Eigensystem; | |
745 | |
746 --------------- | |
747 -- Transpose -- | |
748 --------------- | |
749 | |
750 function Transpose (X : Real_Matrix) return Real_Matrix is | |
751 begin | |
752 return R : Real_Matrix (X'Range (2), X'Range (1)) do | |
753 Transpose (X, R); | |
754 end return; | |
755 end Transpose; | |
756 | |
757 ----------------- | |
758 -- Unit_Matrix -- | |
759 ----------------- | |
760 | |
761 function Unit_Matrix | |
762 (Order : Positive; | |
763 First_1 : Integer := 1; | |
764 First_2 : Integer := 1) return Real_Matrix | |
765 renames Instantiations.Unit_Matrix; | |
766 | |
767 ----------------- | |
768 -- Unit_Vector -- | |
769 ----------------- | |
770 | |
771 function Unit_Vector | |
772 (Index : Integer; | |
773 Order : Positive; | |
774 First : Integer := 1) return Real_Vector | |
775 renames Instantiations.Unit_Vector; | |
776 | |
777 end Ada.Numerics.Generic_Real_Arrays; |