1 ------------------------------------------------------------------------------
3 -- GNAT RUN-TIME COMPONENTS --
5 -- ADA.NUMERICS.GENERIC_REAL_ARRAYS --
9 -- Copyright (C) 2006-2016, Free Software Foundation, Inc. --
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. --
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. --
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/>. --
27 -- GNAT was originally developed by the GNAT team at New York University. --
28 -- Extensive contributions were provided by Ada Core Technologies Inc. --
30 ------------------------------------------------------------------------------
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.
39 with Ada
.Containers
.Generic_Anonymous_Array_Sort
; use Ada
.Containers
;
41 with System
; use System
;
42 with System
.Generic_Array_Operations
; use System
.Generic_Array_Operations
;
44 package body Ada
.Numerics
.Generic_Real_Arrays
is
46 package Ops
renames System
.Generic_Array_Operations
;
48 function Is_Non_Zero
(X
: Real
'Base) return Boolean is (X
/= 0.0);
50 procedure Back_Substitute
is new Ops
.Back_Substitute
52 Matrix
=> Real_Matrix
,
53 Is_Non_Zero
=> Is_Non_Zero
);
55 function Diagonal
is new Ops
.Diagonal
57 Vector
=> Real_Vector
,
58 Matrix
=> Real_Matrix
);
60 procedure Forward_Eliminate
is new Ops
.Forward_Eliminate
63 Matrix
=> Real_Matrix
,
67 procedure Swap_Column
is new Ops
.Swap_Column
69 Matrix
=> Real_Matrix
);
71 procedure Transpose
is new Ops
.Transpose
73 Matrix
=> Real_Matrix
);
75 function Is_Symmetric
(A
: Real_Matrix
) return Boolean is
77 -- Return True iff A is symmetric, see RM G.3.1 (90).
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.
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
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.
95 procedure Rotate
(X
, Y
: in out Real
; Sin
, Tau
: Real
);
96 -- Perform a Givens rotation
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
103 procedure Swap
(Left
, Right
: in out Real
);
104 -- Exchange Left and Right
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.
115 procedure Rotate
(X
, Y
: in out Real
; Sin
, Tau
: Real
) is
116 Old_X
: constant Real
:= X
;
117 Old_Y
: constant Real
:= Y
;
119 X
:= Old_X
- Sin
* (Old_Y
+ Old_X
* Tau
);
120 Y
:= Old_Y
+ Sin
* (Old_X
- Old_Y
* Tau
);
127 procedure Swap
(Left
, Right
: in out Real
) is
128 Temp
: constant Real
:= Left
;
134 -- Instantiating the following subprograms directly would lead to
135 -- name clashes, so use a local package.
137 package Instantiations
is
140 Vector_Elementwise_Operation
141 (X_Scalar
=> Real
'Base,
142 Result_Scalar
=> Real
'Base,
143 X_Vector
=> Real_Vector
,
144 Result_Vector
=> Real_Vector
,
148 Matrix_Elementwise_Operation
149 (X_Scalar
=> Real
'Base,
150 Result_Scalar
=> Real
'Base,
151 X_Matrix
=> Real_Matrix
,
152 Result_Matrix
=> Real_Matrix
,
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
,
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
,
176 Vector_Elementwise_Operation
177 (X_Scalar
=> Real
'Base,
178 Result_Scalar
=> Real
'Base,
179 X_Vector
=> Real_Vector
,
180 Result_Vector
=> Real_Vector
,
184 Matrix_Elementwise_Operation
185 (X_Scalar
=> Real
'Base,
186 Result_Scalar
=> Real
'Base,
187 X_Matrix
=> Real_Matrix
,
188 Result_Matrix
=> Real_Matrix
,
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
,
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
,
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
,
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
,
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
,
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
,
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
);
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
,
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
,
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
,
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
,
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
,
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
,
313 function "abs" is new
315 (X_Scalar
=> Real
'Base,
316 Result_Real
=> Real
'Base,
317 X_Vector
=> Real_Vector
,
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
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
,
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
,
340 function Solve
is new
341 Matrix_Vector_Solution
(Real
'Base, 0.0, Real_Vector
, Real_Matrix
);
343 function Solve
is new
344 Matrix_Matrix_Solution
(Real
'Base, 0.0, Real_Matrix
);
346 function Unit_Matrix
is new
347 Generic_Array_Operations
.Unit_Matrix
348 (Scalar
=> Real
'Base,
349 Matrix
=> Real_Matrix
,
353 function Unit_Vector
is new
354 Generic_Array_Operations
.Unit_Vector
355 (Scalar
=> Real
'Base,
356 Vector
=> Real_Vector
,
366 function "+" (Right
: Real_Vector
) return Real_Vector
367 renames Instantiations
."+";
369 function "+" (Right
: Real_Matrix
) return Real_Matrix
370 renames Instantiations
."+";
372 function "+" (Left
, Right
: Real_Vector
) return Real_Vector
373 renames Instantiations
."+";
375 function "+" (Left
, Right
: Real_Matrix
) return Real_Matrix
376 renames Instantiations
."+";
382 function "-" (Right
: Real_Vector
) return Real_Vector
383 renames Instantiations
."-";
385 function "-" (Right
: Real_Matrix
) return Real_Matrix
386 renames Instantiations
."-";
388 function "-" (Left
, Right
: Real_Vector
) return Real_Vector
389 renames Instantiations
."-";
391 function "-" (Left
, Right
: Real_Matrix
) return Real_Matrix
392 renames Instantiations
."-";
398 -- Scalar multiplication
400 function "*" (Left
: Real
'Base; Right
: Real_Vector
) return Real_Vector
401 renames Instantiations
."*";
403 function "*" (Left
: Real_Vector
; Right
: Real
'Base) return Real_Vector
404 renames Instantiations
."*";
406 function "*" (Left
: Real
'Base; Right
: Real_Matrix
) return Real_Matrix
407 renames Instantiations
."*";
409 function "*" (Left
: Real_Matrix
; Right
: Real
'Base) return Real_Matrix
410 renames Instantiations
."*";
412 -- Vector multiplication
414 function "*" (Left
, Right
: Real_Vector
) return Real
'Base
415 renames Instantiations
."*";
417 function "*" (Left
, Right
: Real_Vector
) return Real_Matrix
418 renames Instantiations
."*";
420 function "*" (Left
: Real_Vector
; Right
: Real_Matrix
) return Real_Vector
421 renames Instantiations
."*";
423 function "*" (Left
: Real_Matrix
; Right
: Real_Vector
) return Real_Vector
424 renames Instantiations
."*";
426 -- Matrix Multiplication
428 function "*" (Left
, Right
: Real_Matrix
) return Real_Matrix
429 renames Instantiations
."*";
435 function "/" (Left
: Real_Vector
; Right
: Real
'Base) return Real_Vector
436 renames Instantiations
."/";
438 function "/" (Left
: Real_Matrix
; Right
: Real
'Base) return Real_Matrix
439 renames Instantiations
."/";
445 function "abs" (Right
: Real_Vector
) return Real
'Base
446 renames Instantiations
."abs";
448 function "abs" (Right
: Real_Vector
) return Real_Vector
449 renames Instantiations
."abs";
451 function "abs" (Right
: Real_Matrix
) return Real_Matrix
452 renames Instantiations
."abs";
458 function Determinant
(A
: Real_Matrix
) return Real
'Base is
459 M
: Real_Matrix
:= A
;
460 B
: Real_Matrix
(A
'Range (1), 1 .. 0);
463 Forward_Eliminate
(M
, B
, R
);
471 procedure Eigensystem
473 Values
: out Real_Vector
;
474 Vectors
: out Real_Matrix
)
477 Jacobi
(A
, Values
, Vectors
, Compute_Vectors
=> True);
478 Sort_Eigensystem
(Values
, Vectors
);
485 function Eigenvalues
(A
: Real_Matrix
) return Real_Vector
is
487 return Values
: Real_Vector
(A
'Range (1)) do
489 Vectors
: Real_Matrix
(1 .. 0, 1 .. 0);
491 Jacobi
(A
, Values
, Vectors
, Compute_Vectors
=> False);
492 Sort_Eigensystem
(Values
, Vectors
);
501 function Inverse
(A
: Real_Matrix
) return Real_Matrix
is
502 (Solve
(A
, Unit_Matrix
(Length
(A
))));
510 Values
: out Real_Vector
;
511 Vectors
: out Real_Matrix
;
512 Compute_Vectors
: Boolean := True)
514 -- This subprogram uses Carl Gustav Jacob Jacobi's iterative method
515 -- for computing eigenvalues and eigenvectors and is based on
516 -- Rutishauser's implementation.
518 -- The given real symmetric matrix is transformed iteratively to
519 -- diagonal form through a sequence of appropriately chosen elementary
520 -- orthogonal transformations, called Jacobi rotations here.
522 -- The Jacobi method produces a systematic decrease of the sum of the
523 -- squares of off-diagonal elements. Convergence to zero is quadratic,
524 -- both for this implementation, as for the classic method that doesn't
525 -- use row-wise scanning for pivot selection.
527 -- The numerical stability and accuracy of Jacobi's method make it the
528 -- best choice here, even though for large matrices other methods will
529 -- be significantly more efficient in both time and space.
531 -- While the eigensystem computations are absolutely foolproof for all
532 -- real symmetric matrices, in presence of invalid values, or similar
533 -- exceptional situations it might not. In such cases the results cannot
534 -- be trusted and Constraint_Error is raised.
536 -- Note: this implementation needs temporary storage for 2 * N + N**2
537 -- values of type Real.
539 Max_Iterations
: constant := 50;
540 N
: constant Natural := Length
(A
);
542 subtype Square_Matrix
is Real_Matrix
(1 .. N
, 1 .. N
);
544 -- In order to annihilate the M (Row, Col) element, the
545 -- rotation parameters Cos and Sin are computed as
548 -- Theta = Cot (2.0 * Phi)
549 -- = (Diag (Col) - Diag (Row)) / (2.0 * M (Row, Col))
551 -- Then Tan (Phi) as the smaller root (in modulus) of
553 -- T**2 + 2 * T * Theta = 1 (or 0.5 / Theta, if Theta is large)
555 function Compute_Tan
(Theta
: Real
) return Real
is
556 (Real
'Copy_Sign (1.0 / (abs Theta
+ Sqrt
(1.0 + Theta
**2)), Theta
));
558 function Compute_Tan
(P
, H
: Real
) return Real
is
559 (if Is_Tiny
(P
, Compared_To
=> H
) then P
/ H
560 else Compute_Tan
(Theta
=> H
/ (2.0 * P
)));
562 function Sum_Strict_Upper
(M
: Square_Matrix
) return Real
;
563 -- Return the sum of all elements in the strict upper triangle of M
565 ----------------------
566 -- Sum_Strict_Upper --
567 ----------------------
569 function Sum_Strict_Upper
(M
: Square_Matrix
) return Real
is
573 for Row
in 1 .. N
- 1 loop
574 for Col
in Row
+ 1 .. N
loop
575 Sum
:= Sum
+ abs M
(Row
, Col
);
580 end Sum_Strict_Upper
;
582 M
: Square_Matrix
:= A
; -- Work space for solving eigensystem
585 Diag
: Real_Vector
(1 .. N
);
586 Diag_Adj
: Real_Vector
(1 .. N
);
588 -- The vector Diag_Adj indicates the amount of change in each value,
589 -- while Diag tracks the value itself and Values holds the values as
590 -- they were at the beginning. As the changes typically will be small
591 -- compared to the absolute value of Diag, at the end of each iteration
592 -- Diag is computed as Diag + Diag_Adj thus avoiding accumulating
593 -- rounding errors. This technique is due to Rutishauser.
597 and then (Vectors
'Length (1) /= N
or else Vectors
'Length (2) /= N
)
599 raise Constraint_Error
with "incompatible matrix dimensions";
601 elsif Values
'Length /= N
then
602 raise Constraint_Error
with "incompatible vector length";
604 elsif not Is_Symmetric
(M
) then
605 raise Constraint_Error
with "matrix not symmetric";
608 -- Note: Only the locally declared matrix M and vectors (Diag, Diag_Adj)
609 -- have lower bound equal to 1. The Vectors matrix may have
610 -- different bounds, so take care indexing elements. Assignment
611 -- as a whole is fine as sliding is automatic in that case.
613 Vectors
:= (if not Compute_Vectors
then (1 .. 0 => (1 .. 0 => 0.0))
614 else Unit_Matrix
(Vectors
'Length (1), Vectors
'Length (2)));
615 Values
:= Diagonal
(M
);
617 Sweep
: for Iteration
in 1 .. Max_Iterations
loop
619 -- The first three iterations, perform rotation for any non-zero
620 -- element. After this, rotate only for those that are not much
621 -- smaller than the average off-diagnal element. After the fifth
622 -- iteration, additionally zero out off-diagonal elements that are
623 -- very small compared to elements on the diagonal with the same
624 -- column or row index.
626 Sum
:= Sum_Strict_Upper
(M
);
628 exit Sweep
when Sum
= 0.0;
630 Threshold
:= (if Iteration
< 4 then 0.2 * Sum
/ Real
(N
**2) else 0.0);
632 -- Iterate over all off-diagonal elements, rotating any that have
633 -- an absolute value that exceeds the threshold.
636 Diag_Adj
:= (others => 0.0); -- Accumulates adjustments to Diag
638 for Row
in 1 .. N
- 1 loop
639 for Col
in Row
+ 1 .. N
loop
641 -- If, before the rotation M (Row, Col) is tiny compared to
642 -- Diag (Row) and Diag (Col), rotation is skipped. This is
643 -- meaningful, as it produces no larger error than would be
644 -- produced anyhow if the rotation had been performed.
645 -- Suppress this optimization in the first four sweeps, so
646 -- that this procedure can be used for computing eigenvectors
647 -- of perturbed diagonal matrices.
650 and then Is_Tiny
(M
(Row
, Col
), Compared_To
=> Diag
(Row
))
651 and then Is_Tiny
(M
(Row
, Col
), Compared_To
=> Diag
(Col
))
655 elsif abs M
(Row
, Col
) > Threshold
then
656 Perform_Rotation
: declare
657 Tan
: constant Real
:= Compute_Tan
(M
(Row
, Col
),
658 Diag
(Col
) - Diag
(Row
));
659 Cos
: constant Real
:= 1.0 / Sqrt
(1.0 + Tan
**2);
660 Sin
: constant Real
:= Tan
* Cos
;
661 Tau
: constant Real
:= Sin
/ (1.0 + Cos
);
662 Adj
: constant Real
:= Tan
* M
(Row
, Col
);
665 Diag_Adj
(Row
) := Diag_Adj
(Row
) - Adj
;
666 Diag_Adj
(Col
) := Diag_Adj
(Col
) + Adj
;
667 Diag
(Row
) := Diag
(Row
) - Adj
;
668 Diag
(Col
) := Diag
(Col
) + Adj
;
672 for J
in 1 .. Row
- 1 loop -- 1 <= J < Row
673 Rotate
(M
(J
, Row
), M
(J
, Col
), Sin
, Tau
);
676 for J
in Row
+ 1 .. Col
- 1 loop -- Row < J < Col
677 Rotate
(M
(Row
, J
), M
(J
, Col
), Sin
, Tau
);
680 for J
in Col
+ 1 .. N
loop -- Col < J <= N
681 Rotate
(M
(Row
, J
), M
(Col
, J
), Sin
, Tau
);
684 for J
in Vectors
'Range (1) loop
685 Rotate
(Vectors
(J
, Row
- 1 + Vectors
'First (2)),
686 Vectors
(J
, Col
- 1 + Vectors
'First (2)),
689 end Perform_Rotation
;
694 Values
:= Values
+ Diag_Adj
;
697 -- All normal matrices with valid values should converge perfectly.
700 raise Constraint_Error
with "eigensystem solution does not converge";
708 function Solve
(A
: Real_Matrix
; X
: Real_Vector
) return Real_Vector
709 renames Instantiations
.Solve
;
711 function Solve
(A
, X
: Real_Matrix
) return Real_Matrix
712 renames Instantiations
.Solve
;
714 ----------------------
715 -- Sort_Eigensystem --
716 ----------------------
718 procedure Sort_Eigensystem
719 (Values
: in out Real_Vector
;
720 Vectors
: in out Real_Matrix
)
722 procedure Swap
(Left
, Right
: Integer);
723 -- Swap Values (Left) with Values (Right), and also swap the
724 -- corresponding eigenvectors. Note that lowerbounds may differ.
726 function Less
(Left
, Right
: Integer) return Boolean is
727 (Values
(Left
) > Values
(Right
));
728 -- Sort by decreasing eigenvalue, see RM G.3.1 (76).
730 procedure Sort
is new Generic_Anonymous_Array_Sort
(Integer);
731 -- Sorts eigenvalues and eigenvectors by decreasing value
733 procedure Swap
(Left
, Right
: Integer) is
735 Swap
(Values
(Left
), Values
(Right
));
736 Swap_Column
(Vectors
, Left
- Values
'First + Vectors
'First (2),
737 Right
- Values
'First + Vectors
'First (2));
741 Sort
(Values
'First, Values
'Last);
742 end Sort_Eigensystem
;
748 function Transpose
(X
: Real_Matrix
) return Real_Matrix
is
750 return R
: Real_Matrix
(X
'Range (2), X
'Range (1)) do
761 First_1
: Integer := 1;
762 First_2
: Integer := 1) return Real_Matrix
763 renames Instantiations
.Unit_Matrix
;
772 First
: Integer := 1) return Real_Vector
773 renames Instantiations
.Unit_Vector
;
775 end Ada
.Numerics
.Generic_Real_Arrays
;