2011-06-29 François Dumont <francois.cppdevs@free.fr>
[official-gcc.git] / gcc / ada / a-ngrear.adb
blob5c8a0092477a66f82c87b08806d23c1ae1bce248
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-2009, 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 ------------------------------------------------------------------------------
32 with System; use System;
33 with System.Generic_Real_BLAS;
34 with System.Generic_Real_LAPACK;
35 with System.Generic_Array_Operations; use System.Generic_Array_Operations;
37 package body Ada.Numerics.Generic_Real_Arrays is
39 -- Operations involving inner products use BLAS library implementations.
40 -- This allows larger matrices and vectors to be computed efficiently,
41 -- taking into account memory hierarchy issues and vector instructions
42 -- that vary widely between machines.
44 -- Operations that are defined in terms of operations on the type Real,
45 -- such as addition, subtraction and scaling, are computed in the canonical
46 -- way looping over all elements.
48 -- Operations for solving linear systems and computing determinant,
49 -- eigenvalues, eigensystem and inverse, are implemented using the
50 -- LAPACK library.
52 package BLAS is
53 new Generic_Real_BLAS (Real'Base, Real_Vector, Real_Matrix);
55 package LAPACK is
56 new Generic_Real_LAPACK (Real'Base, Real_Vector, Real_Matrix);
58 use BLAS, LAPACK;
60 -- Procedure versions of functions returning unconstrained values.
61 -- This allows for inlining the function wrapper.
63 procedure Eigenvalues (A : Real_Matrix; Values : out Real_Vector);
64 procedure Inverse (A : Real_Matrix; R : out Real_Matrix);
65 procedure Solve (A : Real_Matrix; X : Real_Vector; B : out Real_Vector);
66 procedure Solve (A : Real_Matrix; X : Real_Matrix; B : out Real_Matrix);
68 procedure Transpose is new
69 Generic_Array_Operations.Transpose
70 (Scalar => Real'Base,
71 Matrix => Real_Matrix);
73 -- Helper function that raises a Constraint_Error is the argument is
74 -- not a square matrix, and otherwise returns its length.
76 function Length is new Square_Matrix_Length (Real'Base, Real_Matrix);
78 -- Instantiating the following subprograms directly would lead to
79 -- name clashes, so use a local package.
81 package Instantiations is
83 function "+" is new
84 Vector_Elementwise_Operation
85 (X_Scalar => Real'Base,
86 Result_Scalar => Real'Base,
87 X_Vector => Real_Vector,
88 Result_Vector => Real_Vector,
89 Operation => "+");
91 function "+" is new
92 Matrix_Elementwise_Operation
93 (X_Scalar => Real'Base,
94 Result_Scalar => Real'Base,
95 X_Matrix => Real_Matrix,
96 Result_Matrix => Real_Matrix,
97 Operation => "+");
99 function "+" is new
100 Vector_Vector_Elementwise_Operation
101 (Left_Scalar => Real'Base,
102 Right_Scalar => Real'Base,
103 Result_Scalar => Real'Base,
104 Left_Vector => Real_Vector,
105 Right_Vector => Real_Vector,
106 Result_Vector => Real_Vector,
107 Operation => "+");
109 function "+" is new
110 Matrix_Matrix_Elementwise_Operation
111 (Left_Scalar => Real'Base,
112 Right_Scalar => Real'Base,
113 Result_Scalar => Real'Base,
114 Left_Matrix => Real_Matrix,
115 Right_Matrix => Real_Matrix,
116 Result_Matrix => Real_Matrix,
117 Operation => "+");
119 function "-" is new
120 Vector_Elementwise_Operation
121 (X_Scalar => Real'Base,
122 Result_Scalar => Real'Base,
123 X_Vector => Real_Vector,
124 Result_Vector => Real_Vector,
125 Operation => "-");
127 function "-" is new
128 Matrix_Elementwise_Operation
129 (X_Scalar => Real'Base,
130 Result_Scalar => Real'Base,
131 X_Matrix => Real_Matrix,
132 Result_Matrix => Real_Matrix,
133 Operation => "-");
135 function "-" is new
136 Vector_Vector_Elementwise_Operation
137 (Left_Scalar => Real'Base,
138 Right_Scalar => Real'Base,
139 Result_Scalar => Real'Base,
140 Left_Vector => Real_Vector,
141 Right_Vector => Real_Vector,
142 Result_Vector => Real_Vector,
143 Operation => "-");
145 function "-" is new
146 Matrix_Matrix_Elementwise_Operation
147 (Left_Scalar => Real'Base,
148 Right_Scalar => Real'Base,
149 Result_Scalar => Real'Base,
150 Left_Matrix => Real_Matrix,
151 Right_Matrix => Real_Matrix,
152 Result_Matrix => Real_Matrix,
153 Operation => "-");
155 function "*" is new
156 Scalar_Vector_Elementwise_Operation
157 (Left_Scalar => Real'Base,
158 Right_Scalar => Real'Base,
159 Result_Scalar => Real'Base,
160 Right_Vector => Real_Vector,
161 Result_Vector => Real_Vector,
162 Operation => "*");
164 function "*" is new
165 Scalar_Matrix_Elementwise_Operation
166 (Left_Scalar => Real'Base,
167 Right_Scalar => Real'Base,
168 Result_Scalar => Real'Base,
169 Right_Matrix => Real_Matrix,
170 Result_Matrix => Real_Matrix,
171 Operation => "*");
173 function "*" is new
174 Vector_Scalar_Elementwise_Operation
175 (Left_Scalar => Real'Base,
176 Right_Scalar => Real'Base,
177 Result_Scalar => Real'Base,
178 Left_Vector => Real_Vector,
179 Result_Vector => Real_Vector,
180 Operation => "*");
182 function "*" is new
183 Matrix_Scalar_Elementwise_Operation
184 (Left_Scalar => Real'Base,
185 Right_Scalar => Real'Base,
186 Result_Scalar => Real'Base,
187 Left_Matrix => Real_Matrix,
188 Result_Matrix => Real_Matrix,
189 Operation => "*");
191 function "*" is new
192 Outer_Product
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 Matrix => Real_Matrix);
200 function "/" is new
201 Vector_Scalar_Elementwise_Operation
202 (Left_Scalar => Real'Base,
203 Right_Scalar => Real'Base,
204 Result_Scalar => Real'Base,
205 Left_Vector => Real_Vector,
206 Result_Vector => Real_Vector,
207 Operation => "/");
209 function "/" is new
210 Matrix_Scalar_Elementwise_Operation
211 (Left_Scalar => Real'Base,
212 Right_Scalar => Real'Base,
213 Result_Scalar => Real'Base,
214 Left_Matrix => Real_Matrix,
215 Result_Matrix => Real_Matrix,
216 Operation => "/");
218 function "abs" is new
219 Vector_Elementwise_Operation
220 (X_Scalar => Real'Base,
221 Result_Scalar => Real'Base,
222 X_Vector => Real_Vector,
223 Result_Vector => Real_Vector,
224 Operation => "abs");
226 function "abs" is new
227 Matrix_Elementwise_Operation
228 (X_Scalar => Real'Base,
229 Result_Scalar => Real'Base,
230 X_Matrix => Real_Matrix,
231 Result_Matrix => Real_Matrix,
232 Operation => "abs");
234 function Unit_Matrix is new
235 Generic_Array_Operations.Unit_Matrix
236 (Scalar => Real'Base,
237 Matrix => Real_Matrix,
238 Zero => 0.0,
239 One => 1.0);
241 function Unit_Vector is new
242 Generic_Array_Operations.Unit_Vector
243 (Scalar => Real'Base,
244 Vector => Real_Vector,
245 Zero => 0.0,
246 One => 1.0);
248 end Instantiations;
250 ---------
251 -- "+" --
252 ---------
254 function "+" (Right : Real_Vector) return Real_Vector
255 renames Instantiations."+";
257 function "+" (Right : Real_Matrix) return Real_Matrix
258 renames Instantiations."+";
260 function "+" (Left, Right : Real_Vector) return Real_Vector
261 renames Instantiations."+";
263 function "+" (Left, Right : Real_Matrix) return Real_Matrix
264 renames Instantiations."+";
266 ---------
267 -- "-" --
268 ---------
270 function "-" (Right : Real_Vector) return Real_Vector
271 renames Instantiations."-";
273 function "-" (Right : Real_Matrix) return Real_Matrix
274 renames Instantiations."-";
276 function "-" (Left, Right : Real_Vector) return Real_Vector
277 renames Instantiations."-";
279 function "-" (Left, Right : Real_Matrix) return Real_Matrix
280 renames Instantiations."-";
282 ---------
283 -- "*" --
284 ---------
286 -- Scalar multiplication
288 function "*" (Left : Real'Base; Right : Real_Vector) return Real_Vector
289 renames Instantiations."*";
291 function "*" (Left : Real_Vector; Right : Real'Base) return Real_Vector
292 renames Instantiations."*";
294 function "*" (Left : Real'Base; Right : Real_Matrix) return Real_Matrix
295 renames Instantiations."*";
297 function "*" (Left : Real_Matrix; Right : Real'Base) return Real_Matrix
298 renames Instantiations."*";
300 -- Vector multiplication
302 function "*" (Left, Right : Real_Vector) return Real'Base is
303 begin
304 if Left'Length /= Right'Length then
305 raise Constraint_Error with
306 "vectors are of different length in inner product";
307 end if;
309 return dot (Left'Length, X => Left, Y => Right);
310 end "*";
312 function "*" (Left, Right : Real_Vector) return Real_Matrix
313 renames Instantiations."*";
315 function "*"
316 (Left : Real_Vector;
317 Right : Real_Matrix) return Real_Vector
319 R : Real_Vector (Right'Range (2));
321 begin
322 if Left'Length /= Right'Length (1) then
323 raise Constraint_Error with
324 "incompatible dimensions in vector-matrix multiplication";
325 end if;
327 gemv (Trans => No_Trans'Access,
328 M => Right'Length (2),
329 N => Right'Length (1),
330 A => Right,
331 Ld_A => Right'Length (2),
332 X => Left,
333 Y => R);
335 return R;
336 end "*";
338 function "*"
339 (Left : Real_Matrix;
340 Right : Real_Vector) return Real_Vector
342 R : Real_Vector (Left'Range (1));
344 begin
345 if Left'Length (2) /= Right'Length then
346 raise Constraint_Error with
347 "incompatible dimensions in matrix-vector multiplication";
348 end if;
350 gemv (Trans => Trans'Access,
351 M => Left'Length (2),
352 N => Left'Length (1),
353 A => Left,
354 Ld_A => Left'Length (2),
355 X => Right,
356 Y => R);
358 return R;
359 end "*";
361 -- Matrix Multiplication
363 function "*" (Left, Right : Real_Matrix) return Real_Matrix is
364 R : Real_Matrix (Left'Range (1), Right'Range (2));
366 begin
367 if Left'Length (2) /= Right'Length (1) then
368 raise Constraint_Error with
369 "incompatible dimensions in matrix-matrix multiplication";
370 end if;
372 gemm (Trans_A => No_Trans'Access,
373 Trans_B => No_Trans'Access,
374 M => Right'Length (2),
375 N => Left'Length (1),
376 K => Right'Length (1),
377 A => Right,
378 Ld_A => Right'Length (2),
379 B => Left,
380 Ld_B => Left'Length (2),
381 C => R,
382 Ld_C => R'Length (2));
384 return R;
385 end "*";
387 ---------
388 -- "/" --
389 ---------
391 function "/" (Left : Real_Vector; Right : Real'Base) return Real_Vector
392 renames Instantiations."/";
394 function "/" (Left : Real_Matrix; Right : Real'Base) return Real_Matrix
395 renames Instantiations."/";
397 -----------
398 -- "abs" --
399 -----------
401 function "abs" (Right : Real_Vector) return Real'Base is
402 begin
403 return nrm2 (Right'Length, Right);
404 end "abs";
406 function "abs" (Right : Real_Vector) return Real_Vector
407 renames Instantiations."abs";
409 function "abs" (Right : Real_Matrix) return Real_Matrix
410 renames Instantiations."abs";
412 -----------------
413 -- Determinant --
414 -----------------
416 function Determinant (A : Real_Matrix) return Real'Base is
417 N : constant Integer := Length (A);
418 LU : Real_Matrix (1 .. N, 1 .. N) := A;
419 Piv : Integer_Vector (1 .. N);
420 Info : aliased Integer := -1;
421 Det : Real := 1.0;
423 begin
424 getrf (M => N,
425 N => N,
426 A => LU,
427 Ld_A => N,
428 I_Piv => Piv,
429 Info => Info'Access);
431 if Info /= 0 then
432 raise Constraint_Error with "ill-conditioned matrix";
433 end if;
435 for J in 1 .. N loop
436 Det := (if Piv (J) /= J then -Det * LU (J, J) else Det * LU (J, J));
437 end loop;
439 return Det;
440 end Determinant;
442 -----------------
443 -- Eigensystem --
444 -----------------
446 procedure Eigensystem
447 (A : Real_Matrix;
448 Values : out Real_Vector;
449 Vectors : out Real_Matrix)
451 N : constant Natural := Length (A);
452 Tau : Real_Vector (1 .. N);
453 L_Work : Real_Vector (1 .. 1);
454 Info : aliased Integer;
456 E : Real_Vector (1 .. N);
457 pragma Warnings (Off, E);
459 begin
460 if Values'Length /= N then
461 raise Constraint_Error with "wrong length for output vector";
462 end if;
464 if N = 0 then
465 return;
466 end if;
468 -- Initialize working matrix and check for symmetric input matrix
470 Transpose (A, Vectors);
472 if A /= Vectors then
473 raise Argument_Error with "matrix not symmetric";
474 end if;
476 -- Compute size of additional working space
478 sytrd (Uplo => Lower'Access,
479 N => N,
480 A => Vectors,
481 Ld_A => N,
482 D => Values,
483 E => E,
484 Tau => Tau,
485 Work => L_Work,
486 L_Work => -1,
487 Info => Info'Access);
489 declare
490 Work : Real_Vector (1 .. Integer'Max (Integer (L_Work (1)), 2 * N));
491 pragma Warnings (Off, Work);
493 Comp_Z : aliased constant Character := 'V';
495 begin
496 -- Reduce matrix to tridiagonal form
498 sytrd (Uplo => Lower'Access,
499 N => N,
500 A => Vectors,
501 Ld_A => A'Length (1),
502 D => Values,
503 E => E,
504 Tau => Tau,
505 Work => Work,
506 L_Work => Work'Length,
507 Info => Info'Access);
509 if Info /= 0 then
510 raise Program_Error;
511 end if;
513 -- Generate the real orthogonal matrix determined by sytrd
515 orgtr (Uplo => Lower'Access,
516 N => N,
517 A => Vectors,
518 Ld_A => N,
519 Tau => Tau,
520 Work => Work,
521 L_Work => Work'Length,
522 Info => Info'Access);
524 if Info /= 0 then
525 raise Program_Error;
526 end if;
528 -- Compute all eigenvalues and eigenvectors using QR algorithm
530 steqr (Comp_Z => Comp_Z'Access,
531 N => N,
532 D => Values,
533 E => E,
534 Z => Vectors,
535 Ld_Z => N,
536 Work => Work,
537 Info => Info'Access);
539 if Info /= 0 then
540 raise Constraint_Error with
541 "eigensystem computation failed to converge";
542 end if;
543 end;
544 end Eigensystem;
546 -----------------
547 -- Eigenvalues --
548 -----------------
550 procedure Eigenvalues
551 (A : Real_Matrix;
552 Values : out Real_Vector)
554 N : constant Natural := Length (A);
555 L_Work : Real_Vector (1 .. 1);
556 Info : aliased Integer;
558 B : Real_Matrix (1 .. N, 1 .. N);
559 Tau : Real_Vector (1 .. N);
560 E : Real_Vector (1 .. N);
561 pragma Warnings (Off, B);
562 pragma Warnings (Off, Tau);
563 pragma Warnings (Off, E);
565 begin
566 if Values'Length /= N then
567 raise Constraint_Error with "wrong length for output vector";
568 end if;
570 if N = 0 then
571 return;
572 end if;
574 -- Initialize working matrix and check for symmetric input matrix
576 Transpose (A, B);
578 if A /= B then
579 raise Argument_Error with "matrix not symmetric";
580 end if;
582 -- Find size of work area
584 sytrd (Uplo => Lower'Access,
585 N => N,
586 A => B,
587 Ld_A => N,
588 D => Values,
589 E => E,
590 Tau => Tau,
591 Work => L_Work,
592 L_Work => -1,
593 Info => Info'Access);
595 declare
596 Work : Real_Vector (1 .. Integer'Min (Integer (L_Work (1)), 4 * N));
597 pragma Warnings (Off, Work);
599 begin
600 -- Reduce matrix to tridiagonal form
602 sytrd (Uplo => Lower'Access,
603 N => N,
604 A => B,
605 Ld_A => A'Length (1),
606 D => Values,
607 E => E,
608 Tau => Tau,
609 Work => Work,
610 L_Work => Work'Length,
611 Info => Info'Access);
613 if Info /= 0 then
614 raise Constraint_Error;
615 end if;
617 -- Compute all eigenvalues using QR algorithm
619 sterf (N => N,
620 D => Values,
621 E => E,
622 Info => Info'Access);
624 if Info /= 0 then
625 raise Constraint_Error with
626 "eigenvalues computation failed to converge";
627 end if;
628 end;
629 end Eigenvalues;
631 function Eigenvalues (A : Real_Matrix) return Real_Vector is
632 R : Real_Vector (A'Range (1));
633 begin
634 Eigenvalues (A, R);
635 return R;
636 end Eigenvalues;
638 -------------
639 -- Inverse --
640 -------------
642 procedure Inverse (A : Real_Matrix; R : out Real_Matrix) is
643 N : constant Integer := Length (A);
644 Piv : Integer_Vector (1 .. N);
645 L_Work : Real_Vector (1 .. 1);
646 Info : aliased Integer := -1;
648 begin
649 -- All computations are done using column-major order, but this works
650 -- out fine, because Transpose (Inverse (Transpose (A))) = Inverse (A).
652 R := A;
654 -- Compute LU decomposition
656 getrf (M => N,
657 N => N,
658 A => R,
659 Ld_A => N,
660 I_Piv => Piv,
661 Info => Info'Access);
663 if Info /= 0 then
664 raise Constraint_Error with "inverting singular matrix";
665 end if;
667 -- Determine size of work area
669 getri (N => N,
670 A => R,
671 Ld_A => N,
672 I_Piv => Piv,
673 Work => L_Work,
674 L_Work => -1,
675 Info => Info'Access);
677 if Info /= 0 then
678 raise Constraint_Error;
679 end if;
681 declare
682 Work : Real_Vector (1 .. Integer (L_Work (1)));
683 pragma Warnings (Off, Work);
685 begin
686 -- Compute inverse from LU decomposition
688 getri (N => N,
689 A => R,
690 Ld_A => N,
691 I_Piv => Piv,
692 Work => Work,
693 L_Work => Work'Length,
694 Info => Info'Access);
696 if Info /= 0 then
697 raise Constraint_Error with "inverting singular matrix";
698 end if;
700 -- ??? Should iterate with gerfs, based on implementation advice
701 end;
702 end Inverse;
704 function Inverse (A : Real_Matrix) return Real_Matrix is
705 R : Real_Matrix (A'Range (2), A'Range (1));
706 begin
707 Inverse (A, R);
708 return R;
709 end Inverse;
711 -----------
712 -- Solve --
713 -----------
715 procedure Solve (A : Real_Matrix; X : Real_Vector; B : out Real_Vector) is
716 begin
717 if Length (A) /= X'Length then
718 raise Constraint_Error with
719 "incompatible matrix and vector dimensions";
720 end if;
722 -- ??? Should solve directly, is faster and more accurate
724 B := Inverse (A) * X;
725 end Solve;
727 procedure Solve (A : Real_Matrix; X : Real_Matrix; B : out Real_Matrix) is
728 begin
729 if Length (A) /= X'Length (1) then
730 raise Constraint_Error with "incompatible matrix dimensions";
731 end if;
733 -- ??? Should solve directly, is faster and more accurate
735 B := Inverse (A) * X;
736 end Solve;
738 function Solve (A : Real_Matrix; X : Real_Vector) return Real_Vector is
739 B : Real_Vector (A'Range (2));
740 begin
741 Solve (A, X, B);
742 return B;
743 end Solve;
745 function Solve (A, X : Real_Matrix) return Real_Matrix is
746 B : Real_Matrix (A'Range (2), X'Range (2));
747 begin
748 Solve (A, X, B);
749 return B;
750 end Solve;
752 ---------------
753 -- Transpose --
754 ---------------
756 function Transpose (X : Real_Matrix) return Real_Matrix is
757 R : Real_Matrix (X'Range (2), X'Range (1));
758 begin
759 Transpose (X, R);
761 return R;
762 end Transpose;
764 -----------------
765 -- Unit_Matrix --
766 -----------------
768 function Unit_Matrix
769 (Order : Positive;
770 First_1 : Integer := 1;
771 First_2 : Integer := 1) return Real_Matrix
772 renames Instantiations.Unit_Matrix;
774 -----------------
775 -- Unit_Vector --
776 -----------------
778 function Unit_Vector
779 (Index : Integer;
780 Order : Positive;
781 First : Integer := 1) return Real_Vector
782 renames Instantiations.Unit_Vector;
784 end Ada.Numerics.Generic_Real_Arrays;