2 * matfunc - extended precision rational arithmetic matrix functions
4 * Copyright (C) 1999-2007 David I. Bell
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.2 $
21 * @(#) $Id: matfunc.c,v 30.2 2007/07/05 13:30:38 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/RCS/matfunc.c,v $
24 * Under source code control: 1990/02/15 01:48:18
25 * File existed as early as: before 1990
27 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
31 * Extended precision rational arithmetic matrix functions.
32 * Matrices can contain arbitrary types of elements.
39 #include "have_unused.h"
41 E_FUNC
long irand(long s
);
43 S_FUNC
void matswaprow(MATRIX
*m
, long r1
, long r2
);
44 S_FUNC
void matsubrow(MATRIX
*m
, long oprow
, long baserow
, VALUE
*mulval
);
45 S_FUNC
void matmulrow(MATRIX
*m
, long row
, VALUE
*mulval
);
46 S_FUNC MATRIX
*matident(MATRIX
*m
);
51 * Add two compatible matrices.
54 matadd(MATRIX
*m1
, MATRIX
*m2
)
58 long min1
, min2
, max1
, max2
, index
;
59 VALUE
*v1
, *v2
, *vres
;
63 if (m1
->m_dim
!= m2
->m_dim
) {
64 math_error("Incompatible matrix dimensions for add");
67 tmp
.m_dim
= m1
->m_dim
;
68 tmp
.m_size
= m1
->m_size
;
69 for (dim
= 0; dim
< m1
->m_dim
; dim
++) {
70 min1
= m1
->m_min
[dim
];
71 max1
= m1
->m_max
[dim
];
72 min2
= m2
->m_min
[dim
];
73 max2
= m2
->m_max
[dim
];
74 if ((min1
&& min2
&& (min1
!= min2
)) ||
75 ((max1
-min1
) != (max2
-min2
))) {
76 math_error("Incompatible matrix bounds for add");
79 tmp
.m_min
[dim
] = (min1
? min1
: min2
);
80 tmp
.m_max
[dim
] = tmp
.m_min
[dim
] + (max1
- min1
);
82 res
= matalloc(m1
->m_size
);
87 for (index
= m1
->m_size
; index
> 0; index
--)
88 addvalue(v1
++, v2
++, vres
++);
94 * Subtract two compatible matrices.
97 matsub(MATRIX
*m1
, MATRIX
*m2
)
100 long min1
, min2
, max1
, max2
, index
;
101 VALUE
*v1
, *v2
, *vres
;
105 if (m1
->m_dim
!= m2
->m_dim
) {
106 math_error("Incompatible matrix dimensions for sub");
109 tmp
.m_dim
= m1
->m_dim
;
110 tmp
.m_size
= m1
->m_size
;
111 for (dim
= 0; dim
< m1
->m_dim
; dim
++) {
112 min1
= m1
->m_min
[dim
];
113 max1
= m1
->m_max
[dim
];
114 min2
= m2
->m_min
[dim
];
115 max2
= m2
->m_max
[dim
];
116 if ((min1
&& min2
&& (min1
!= min2
)) ||
117 ((max1
-min1
) != (max2
-min2
))) {
118 math_error("Incompatible matrix bounds for sub");
121 tmp
.m_min
[dim
] = (min1
? min1
: min2
);
122 tmp
.m_max
[dim
] = tmp
.m_min
[dim
] + (max1
- min1
);
124 res
= matalloc(m1
->m_size
);
129 for (index
= m1
->m_size
; index
> 0; index
--)
130 subvalue(v1
++, v2
++, vres
++);
136 * Produce the negative of a matrix.
141 register VALUE
*val
, *vres
;
145 res
= matalloc(m
->m_size
);
149 for (index
= m
->m_size
; index
> 0; index
--)
150 negvalue(val
++, vres
++);
156 * Multiply two compatible matrices.
159 matmul(MATRIX
*m1
, MATRIX
*m2
)
161 register MATRIX
*res
;
162 long i1
, i2
, max1
, max2
, index
, maxindex
;
163 VALUE
*v1
, *v2
, *vres
;
164 VALUE sum
, tmp1
, tmp2
;
166 if (m1
->m_dim
== 0) {
173 mulvalue(m1
->m_table
, v2
++, vres
++);
176 if (m2
->m_dim
== 0) {
183 mulvalue(v1
++, m2
->m_table
, vres
++);
186 if (m1
->m_dim
== 1 && m2
->m_dim
== 1) {
187 if (m1
->m_max
[0]-m1
->m_min
[0] != m2
->m_max
[0]-m2
->m_min
[0]) {
188 math_error("Incompatible bounds for 1D * 1D matmul");
191 res
= matalloc(m1
->m_size
);
196 for (index
= m1
->m_size
; index
> 0; index
--)
197 mulvalue(v1
++, v2
++, vres
++);
200 if (m1
->m_dim
== 1 && m2
->m_dim
== 2) {
201 if (m1
->m_max
[0]-m1
->m_min
[0] != m2
->m_max
[0]-m2
->m_min
[0]) {
202 math_error("Incompatible bounds for 1D * 2D matmul");
205 res
= matalloc(m2
->m_size
);
207 i1
= m1
->m_max
[0] - m1
->m_min
[0] + 1;
208 max2
= m2
->m_max
[1] - m2
->m_min
[1] + 1;
215 mulvalue(v1
, v2
++, vres
++);
220 if (m1
->m_dim
== 2 && m2
->m_dim
== 1) {
221 if (m1
->m_max
[1]-m1
->m_min
[1] != m2
->m_max
[0]-m2
->m_min
[0]) {
222 math_error("Incompatible bounds for 2D * 1D matmul");
225 res
= matalloc(m1
->m_size
);
227 i1
= m1
->m_max
[0] - m1
->m_min
[0] + 1;
228 max1
= m1
->m_max
[1] - m1
->m_min
[1] + 1;
235 mulvalue(v1
++, v2
++, vres
++);
240 if ((m1
->m_dim
!= 2) || (m2
->m_dim
!= 2)) {
241 math_error("Matrix dimensions not compatible for mul");
244 if ((m1
->m_max
[1]-m1
->m_min
[1]) != (m2
->m_max
[0]-m2
->m_min
[0])) {
245 math_error("Incompatible bounds for 2D * 2D matrix mul");
248 max1
= (m1
->m_max
[0] - m1
->m_min
[0] + 1);
249 max2
= (m2
->m_max
[1] - m2
->m_min
[1] + 1);
250 maxindex
= (m1
->m_max
[1] - m1
->m_min
[1] + 1);
251 res
= matalloc(max1
* max2
);
253 res
->m_min
[0] = m1
->m_min
[0];
254 res
->m_max
[0] = m1
->m_max
[0];
255 res
->m_min
[1] = m2
->m_min
[1];
256 res
->m_max
[1] = m2
->m_max
[1];
257 for (i1
= 0; i1
< max1
; i1
++) {
258 for (i2
= 0; i2
< max2
; i2
++) {
260 sum
.v_subtype
= V_NOSUBTYPE
;
261 v1
= &m1
->m_table
[i1
* maxindex
];
262 v2
= &m2
->m_table
[i2
];
263 for (index
= 0; index
< maxindex
; index
++) {
264 mulvalue(v1
, v2
, &tmp1
);
265 addvalue(&sum
, &tmp1
, &tmp2
);
270 if (index
+1 < maxindex
)
273 index
= (i1
* max2
) + i2
;
274 res
->m_table
[index
] = sum
;
287 register MATRIX
*res
;
288 long i1
, i2
, max
, index
;
290 VALUE sum
, tmp1
, tmp2
;
293 res
= matalloc(m
->m_size
);
297 for (index
= m
->m_size
; index
> 0; index
--)
298 squarevalue(v1
++, v2
++);
302 math_error("Matrix dimension exceeds two for square");
305 if ((m
->m_max
[0] - m
->m_min
[0]) != (m
->m_max
[1] - m
->m_min
[1])) {
306 math_error("Squaring non-square matrix");
309 max
= (m
->m_max
[0] - m
->m_min
[0] + 1);
310 res
= matalloc(max
* max
);
312 res
->m_min
[0] = m
->m_min
[0];
313 res
->m_max
[0] = m
->m_max
[0];
314 res
->m_min
[1] = m
->m_min
[1];
315 res
->m_max
[1] = m
->m_max
[1];
316 for (i1
= 0; i1
< max
; i1
++) {
317 for (i2
= 0; i2
< max
; i2
++) {
319 sum
.v_subtype
= V_NOSUBTYPE
;
320 v1
= &m
->m_table
[i1
* max
];
321 v2
= &m
->m_table
[i2
];
322 for (index
= 0; index
< max
; index
++) {
323 mulvalue(v1
, v2
, &tmp1
);
324 addvalue(&sum
, &tmp1
, &tmp2
);
331 index
= (i1
* max
) + i2
;
332 res
->m_table
[index
] = sum
;
340 * Compute the result of raising a matrix to an integer power if
341 * dimension <= 2 and for dimension == 2, the matrix is square.
342 * Negative powers mean the positive power of the inverse.
343 * Note: This calculation could someday be improved for large powers
344 * by using the characteristic polynomial of the matrix.
347 * m matrix to be raised
348 * q power to raise it to
351 matpowi(MATRIX
*m
, NUMBER
*q
)
354 long power
; /* power to raise to */
355 FULL bit
; /* current bit value */
358 math_error("Matrix dimension greater than 2 for power");
361 if (m
->m_dim
== 2 && (m
->m_max
[0] - m
->m_min
[0] !=
362 m
->m_max
[1] - m
->m_min
[1])) {
363 math_error("Raising non-square 2D matrix to a power");
367 math_error("Raising matrix to non-integral power");
370 if (zge31b(q
->num
)) {
371 math_error("Raising matrix to very large power");
374 power
= ztolong(q
->num
);
378 * Handle some low powers specially
380 if ((power
<= 4) && (power
>= -2)) {
381 switch ((int) power
) {
392 res
= matsquare(tmp
);
397 res
= matmul(m
, tmp
);
402 res
= matsquare(tmp
);
412 * Compute the power by squaring and multiplying.
413 * This uses the left to right method of power raising.
416 while ((bit
& power
) == 0)
421 tmp
= matmul(res
, m
);
427 tmp
= matsquare(res
);
431 tmp
= matmul(res
, m
);
444 * Calculate the cross product of two one dimensional matrices each
445 * with three components.
446 * m3 = matcross(m1, m2);
449 matcross(MATRIX
*m1
, MATRIX
*m2
)
462 mulvalue(v1
+ 1, v2
+ 2, &tmp1
);
463 mulvalue(v1
+ 2, v2
+ 1, &tmp2
);
464 subvalue(&tmp1
, &tmp2
, vr
+ 0);
467 mulvalue(v1
+ 2, v2
+ 0, &tmp1
);
468 mulvalue(v1
+ 0, v2
+ 2, &tmp2
);
469 subvalue(&tmp1
, &tmp2
, vr
+ 1);
472 mulvalue(v1
+ 0, v2
+ 1, &tmp1
);
473 mulvalue(v1
+ 1, v2
+ 0, &tmp2
);
474 subvalue(&tmp1
, &tmp2
, vr
+ 2);
482 * Return the dot product of two matrices.
483 * result = matdot(m1, m2);
486 matdot(MATRIX
*m1
, MATRIX
*m2
)
489 VALUE result
, tmp1
, tmp2
;
494 mulvalue(v1
, v2
, &result
);
497 mulvalue(++v1
, ++v2
, &tmp1
);
498 addvalue(&result
, &tmp1
, &tmp2
);
508 * Scale the elements of a matrix by a specified power of two.
511 * m matrix to be scaled
515 matscale(MATRIX
*m
, long n
)
517 register VALUE
*val
, *vres
;
520 MATRIX
*res
; /* resulting matrix */
525 temp
.v_subtype
= V_NOSUBTYPE
;
526 temp
.v_num
= itoq(n
);
527 res
= matalloc(m
->m_size
);
531 for (index
= m
->m_size
; index
> 0; index
--)
532 scalevalue(val
++, &temp
, vres
++);
539 * Shift the elements of a matrix by the specified number of bits.
540 * Positive shift means leftwards, negative shift rightwards.
543 * m matrix to be shifted
547 matshift(MATRIX
*m
, long n
)
549 register VALUE
*val
, *vres
;
552 MATRIX
*res
; /* resulting matrix */
557 temp
.v_subtype
= V_NOSUBTYPE
;
558 temp
.v_num
= itoq(n
);
559 res
= matalloc(m
->m_size
);
563 for (index
= m
->m_size
; index
> 0; index
--)
564 shiftvalue(val
++, &temp
, FALSE
, vres
++);
571 * Multiply the elements of a matrix by a specified value.
574 * m matrix to be multiplied
575 * vp value to multiply by
578 matmulval(MATRIX
*m
, VALUE
*vp
)
580 register VALUE
*val
, *vres
;
584 res
= matalloc(m
->m_size
);
588 for (index
= m
->m_size
; index
> 0; index
--)
589 mulvalue(val
++, vp
, vres
++);
595 * Divide the elements of a matrix by a specified value, keeping
596 * only the integer quotient.
599 * m matrix to be divided
600 * vp value to divide by
601 * v3 rounding type parameter
604 matquoval(MATRIX
*m
, VALUE
*vp
, VALUE
*v3
)
606 register VALUE
*val
, *vres
;
610 if ((vp
->v_type
== V_NUM
) && qiszero(vp
->v_num
)) {
611 math_error("Division by zero");
614 res
= matalloc(m
->m_size
);
618 for (index
= m
->m_size
; index
> 0; index
--)
619 quovalue(val
++, vp
, v3
, vres
++);
625 * Divide the elements of a matrix by a specified value, keeping
626 * only the remainder of the division.
629 * m matrix to be divided
630 * vp value to divide by
631 * v3 rounding type parameter
634 matmodval(MATRIX
*m
, VALUE
*vp
, VALUE
*v3
)
636 register VALUE
*val
, *vres
;
640 if ((vp
->v_type
== V_NUM
) && qiszero(vp
->v_num
)) {
641 math_error("Division by zero");
644 res
= matalloc(m
->m_size
);
648 for (index
= m
->m_size
; index
> 0; index
--)
649 modvalue(val
++, vp
, v3
, vres
++);
667 return error_value(E_MATTRACE2
);
668 i
= (m
->m_max
[0] - m
->m_min
[0] + 1);
669 j
= (m
->m_max
[1] - m
->m_min
[1] + 1);
671 return error_value(E_MATTRACE3
);
677 addvalue(&sum
, vp
, &tmp
);
686 * Transpose a 2-dimensional matrix
691 register VALUE
*v1
, *v2
; /* current values */
692 long rows
, cols
; /* rows and columns in new matrix */
693 long row
, col
; /* current row and column */
698 res
= matalloc(m
->m_size
);
700 res
->m_min
[0] = m
->m_min
[1];
701 res
->m_max
[0] = m
->m_max
[1];
702 res
->m_min
[1] = m
->m_min
[0];
703 res
->m_max
[1] = m
->m_max
[0];
704 rows
= (m
->m_max
[1] - m
->m_min
[1] + 1);
705 cols
= (m
->m_max
[0] - m
->m_min
[0] + 1);
707 for (row
= 0; row
< rows
; row
++) {
708 v2
= &m
->m_table
[row
];
709 for (col
= 0; col
< cols
; col
++) {
720 * Produce a matrix with values all of which are conjugated.
725 register VALUE
*val
, *vres
;
729 res
= matalloc(m
->m_size
);
733 for (index
= m
->m_size
; index
> 0; index
--)
734 conjvalue(val
++, vres
++);
740 * Round elements of a matrix to specified number of decimal digits
743 matround(MATRIX
*m
, VALUE
*v2
, VALUE
*v3
)
755 roundvalue(p
++, v2
, v3
, q
++);
761 * Round elements of a matrix to specified number of binary digits
764 matbround(MATRIX
*m
, VALUE
*v2
, VALUE
*v3
)
776 broundvalue(p
++, v2
, v3
, q
++);
781 * Approximate a matrix by approximating elemenbs to be multiples of
782 * v2, rounding type determined by v3.
785 matappr(MATRIX
*m
, VALUE
*v2
, VALUE
*v3
)
797 apprvalue(p
++, v2
, v3
, q
++);
805 * Produce a matrix with values all of which have been truncated to integers.
810 register VALUE
*val
, *vres
;
814 res
= matalloc(m
->m_size
);
818 for (index
= m
->m_size
; index
> 0; index
--)
819 intvalue(val
++, vres
++);
825 * Produce a matrix with values all of which have only the fraction part left.
830 register VALUE
*val
, *vres
;
834 res
= matalloc(m
->m_size
);
838 for (index
= m
->m_size
; index
> 0; index
--)
839 fracvalue(val
++, vres
++);
845 * Index a matrix normally by the specified set of index values.
846 * Returns the address of the matrix element if it is valid, or generates
847 * an error if the index values are out of range. The create flag is TRUE
848 * if the element is to be written, but this is ignored here.
851 * mp matrix to operate on
852 * create TRUE => create if element does not exist
853 * dim dimension of the indexing
854 * indices table of values being indexed by
858 matindex(MATRIX
*mp
, BOOL UNUSED create
, long dim
, VALUE
*indices
)
860 NUMBER
*q
; /* index value */
862 long index
; /* index value as an integer */
863 long offset
; /* current offset into array */
864 int i
; /* loop counter */
867 math_error("Negative dimension %ld for matrix", dim
);
871 if (dim
< mp
->m_dim
) {
873 "Indexing a %ldd matrix as a %ldd matrix",
878 for (i
= 0; i
< mp
->m_dim
; i
++) {
879 if (indices
->v_type
!= V_NUM
) {
880 math_error("Non-numeric index for matrix");
885 math_error("Non-integral index for matrix");
889 if (zge31b(q
->num
) || (index
< mp
->m_min
[i
]) ||
890 (index
> mp
->m_max
[i
])) {
891 math_error("Index out of bounds for matrix");
894 offset
*= (mp
->m_max
[i
] - mp
->m_min
[i
] + 1);
895 offset
+= (index
- mp
->m_min
[i
]);
898 vp
= mp
->m_table
+ offset
;
902 if (vp
->v_type
!= V_MAT
) {
903 math_error("Non-matrix argument for matindex");
913 * Returns the list of indices for a matrix element with specified
914 * double-bracket index.
917 matindices(MATRIX
*mp
, long index
)
924 if (index
< 0 || index
>= mp
->m_size
)
932 d
= mp
->m_max
[j
] - mp
->m_min
[j
] + 1;
933 val
.v_num
= itoq(index
% d
+ mp
->m_min
[j
]);
934 insertlistfirst(lp
, &val
);
943 * Search a matrix for the specified value, starting with the specified index.
944 * Returns 0 and stores index if value found; otherwise returns 1.
947 matsearch(MATRIX
*m
, VALUE
*vp
, long i
, long j
, ZVALUE
*index
)
951 val
= &m
->m_table
[i
];
952 if (i
< 0 || j
> m
->m_size
) {
953 math_error("This should not happen in call to matsearch");
957 if (acceptvalue(val
++, vp
)) {
968 * Search a matrix backwards for the specified value, starting with the
969 * specified index. Returns 0 and stores index if value found; otherwise
973 matrsearch(MATRIX
*m
, VALUE
*vp
, long i
, long j
, ZVALUE
*index
)
977 if (i
< 0 || j
> m
->m_size
) {
978 math_error("This should not happen in call to matrsearch");
981 val
= &m
->m_table
[--j
];
983 if (acceptvalue(val
--, vp
)) {
993 * Fill all of the elements of a matrix with one of two specified values.
994 * All entries are filled with the first specified value, except that if
995 * the matrix is w-dimensional and the second value pointer is non-NULL, then
996 * all diagonal entries are filled with the second value. This routine
997 * affects the supplied matrix directly, and doesn't return a copy.
1000 * m matrix to be filled
1001 * v1 value to fill most of matrix with
1002 * v2 value for diagonal entries or null
1005 matfill(MATRIX
*m
, VALUE
*v1
, VALUE
*v2
)
1007 register VALUE
*val
;
1012 copyvalue(v1
, &temp1
);
1015 if (m
->m_dim
!= 2 || v2
== NULL
) {
1016 for (i
= m
->m_size
; i
> 0; i
--) {
1018 copyvalue(&temp1
, val
++);
1024 copyvalue(v2
, &temp2
);
1025 rows
= m
->m_max
[0] - m
->m_min
[0] + 1;
1026 cols
= m
->m_max
[1] - m
->m_min
[1] + 1;
1028 for (i
= 0; i
< rows
; i
++) {
1029 for (j
= 0; j
< cols
; j
++) {
1032 copyvalue(&temp2
, val
++);
1034 copyvalue(&temp1
, val
++);
1044 * Set a copy of a square matrix to the identity matrix.
1049 register VALUE
*val
; /* current value */
1050 long row
, col
; /* current row and column */
1051 long rows
; /* number of rows */
1052 MATRIX
*res
; /* resulting matrix */
1054 if (m
->m_dim
!= 2) {
1056 "Matrix dimension must be two for setting to identity");
1059 if ((m
->m_max
[0] - m
->m_min
[0]) != (m
->m_max
[1] - m
->m_min
[1])) {
1060 math_error("Matrix must be square for setting to identity");
1063 res
= matalloc(m
->m_size
);
1066 rows
= (res
->m_max
[0] - res
->m_min
[0] + 1);
1067 for (row
= 0; row
< rows
; row
++) {
1068 for (col
= 0; col
< rows
; col
++) {
1069 val
->v_type
= V_NUM
;
1070 val
->v_num
= ((row
== col
) ? qlink(&_qone_
) :
1080 * Calculate the inverse of a matrix if it exists.
1081 * This is done by using transformations on the supplied matrix to convert
1082 * it to the identity matrix, and simultaneously applying the same set of
1083 * transformations to the identity matrix.
1088 MATRIX
*res
; /* matrix to become the inverse */
1089 long rows
; /* number of rows */
1090 long cur
; /* current row being worked on */
1091 long row
, col
; /* temp row and column values */
1092 VALUE
*val
; /* current value in matrix*/
1093 VALUE
*vres
; /* current value in result for dim < 2 */
1094 VALUE mulval
; /* value to multiply rows by */
1095 VALUE tmpval
; /* temporary value */
1098 res
= matalloc(m
->m_size
);
1101 vres
= res
->m_table
;
1102 for (cur
= m
->m_size
; cur
> 0; cur
--)
1103 invertvalue(val
++, vres
++);
1106 if (m
->m_dim
!= 2) {
1107 math_error("Matrix dimension exceeds two for inverse");
1110 if ((m
->m_max
[0] - m
->m_min
[0]) != (m
->m_max
[1] - m
->m_min
[1])) {
1111 math_error("Inverting non-square matrix");
1115 * Begin by creating the identity matrix with the same attributes.
1117 res
= matalloc(m
->m_size
);
1119 rows
= (m
->m_max
[0] - m
->m_min
[0] + 1);
1121 for (row
= 0; row
< rows
; row
++) {
1122 for (col
= 0; col
< rows
; col
++) {
1124 val
->v_num
= qlink(&_qone_
);
1126 val
->v_num
= qlink(&_qzero_
);
1127 val
->v_type
= V_NUM
;
1132 * Now loop over each row, and eliminate all entries in the
1133 * corresponding column by using row operations. Do the same
1134 * operations on the resulting matrix. Copy the original matrix
1135 * so that we don't destroy it.
1138 for (cur
= 0; cur
< rows
; cur
++) {
1140 * Find the first nonzero value in the rest of the column
1141 * downwards from [cur,cur]. If there is no such value, then
1142 * the matrix is not invertible. If the first nonzero entry
1143 * is not the current row, then swap the two rows to make the
1144 * current one nonzero.
1147 val
= &m
->m_table
[(row
* rows
) + row
];
1148 while (testvalue(val
) == 0) {
1149 if (++row
>= rows
) {
1152 math_error("Matrix is not invertible");
1157 invertvalue(val
, &mulval
);
1159 matswaprow(m
, row
, cur
);
1160 matswaprow(res
, row
, cur
);
1163 * Now for every other nonzero entry in the current column,
1164 * subtract the appropriate multiple of the current row to
1165 * force that entry to become zero.
1167 val
= &m
->m_table
[cur
];
1168 for (row
= 0; row
< rows
; row
++) {
1169 if ((row
== cur
) || (testvalue(val
) == 0)) {
1174 mulvalue(val
, &mulval
, &tmpval
);
1175 matsubrow(m
, row
, cur
, &tmpval
);
1176 matsubrow(res
, row
, cur
, &tmpval
);
1184 * Now the original matrix has nonzero entries only on its main
1185 * diagonal. Scale the rows of the result matrix by the inverse
1189 for (row
= 0; row
< rows
; row
++) {
1190 if ((val
->v_type
!= V_NUM
) || !qisone(val
->v_num
)) {
1191 invertvalue(val
, &mulval
);
1192 matmulrow(res
, row
, &mulval
);
1204 * Calculate the determinant of a square matrix.
1205 * This uses the fraction-free Gauss-Bareiss algorithm.
1210 long n
; /* original matrix is n x n */
1211 long k
; /* working submatrix is k x k */
1213 VALUE
*pivot
, *div
, *val
;
1215 VALUE tmp1
, tmp2
, tmp3
;
1216 BOOL neg
; /* whether to negate determinant */
1221 copyvalue(vp
, &tmp1
);
1224 mulvalue(&tmp1
, ++vp
, &tmp2
);
1232 return error_value(E_DET2
);
1233 if ((m
->m_max
[0] - m
->m_min
[0]) != (m
->m_max
[1] - m
->m_min
[1]))
1234 return error_value(E_DET3
);
1237 * Loop over each row, and eliminate all lower entries in the
1238 * corresponding column by using row operations. Copy the original
1239 * matrix so that we don't destroy it.
1243 n
= (m
->m_max
[0] - m
->m_min
[0] + 1);
1244 pivot
= div
= m
->m_table
;
1245 for (k
= n
; k
> 0; k
--) {
1247 * Find the first nonzero value in the rest of the column
1248 * downwards from pivot. If there is no such value, then
1249 * the determinant is zero. If the first nonzero entry is not
1250 * the pivot, then swap rows in the k * k submatrix, and
1251 * remember that the determinant changes sign.
1255 while (!testvalue(val
)) {
1257 tmp1
.v_type
= V_NUM
;
1258 tmp1
.v_subtype
= V_NOSUBTYPE
;
1259 tmp1
.v_num
= qlink(&_qzero_
);
1277 * Now for every val below the pivot, for each entry to
1278 * the right of val, calculate the 2 x 2 determinant
1279 * with corners at the pivot and the entry. If
1280 * k < n, divide by div (the previous pivot value).
1290 mulvalue(pivot
, ++vv
, &tmp1
);
1291 mulvalue(val
, ++vp
, &tmp2
);
1292 subvalue(&tmp1
, &tmp2
, &tmp3
);
1297 divvalue(&tmp3
, div
, vv
);
1309 negvalue(div
, &tmp1
);
1311 copyvalue(div
, &tmp1
);
1318 * Local utility routine to swap two rows of a square matrix.
1319 * No checks are made to verify the legality of the arguments.
1322 matswaprow(MATRIX
*m
, long r1
, long r2
)
1324 register VALUE
*v1
, *v2
;
1330 rows
= (m
->m_max
[0] - m
->m_min
[0] + 1);
1331 v1
= &m
->m_table
[r1
* rows
];
1332 v2
= &m
->m_table
[r2
* rows
];
1333 while (rows
-- > 0) {
1344 * Local utility routine to subtract a multiple of one row to another one.
1345 * The row to be changed is oprow, the row to be subtracted is baserow.
1346 * No checks are made to verify the legality of the arguments.
1349 matsubrow(MATRIX
*m
, long oprow
, long baserow
, VALUE
*mulval
)
1351 register VALUE
*vop
, *vbase
;
1352 register long entries
;
1355 entries
= (m
->m_max
[0] - m
->m_min
[0] + 1);
1356 vop
= &m
->m_table
[oprow
* entries
];
1357 vbase
= &m
->m_table
[baserow
* entries
];
1358 while (entries
-- > 0) {
1359 mulvalue(vbase
, mulval
, &tmp1
);
1360 subvalue(vop
, &tmp1
, &tmp2
);
1371 * Local utility routine to multiply a row by a specified number.
1372 * No checks are made to verify the legality of the arguments.
1375 matmulrow(MATRIX
*m
, long row
, VALUE
*mulval
)
1377 register VALUE
*val
;
1381 rows
= (m
->m_max
[0] - m
->m_min
[0] + 1);
1382 val
= &m
->m_table
[row
* rows
];
1383 while (rows
-- > 0) {
1384 mulvalue(val
, mulval
, &tmp
);
1393 * Make a full copy of a matrix.
1399 register VALUE
*v1
, *v2
;
1402 res
= matalloc(m
->m_size
);
1417 * Make a matrix the same size as another and filled with a fixed value.
1420 * m matrix to initialize
1421 * v1 value to fill most of matrix with
1422 * v2 value for diagonal entries (or NULL)
1425 matinit(MATRIX
*m
, VALUE
*v1
, VALUE
*v2
)
1436 res
= matalloc(m
->m_size
);
1442 if (v2
&& ((res
->m_dim
!= 2) ||
1443 ((res
->m_max
[0] - res
->m_min
[0]) !=
1444 (res
->m_max
[1] - res
->m_min
[1])))) {
1445 math_error("Filling diagonals of non-square matrix");
1450 * fill the bulk of the matrix
1462 * fill the diaginal of a square matrix if requested
1464 rows
= res
->m_max
[0] - res
->m_min
[0] + 1;
1466 for (row
= 0; row
< rows
; row
++) {
1467 copyvalue(v2
, v
+row
);
1475 * Allocate a matrix with the specified number of elements.
1484 m
= (MATRIX
*) malloc(matsize(size
));
1486 math_error("Cannot get memory to allocate matrix of size %ld",
1491 for (i
= size
, vp
= m
->m_table
; i
> 0; i
--, vp
++)
1492 vp
->v_subtype
= V_NOSUBTYPE
;
1498 * Free a matrix, along with all of its element values.
1515 * Test whether a matrix has any "nonzero" values.
1516 * Returns TRUE if so.
1527 if (testvalue(vp
++))
1534 * Sum the elements in a matrix.
1537 matsum(MATRIX
*m
, VALUE
*vres
)
1540 VALUE tmp
; /* first sum value */
1541 VALUE sum
; /* final sum value */
1546 copyvalue(vp
, &sum
);
1549 addvalue(&sum
, ++vp
, &tmp
);
1558 * Test whether or not two matrices are equal.
1559 * Equality is determined by the shape and values of the matrices,
1560 * but not by their index bounds. Returns TRUE if they differ.
1563 matcmp(MATRIX
*m1
, MATRIX
*m2
)
1570 if ((m1
->m_dim
!= m2
->m_dim
) || (m1
->m_size
!= m2
->m_size
))
1572 for (i
= 0; i
< m1
->m_dim
; i
++) {
1573 if ((m1
->m_max
[i
] - m1
->m_min
[i
]) !=
1574 (m2
->m_max
[i
] - m2
->m_min
[i
]))
1581 if (comparevalue(v1
++, v2
++))
1589 matreverse(MATRIX
*m
)
1595 q
= m
->m_table
+ m
->m_size
- 1;
1607 VALUE
*a
, *b
, *next
, *end
;
1609 VALUE
*S
[LONG_BITS
];
1610 long len
[LONG_BITS
];
1613 buf
= (VALUE
*) malloc(m
->m_size
* sizeof(VALUE
));
1615 math_error("Not enough memory for matsort");
1619 end
= next
+ m
->m_size
;
1620 for (k
= 0; next
&& k
< LONG_BITS
; k
++) {
1621 S
[k
] = next
++; /* S[k] is start of a run */
1625 while (k
> 0 && (!next
|| len
[k
] >= len
[k
- 1])) {/* merging */
1632 if (precvalue(b
, a
)) {
1636 } while (j
> 0 && precvalue(b
,a
));
1638 memcpy(p
, a
, i
* sizeof(VALUE
));
1640 len
[k
] * sizeof(VALUE
));
1649 } while (i
> 0 && !precvalue(b
,a
));
1656 } while (j
> 0 && precvalue(b
,a
));
1660 memcpy(S
[k
], buf
, (p
- buf
) * sizeof(VALUE
));
1661 } else if (j
== 0) {
1662 memcpy(p
, a
, i
* sizeof(VALUE
));
1663 memcpy(S
[k
], buf
, len
[k
] * sizeof(VALUE
));
1668 if (k
>= LONG_BITS
) {
1669 /* this should never happen */
1670 math_error("impossible k overflow in matsort!");
1676 matrandperm(MATRIX
*m
)
1683 for (vp
= m
->m_table
; s
> 1; vp
++, s
--) {
1695 * Test whether or not a matrix is the identity matrix.
1696 * Returns TRUE if so.
1699 matisident(MATRIX
*m
)
1701 register VALUE
*val
; /* current value */
1702 long row
, col
; /* row and column numbers */
1705 if (m
->m_dim
== 0) {
1706 return (val
->v_type
== V_NUM
&& qisone(val
->v_num
));
1708 if (m
->m_dim
== 1) {
1709 for (row
= m
->m_min
[0]; row
<= m
->m_max
[0]; row
++, val
++) {
1710 if (val
->v_type
!= V_NUM
|| !qisone(val
->v_num
))
1715 if ((m
->m_dim
!= 2) ||
1716 ((m
->m_max
[0] - m
->m_min
[0]) != (m
->m_max
[1] - m
->m_min
[1])))
1718 for (row
= m
->m_min
[0]; row
<= m
->m_max
[0]; row
++) {
1720 * We could use col = m->m_min[1]; col < m->m_max[1]
1721 * but if m->m_min[0] != m->m_min[1] this won't work.
1722 * We know that we have a square 2-dimensional matrix
1723 * so we will pretend that m->m_min[0] == m->m_min[1].
1725 for (col
= m
->m_min
[0]; col
<= m
->m_max
[0]; col
++) {
1726 if (val
->v_type
!= V_NUM
)
1729 if (!qisone(val
->v_num
))
1732 if (!qiszero(val
->v_num
))
1743 * Print a matrix and possibly few of its elements.
1744 * The argument supplied specifies how many elements to allow printing.
1745 * If any elements are printed, they are printed in short form.
1748 matprint(MATRIX
*m
, long max_print
)
1751 long fullsize
, count
, index
;
1758 for (i
= dim
- 1; i
>= 0; i
--) {
1759 sizes
[i
] = fullsize
;
1760 fullsize
*= (m
->m_max
[i
] - m
->m_min
[i
] + 1);
1762 msg
= ((max_print
> 0) ? "\nmat [" : "mat [");
1764 for (i
= 0; i
< dim
; i
++) {
1766 math_fmt("%s%ld:%ld", msg
,
1767 m
->m_min
[i
], m
->m_max
[i
]);
1769 math_fmt("%s%ld", msg
, m
->m_max
[i
] + 1);
1776 if (max_print
> fullsize
) {
1777 max_print
= fullsize
;
1781 for (index
= 0; index
< fullsize
; index
++) {
1782 if ((vp
->v_type
!= V_NUM
) || !qiszero(vp
->v_num
))
1786 math_fmt("] (%ld element%s, %ld nonzero)",
1787 fullsize
, (fullsize
== 1) ? "" : "s", count
);
1792 * Now print the first few elements of the matrix in short
1793 * and unambigous format.
1797 for (index
= 0; index
< max_print
; index
++) {
1801 for (i
= 0; i
< dim
; i
++) {
1802 math_fmt("%s%ld", msg
,
1803 m
->m_min
[i
] + (j
/ sizes
[i
]));
1811 printvalue(vp
++, PRINT_SHORT
| PRINT_UNAMBIG
);
1814 if (max_print
< fullsize
)