3 Both this software and its documentation are
5 Copyright 1993 by IRISA /Universite de Rennes I -
6 France, Copyright 1995,1996 by BYU, Provo, Utah
15 #include <polylib/polylib.h>
22 * Allocate space for matrix dimensioned by 'NbRows X NbColumns'.
24 Matrix
*Matrix_Alloc(unsigned NbRows
,unsigned NbColumns
) {
30 Mat
=(Matrix
*)malloc(sizeof(Matrix
));
32 errormsg1("Matrix_Alloc", "outofmem", "out of memory space");
36 Mat
->NbColumns
=NbColumns
;
37 if (NbRows
==0 || NbColumns
==0) {
39 Mat
->p_Init
= (Value
*)0;
42 q
= (Value
**)malloc(NbRows
* sizeof(*q
));
45 errormsg1("Matrix_Alloc", "outofmem", "out of memory space");
48 p
= value_alloc(NbRows
* NbColumns
, &Mat
->p_Init_size
);
52 errormsg1("Matrix_Alloc", "outofmem", "out of memory space");
57 for (i
=0;i
<NbRows
;i
++) {
69 * Free the memory space occupied by Matrix 'Mat'
71 void Matrix_Free(Matrix
*Mat
)
74 value_free(Mat
->p_Init
, Mat
->p_Init_size
);
82 void Matrix_Extend(Matrix
*Mat
, unsigned NbRows
)
87 q
= (Value
**)realloc(Mat
->p
, NbRows
* sizeof(*q
));
89 errormsg1("Matrix_Extend", "outofmem", "out of memory space");
93 if (Mat
->p_Init_size
< NbRows
* Mat
->NbColumns
) {
94 p
= (Value
*)realloc(Mat
->p_Init
, NbRows
* Mat
->NbColumns
* sizeof(Value
));
96 errormsg1("Matrix_Extend", "outofmem", "out of memory space");
100 Vector_Set(Mat
->p_Init
+ Mat
->NbRows
*Mat
->NbColumns
, 0,
101 Mat
->p_Init_size
- Mat
->NbRows
*Mat
->NbColumns
);
102 for (i
= Mat
->p_Init_size
; i
< Mat
->NbColumns
*NbRows
; ++i
)
103 value_init(Mat
->p_Init
[i
]);
104 Mat
->p_Init_size
= Mat
->NbColumns
*NbRows
;
106 Vector_Set(Mat
->p_Init
+ Mat
->NbRows
*Mat
->NbColumns
, 0,
107 (NbRows
- Mat
->NbRows
) * Mat
->NbColumns
);
108 for (i
=0;i
<NbRows
;i
++) {
109 Mat
->p
[i
] = Mat
->p_Init
+ (i
* Mat
->NbColumns
);
111 Mat
->NbRows
= NbRows
;
115 * Print the contents of the Matrix 'Mat'
117 void Matrix_Print(FILE *Dst
, const char *Format
, Matrix
*Mat
)
121 unsigned NbRows
, NbColumns
;
123 fprintf(Dst
,"%d %d\n", NbRows
=Mat
->NbRows
, NbColumns
=Mat
->NbColumns
);
128 for (i
=0;i
<NbRows
;i
++) {
130 for (j
=0;j
<NbColumns
;j
++) {
132 value_print(Dst
," "P_VALUE_FMT
" ",*p
++);
135 value_print(Dst
,Format
,*p
++);
143 * Read the contents of the Matrix 'Mat' from standard input
145 Matrix
*Matrix_Read_Input(Matrix
*Mat
) {
146 return Matrix_Read_InputFile(Mat
, stdin
);
147 } /* Matrix_Read_Input */
150 * Read the contents of the Matrix 'Mat' from file open in fp
152 Matrix
*Matrix_Read_InputFile(Matrix
*Mat
, FILE *fp
) {
159 for (i
=0;i
<Mat
->NbRows
;i
++) {
162 c
= fgets(s
, 1024, fp
);
165 /* jump to the first non space char */
166 while(isspace(*c
) && *c
!='\n' && *c
)
169 while(*c
=='#' || *c
== '\n'); /* continue if the line is empty or is a comment */
171 errormsg1( "Matrix_Read", "baddim", "not enough rows" );
177 /* skip to EOL and ignore the rest of the line if longer than 1024 */
178 errormsg1( "Matrix_Read", "warning", "line longer than 1024 chars (ignored remaining chars till EOL)" );
181 while( n
!=EOF
&& n
!='\n' );
185 for (j
=0;j
<Mat
->NbColumns
;j
++)
188 if(*c
=='\n' || *c
=='#' || *c
=='\0') {
189 errormsg1("Matrix_Read", "baddim", "not enough columns");
192 /* go the the next space or end */
193 for( z
=c
; *z
; z
++ )
195 if( *z
=='\n' || *z
=='#' || isspace(*z
) )
201 z
--; /* hit EOL :/ go back one char */
202 value_read(*(p
++),c
);
203 /* go point to the next non space char */
210 } /* Matrix_Read_InputFile */
213 * Read the contents of the matrix 'Mat' from standard input.
214 * a '#' is a comment (till EOL)
216 Matrix
*Matrix_Read(void) {
217 return Matrix_ReadFile(stdin
);
221 * Read the contents of the matrix 'Mat' from file open in fp.
222 * a '#' is a comment (till EOL)
224 Matrix
*Matrix_ReadFile(FILE *fp
){
226 unsigned NbRows
, NbColumns
;
229 if (fgets(s
, 1024, fp
) == NULL
)
231 while ((*s
=='#' || *s
=='\n') ||
232 (sscanf(s
, "%d %d", &NbRows
, &NbColumns
)<2)) {
233 if (fgets(s
, 1024, fp
) == NULL
)
236 Mat
= Matrix_Alloc(NbRows
,NbColumns
);
238 errormsg1("Matrix_Read", "outofmem", "out of memory space");
241 if( !Matrix_Read_Input(Mat
) )
247 } /* Matrix_ReadFile */
250 * Basic hermite engine
252 static int hermite(Matrix
*H
,Matrix
*U
,Matrix
*Q
) {
254 int nc
, nr
, i
, j
, k
, rank
, reduced
, pivotrow
;
256 Value
*temp1
, *temp2
;
259 /* Computes form: A = Q H and U A = H and U = Q */
262 errormsg1("Domlib", "nullH", "hermite: ? Null H");
267 temp1
= (Value
*) malloc(nc
* sizeof(Value
));
268 temp2
= (Value
*) malloc(nr
* sizeof(Value
));
269 if (!temp1
||!temp2
) {
270 errormsg1("Domlib", "outofmem", "out of memory space");
274 /* Initialize all the 'Value' variables */
275 value_init(pivot
); value_init(x
);
278 value_init(temp1
[i
]);
280 value_init(temp2
[i
]);
283 fprintf(stderr
,"Start -----------\n");
284 Matrix_Print(stderr
,0,H
);
286 for (k
=0, rank
=0; k
<nc
&& rank
<nr
; k
=k
+1) {
287 reduced
= 1; /* go through loop the first time */
289 fprintf(stderr
, "Working on col %d. Rank=%d ----------\n", k
+1, rank
+1);
294 /* 1. find pivot row */
295 value_absolute(pivot
,H
->p
[rank
][k
]);
297 /* the kth-diagonal element */
300 /* find the row i>rank with smallest nonzero element in col k */
301 for (i
=rank
+1; i
<nr
; i
++) {
302 value_absolute(x
,H
->p
[i
][k
]);
303 if (value_notzero_p(x
) &&
304 (value_lt(x
,pivot
) || value_zero_p(pivot
))) {
305 value_assign(pivot
,x
);
310 /* 2. Bring pivot to diagonal (exchange rows pivotrow and rank) */
311 if (pivotrow
!= rank
) {
312 Vector_Exchange(H
->p
[pivotrow
],H
->p
[rank
],nc
);
314 Vector_Exchange(U
->p
[pivotrow
],U
->p
[rank
],nr
);
316 Vector_Exchange(Q
->p
[pivotrow
],Q
->p
[rank
],nr
);
319 fprintf(stderr
,"Exchange rows %d and %d -----------\n", rank
+1, pivotrow
+1);
320 Matrix_Print(stderr
,0,H
);
323 value_assign(pivot
,H
->p
[rank
][k
]); /* actual ( no abs() ) pivot */
325 /* 3. Invert the row 'rank' if pivot is negative */
326 if (value_neg_p(pivot
)) {
327 value_oppose(pivot
,pivot
); /* pivot = -pivot */
329 value_oppose(H
->p
[rank
][j
],H
->p
[rank
][j
]);
331 /* H->p[rank][j] = -(H->p[rank][j]); */
334 value_oppose(U
->p
[rank
][j
],U
->p
[rank
][j
]);
336 /* U->p[rank][j] = -(U->p[rank][j]); */
339 value_oppose(Q
->p
[rank
][j
],Q
->p
[rank
][j
]);
341 /* Q->p[rank][j] = -(Q->p[rank][j]); */
343 fprintf(stderr
,"Negate row %d -----------\n", rank
+1);
344 Matrix_Print(stderr
,0,H
);
348 if (value_notzero_p(pivot
)) {
350 /* 4. Reduce the column modulo the pivot */
351 /* This eventually zeros out everything below the */
352 /* diagonal and produces an upper triangular matrix */
354 for (i
=rank
+1;i
<nr
;i
++) {
355 value_assign(x
,H
->p
[i
][k
]);
356 if (value_notzero_p(x
)) {
357 value_modulus(aux
,x
,pivot
);
359 /* floor[integer division] (corrected for neg x) */
360 if (value_neg_p(x
) && value_notzero_p(aux
)) {
363 value_division(x
,x
,pivot
);
364 value_decrement(x
,x
);
367 value_division(x
,x
,pivot
);
368 for (j
=0; j
<nc
; j
++) {
369 value_multiply(aux
,x
,H
->p
[rank
][j
]);
370 value_subtract(H
->p
[i
][j
],H
->p
[i
][j
],aux
);
373 /* U->p[i][j] -= (x * U->p[rank][j]); */
375 for (j
=0; j
<nr
; j
++) {
376 value_multiply(aux
,x
,U
->p
[rank
][j
]);
377 value_subtract(U
->p
[i
][j
],U
->p
[i
][j
],aux
);
380 /* Q->p[rank][j] += (x * Q->p[i][j]); */
383 value_addmul(Q
->p
[rank
][j
], x
, Q
->p
[i
][j
]);
389 "row %d = row %d - %d row %d -----------\n", i
+1, i
+1, x
, rank
+1);
390 Matrix_Print(stderr
,0,H
);
395 } /* if (pivot != 0) */
396 } /* while (reduced) */
398 /* Last finish up this column */
399 /* 5. Make pivot column positive (above pivot row) */
400 /* x should be zero for i>k */
402 if (value_notzero_p(pivot
)) {
403 for (i
=0; i
<rank
; i
++) {
404 value_assign(x
,H
->p
[i
][k
]);
405 if (value_notzero_p(x
)) {
406 value_modulus(aux
,x
,pivot
);
408 /* floor[integer division] (corrected for neg x) */
409 if (value_neg_p(x
) && value_notzero_p(aux
)) {
410 value_division(x
,x
,pivot
);
411 value_decrement(x
,x
);
416 value_division(x
,x
,pivot
);
418 /* H->p[i][j] -= x * H->p[rank][j]; */
419 for (j
=0; j
<nc
; j
++) {
420 value_multiply(aux
,x
,H
->p
[rank
][j
]);
421 value_subtract(H
->p
[i
][j
],H
->p
[i
][j
],aux
);
424 /* U->p[i][j] -= x * U->p[rank][j]; */
426 for (j
=0; j
<nr
; j
++) {
427 value_multiply(aux
,x
,U
->p
[rank
][j
]);
428 value_subtract(U
->p
[i
][j
],U
->p
[i
][j
],aux
);
431 /* Q->p[rank][j] += x * Q->p[i][j]; */
433 for (j
=0; j
<nr
; j
++) {
434 value_addmul(Q
->p
[rank
][j
], x
, Q
->p
[i
][j
]);
438 "row %d = row %d - %d row %d -----------\n", i
+1, i
+1, x
, rank
+1);
439 Matrix_Print(stderr
,0,H
);
444 } /* if (pivot!=0) */
447 /* Clear all the 'Value' variables */
448 value_clear(pivot
); value_clear(x
);
451 value_clear(temp1
[i
]);
453 value_clear(temp2
[i
]);
459 void right_hermite(Matrix
*A
,Matrix
**Hp
,Matrix
**Up
,Matrix
**Qp
) {
465 /* Computes form: A = QH , UA = H */
470 *Hp
= H
= Matrix_Alloc(nr
,nc
);
472 errormsg1("DomRightHermite", "outofmem", "out of memory space");
476 /* Initialize all the 'Value' variables */
479 Vector_Copy(A
->p_Init
,H
->p_Init
,nr
*nc
);
483 *Up
= U
= Matrix_Alloc(nr
, nr
);
485 errormsg1("DomRightHermite", "outofmem", "out of memory space");
489 Vector_Set(U
->p_Init
,0,nr
*nr
); /* zero's */
490 for(i
=0;i
<nr
;i
++) /* with diagonal of 1's */
491 value_set_si(U
->p
[i
][i
],1);
497 /* Actually I compute Q transpose... its easier */
499 *Qp
= Q
= Matrix_Alloc(nr
,nr
);
501 errormsg1("DomRightHermite", "outofmem", "out of memory space");
505 Vector_Set(Q
->p_Init
,0,nr
*nr
); /* zero's */
506 for (i
=0;i
<nr
;i
++) /* with diagonal of 1's */
507 value_set_si(Q
->p
[i
][i
],1);
514 /* Q is returned transposed */
517 for (i
=0; i
<nr
; i
++) {
518 for (j
=i
+1; j
<nr
; j
++) {
519 value_assign(tmp
,Q
->p
[i
][j
]);
520 value_assign(Q
->p
[i
][j
],Q
->p
[j
][i
] );
521 value_assign(Q
->p
[j
][i
],tmp
);
527 } /* right_hermite */
529 void left_hermite(Matrix
*A
,Matrix
**Hp
,Matrix
**Qp
,Matrix
**Up
) {
531 Matrix
*H
, *HT
, *Q
, *U
;
535 /* Computes left form: A = HQ , AU = H ,
537 using right form A = Q H , U A = H */
542 /* HT = A transpose */
543 HT
= Matrix_Alloc(nc
, nr
);
545 errormsg1("DomLeftHermite", "outofmem", "out of memory space");
551 value_assign(HT
->p
[j
][i
],A
->p
[i
][j
]);
555 *Up
= U
= Matrix_Alloc(nc
,nc
);
557 errormsg1("DomLeftHermite", "outofmem", "out of memory space");
561 Vector_Set(U
->p_Init
,0,nc
*nc
); /* zero's */
562 for (i
=0;i
<nc
;i
++) /* with diagonal of 1's */
563 value_set_si(U
->p
[i
][i
],1);
569 *Qp
= Q
= Matrix_Alloc(nc
, nc
);
571 errormsg1("DomLeftHermite", "outofmem", "out of memory space");
575 Vector_Set(Q
->p_Init
,0,nc
*nc
); /* zero's */
576 for (i
=0;i
<nc
;i
++) /* with diagonal of 1's */
577 value_set_si(Q
->p
[i
][i
],1);
582 /* H = HT transpose */
583 *Hp
= H
= Matrix_Alloc(nr
,nc
);
585 errormsg1("DomLeftHermite", "outofmem", "out of memory space");
591 value_assign(H
->p
[i
][j
],HT
->p
[j
][i
]);
596 for (i
=0; i
<nc
; i
++) {
597 for (j
=i
+1; j
<nc
; j
++) {
598 value_assign(tmp
,U
->p
[i
][j
]);
599 value_assign(U
->p
[i
][j
],U
->p
[j
][i
] );
600 value_assign(U
->p
[j
][i
],tmp
);
608 * Given a integer matrix 'Mat'(k x k), compute its inverse rational matrix
609 * 'MatInv' k x (k+1). The last column of each row in matrix MatInv is used
610 * to store the common denominator of the entries in a row. The output is 1,
611 * if 'Mat' is non-singular (invertible), otherwise the output is 0. Note::
612 * (1) Matrix 'Mat' is modified during the inverse operation.
613 * (2) Matrix 'MatInv' must be preallocated before passing into this function.
615 int MatInverse(Matrix
*Mat
,Matrix
*MatInv
) {
621 if(Mat
->NbRows
!= Mat
->NbColumns
) {
622 fprintf(stderr
,"Trying to invert a non-square matrix !\n");
626 /* Initialize all the 'Value' variables */
627 value_init(x
); value_init(gcd
); value_init(piv
);
628 value_init(m1
); value_init(m2
);
632 /* Initialise MatInv */
633 Vector_Set(MatInv
->p
[0],0,k
*(k
+1));
635 /* Initialize 'MatInv' to Identity matrix form. Each diagonal entry is set*/
636 /* to 1. Last column of each row (denominator of each entry in a row) is */
639 value_set_si(MatInv
->p
[i
][i
],1);
640 value_set_si(MatInv
->p
[i
][k
],1); /* denum */
642 /* Apply Gauss-Jordan elimination method on the two matrices 'Mat' and */
643 /* 'MatInv' in parallel. */
646 /* Check if the diagonal entry (new pivot) is non-zero or not */
647 if(value_zero_p(Mat
->p
[i
][i
])) {
649 /* Search for a non-zero pivot down the column(i) */
651 if(value_notzero_p(Mat
->p
[j
][i
]))
654 /* If no non-zero pivot is found, the matrix 'Mat' is non-invertible */
658 /* Clear all the 'Value' variables */
659 value_clear(x
); value_clear(gcd
); value_clear(piv
);
660 value_clear(m1
); value_clear(m2
);
664 /* Exchange the rows, row(i) and row(j) so that the diagonal element */
665 /* Mat->p[i][i] (pivot) is non-zero. Repeat the same operations on */
666 /* matrix 'MatInv'. */
669 /* Interchange rows, row(i) and row(j) of matrix 'Mat' */
670 value_assign(x
,Mat
->p
[j
][c
]);
671 value_assign(Mat
->p
[j
][c
],Mat
->p
[i
][c
]);
672 value_assign(Mat
->p
[i
][c
],x
);
674 /* Interchange rows, row(i) and row(j) of matrix 'MatInv' */
675 value_assign(x
,MatInv
->p
[j
][c
]);
676 value_assign(MatInv
->p
[j
][c
],MatInv
->p
[i
][c
]);
677 value_assign(MatInv
->p
[i
][c
],x
);
681 /* Make all the entries in column(i) of matrix 'Mat' zero except the */
682 /* diagonal entry. Repeat the same sequence of operations on matrix */
685 if (j
==i
) continue; /* Skip the pivot */
686 value_assign(x
,Mat
->p
[j
][i
]);
687 if(value_notzero_p(x
)) {
688 value_assign(piv
,Mat
->p
[i
][i
]);
689 value_gcd(gcd
, x
, piv
);
690 if (value_notone_p(gcd
) ) {
691 value_divexact(x
, x
, gcd
);
692 value_divexact(piv
, piv
, gcd
);
694 for(c
=((j
>i
)?i
:0);c
<k
;++c
) {
695 value_multiply(m1
,piv
,Mat
->p
[j
][c
]);
696 value_multiply(m2
,x
,Mat
->p
[i
][c
]);
697 value_subtract(Mat
->p
[j
][c
],m1
,m2
);
700 value_multiply(m1
,piv
,MatInv
->p
[j
][c
]);
701 value_multiply(m2
,x
,MatInv
->p
[i
][c
]);
702 value_subtract(MatInv
->p
[j
][c
],m1
,m2
);
705 /* Simplify row(j) of the two matrices 'Mat' and 'MatInv' by */
706 /* dividing the rows with the common GCD. */
707 Vector_Gcd(&MatInv
->p
[j
][0],k
,&m1
);
708 Vector_Gcd(&Mat
->p
[j
][0],k
,&m2
);
709 value_gcd(gcd
, m1
, m2
);
710 if(value_notone_p(gcd
)) {
712 value_divexact(Mat
->p
[j
][c
], Mat
->p
[j
][c
], gcd
);
713 value_divexact(MatInv
->p
[j
][c
], MatInv
->p
[j
][c
], gcd
);
720 /* Simplify every row so that 'Mat' reduces to Identity matrix. Perform */
721 /* the same sequence of operations on the matrix 'MatInv'. */
723 value_assign(MatInv
->p
[j
][k
],Mat
->p
[j
][j
]);
725 /* Make the last column (denominator of each entry) of every row greater */
727 Vector_Normalize_Positive(&MatInv
->p
[j
][0],k
+1,k
);
730 /* Clear all the 'Value' variables */
731 value_clear(x
); value_clear(gcd
); value_clear(piv
);
732 value_clear(m1
); value_clear(m2
);
738 * Given (m x n) integer matrix 'X' and n x (k+1) rational matrix 'P', compute
739 * the rational m x (k+1) rational matrix 'S'. The last column in each row of
740 * the rational matrices is used to store the common denominator of elements
743 void rat_prodmat(Matrix
*S
,Matrix
*X
,Matrix
*P
) {
746 int last_column_index
= P
->NbColumns
- 1;
747 Value lcm
, gcd
,last_column_entry
,s1
;
750 /* Initialize all the 'Value' variables */
751 value_init(lcm
); value_init(gcd
);
752 value_init(last_column_entry
); value_init(s1
);
753 value_init(m1
); value_init(m2
);
755 /* Compute the LCM of last column entries (denominators) of rows */
756 value_assign(lcm
,P
->p
[0][last_column_index
]);
757 for(k
=1;k
<P
->NbRows
;++k
) {
758 value_assign(last_column_entry
,P
->p
[k
][last_column_index
]);
759 value_gcd(gcd
, lcm
, last_column_entry
);
760 value_divexact(m1
, last_column_entry
, gcd
);
761 value_multiply(lcm
,lcm
,m1
);
764 /* S[i][j] = Sum(X[i][k] * P[k][j] where Sum is extended over k = 1..nbrows*/
765 for(i
=0;i
<X
->NbRows
;++i
)
766 for(j
=0;j
<P
->NbColumns
-1;++j
) {
768 /* Initialize s1 to zero. */
770 for(k
=0;k
<P
->NbRows
;++k
) {
772 /* If the LCM of last column entries is one, simply add the products */
773 if(value_one_p(lcm
)) {
774 value_addmul(s1
, X
->p
[i
][k
], P
->p
[k
][j
]);
777 /* Numerator (num) and denominator (denom) of S[i][j] is given by :- */
778 /* numerator = Sum(X[i][k]*P[k][j]*lcm/P[k][last_column_index]) and */
779 /* denominator= lcm where Sum is extended over k = 1..nbrows. */
781 value_multiply(m1
,X
->p
[i
][k
],P
->p
[k
][j
]);
782 value_division(m2
,lcm
,P
->p
[k
][last_column_index
]);
783 value_addmul(s1
, m1
, m2
);
786 value_assign(S
->p
[i
][j
],s1
);
789 for(i
=0;i
<S
->NbRows
;++i
) {
790 value_assign(S
->p
[i
][last_column_index
],lcm
);
792 /* Normalize the rows so that last element >=0 */
793 Vector_Normalize_Positive(&S
->p
[i
][0],S
->NbColumns
,S
->NbColumns
-1);
796 /* Clear all the 'Value' variables */
797 value_clear(lcm
); value_clear(gcd
);
798 value_clear(last_column_entry
); value_clear(s1
);
799 value_clear(m1
); value_clear(m2
);
805 * Given a matrix 'Mat' and vector 'p1', compute the matrix-vector product
806 * and store the result in vector 'p2'.
808 void Matrix_Vector_Product(Matrix
*Mat
,Value
*p1
,Value
*p2
) {
810 int NbRows
, NbColumns
, i
, j
;
811 Value
**cm
, *q
, *cp1
, *cp2
;
814 NbColumns
=Mat
->NbColumns
;
818 for(i
=0;i
<NbRows
;i
++) {
821 value_multiply(*cp2
,*q
,*cp1
);
825 /* *cp2 = *q++ * *cp1++ */
826 for(j
=1;j
<NbColumns
;j
++) {
827 value_addmul(*cp2
, *q
, *cp1
);
834 } /* Matrix_Vector_Product */
837 * Given a vector 'p1' and a matrix 'Mat', compute the vector-matrix product
838 * and store the result in vector 'p2'
840 void Vector_Matrix_Product(Value
*p1
,Matrix
*Mat
,Value
*p2
) {
842 int NbRows
, NbColumns
, i
, j
;
843 Value
**cm
, *cp1
, *cp2
;
846 NbColumns
=Mat
->NbColumns
;
849 for (j
=0;j
<NbColumns
;j
++) {
851 value_multiply(*cp2
,*(*cm
+j
),*cp1
);
854 /* *cp2= *(*cm+j) * *cp1++; */
855 for (i
=1;i
<NbRows
;i
++) {
856 value_addmul(*cp2
, *(*(cm
+i
)+j
), *cp1
);
862 } /* Vector_Matrix_Product */
865 * Given matrices 'Mat1' and 'Mat2', compute the matrix product and store in
868 void Matrix_Product(Matrix
*Mat1
,Matrix
*Mat2
,Matrix
*Mat3
) {
871 unsigned NbRows
, NbColumns
;
872 Value
**q1
, **q2
, *p1
, *p3
,sum
;
874 NbRows
= Mat1
->NbRows
;
875 NbColumns
= Mat2
->NbColumns
;
877 Size
= Mat1
->NbColumns
;
878 if(Mat2
->NbRows
!=Size
||Mat3
->NbRows
!=NbRows
||Mat3
->NbColumns
!=NbColumns
) {
879 fprintf(stderr
, "? Matrix_Product : incompatible matrix dimension\n");
887 /* Mat3[i][j] = Sum(Mat1[i][k]*Mat2[k][j] where sum is over k = 1..nbrows */
888 for (i
=0;i
<NbRows
;i
++) {
889 for (j
=0;j
<NbColumns
;j
++) {
892 for (k
=0;k
<Size
;k
++) {
893 value_addmul(sum
, *p1
, *(*(q2
+k
)+j
));
896 value_assign(*p3
,sum
);
902 } /* Matrix_Product */
905 * Given a rational matrix 'Mat'(k x k), compute its inverse rational matrix
908 * if 'Mat' is non-singular (invertible), otherwise the output is 0. Note::
909 * (1) Matrix 'Mat' is modified during the inverse operation.
910 * (2) Matrix 'MatInv' must be preallocated before passing into this function.
912 int Matrix_Inverse(Matrix
*Mat
,Matrix
*MatInv
) {
919 if(Mat
->NbRows
!= Mat
->NbColumns
) {
920 fprintf(stderr
,"Trying to invert a non-square matrix !\n");
924 /* Initialize all the 'Value' variables */
925 value_init(x
); value_init(gcd
); value_init(piv
);
926 value_init(m1
); value_init(m2
);
930 /* Initialise MatInv */
931 Vector_Set(MatInv
->p
[0],0,k
*k
);
933 /* Initialize 'MatInv' to Identity matrix form. Each diagonal entry is set*/
934 /* to 1. Last column of each row (denominator of each entry in a row) is */
937 value_set_si(MatInv
->p
[i
][i
],1);
938 /* value_set_si(MatInv->p[i][k],1); // denum */
940 /* Apply Gauss-Jordan elimination method on the two matrices 'Mat' and */
941 /* 'MatInv' in parallel. */
944 /* Check if the diagonal entry (new pivot) is non-zero or not */
945 if(value_zero_p(Mat
->p
[i
][i
])) {
947 /* Search for a non-zero pivot down the column(i) */
949 if(value_notzero_p(Mat
->p
[j
][i
]))
952 /* If no non-zero pivot is found, the matrix 'Mat' is non-invertible */
956 /* Clear all the 'Value' variables */
957 value_clear(x
); value_clear(gcd
); value_clear(piv
);
958 value_clear(m1
); value_clear(m2
);
962 /* Exchange the rows, row(i) and row(j) so that the diagonal element */
963 /* Mat->p[i][i] (pivot) is non-zero. Repeat the same operations on */
964 /* matrix 'MatInv'. */
967 /* Interchange rows, row(i) and row(j) of matrix 'Mat' */
968 value_assign(x
,Mat
->p
[j
][c
]);
969 value_assign(Mat
->p
[j
][c
],Mat
->p
[i
][c
]);
970 value_assign(Mat
->p
[i
][c
],x
);
972 /* Interchange rows, row(i) and row(j) of matrix 'MatInv' */
973 value_assign(x
,MatInv
->p
[j
][c
]);
974 value_assign(MatInv
->p
[j
][c
],MatInv
->p
[i
][c
]);
975 value_assign(MatInv
->p
[i
][c
],x
);
979 /* Make all the entries in column(i) of matrix 'Mat' zero except the */
980 /* diagonal entry. Repeat the same sequence of operations on matrix */
983 if (j
==i
) continue; /* Skip the pivot */
984 value_assign(x
,Mat
->p
[j
][i
]);
985 if(value_notzero_p(x
)) {
986 value_assign(piv
,Mat
->p
[i
][i
]);
987 value_gcd(gcd
, x
, piv
);
988 if (value_notone_p(gcd
) ) {
989 value_divexact(x
, x
, gcd
);
990 value_divexact(piv
, piv
, gcd
);
992 for(c
=((j
>i
)?i
:0);c
<k
;++c
) {
993 value_multiply(m1
,piv
,Mat
->p
[j
][c
]);
994 value_multiply(m2
,x
,Mat
->p
[i
][c
]);
995 value_subtract(Mat
->p
[j
][c
],m1
,m2
);
998 value_multiply(m1
,piv
,MatInv
->p
[j
][c
]);
999 value_multiply(m2
,x
,MatInv
->p
[i
][c
]);
1000 value_subtract(MatInv
->p
[j
][c
],m1
,m2
);
1003 /* Simplify row(j) of the two matrices 'Mat' and 'MatInv' by */
1004 /* dividing the rows with the common GCD. */
1005 Vector_Gcd(&MatInv
->p
[j
][0],k
,&m1
);
1006 Vector_Gcd(&Mat
->p
[j
][0],k
,&m2
);
1007 value_gcd(gcd
, m1
, m2
);
1008 if(value_notone_p(gcd
)) {
1010 value_divexact(Mat
->p
[j
][c
], Mat
->p
[j
][c
], gcd
);
1011 value_divexact(MatInv
->p
[j
][c
], MatInv
->p
[j
][c
], gcd
);
1018 /* Find common denom for each row */
1019 den
= (Value
*)malloc(k
*sizeof(Value
));
1021 for(j
=0 ; j
<k
; ++j
) {
1023 value_assign(den
[j
],Mat
->p
[j
][j
]);
1025 /* gcd is always positive */
1026 Vector_Gcd(&MatInv
->p
[j
][0],k
,&gcd
);
1027 value_gcd(gcd
, gcd
, den
[j
]);
1028 if (value_neg_p(den
[j
]))
1029 value_oppose(gcd
,gcd
); /* make denominator positive */
1030 if (value_notone_p(gcd
)) {
1032 value_divexact(MatInv
->p
[j
][c
], MatInv
->p
[j
][c
], gcd
); /* normalize */
1033 value_divexact(den
[j
], den
[j
], gcd
);
1035 value_gcd(gcd
, x
, den
[j
]);
1036 value_divexact(m1
, den
[j
], gcd
);
1037 value_multiply(x
,x
,m1
);
1039 if (value_notone_p(x
))
1040 for(j
=0 ; j
<k
; ++j
) {
1041 for (c
=0; c
<k
; c
++) {
1042 value_division(m1
,x
,den
[j
]);
1043 value_multiply(MatInv
->p
[j
][c
],MatInv
->p
[j
][c
],m1
); /* normalize */
1047 /* Clear all the 'Value' variables */
1048 for(j
=0 ; j
<k
; ++j
) {
1049 value_clear(den
[j
]);
1051 value_clear(x
); value_clear(gcd
); value_clear(piv
);
1052 value_clear(m1
); value_clear(m2
);
1056 } /* Matrix_Inverse */