2 #include <polylib/polylib.h>
4 /* nota bene: on stocke les matrices par lignes */
5 /* nota bene: matrices are stored in row major order */
7 /*------------------------------------------------------------------------
8 change les signes de la ligne i de la matrice A
9 change the sign of row i of matrix A
10 ------------------------------------------------------------------------*/
12 static void moins_l(Value
*a
,int i
,int n
,int p
) {
26 /*------------------------------------------------------------------------
27 change les signes de la colonne i de la matrice A
28 change the sign of column i of matrix A
29 ------------------------------------------------------------------------*/
31 static void moins_c(Value
*a
,int i
,int n
,int p
) {
45 /*------------------------------------------------------------------------
46 echange les lignes i et j de la matrice A
47 exchange row i and j of matrix A
48 ------------------------------------------------------------------------*/
50 static void echange_l(Value
*a
,int i
,int j
,int n
,int p
) {
62 value_assign(*c1
,*c2
);
71 /*------------------------------------------------------------------------
72 echange les colonnes i et j de la matrice A
73 exchange columns i and j of matrix A
74 ------------------------------------------------------------------------*/
76 static void echange_c(Value
*a
,int i
,int j
,int n
,int p
) {
88 value_assign(*c1
,*c2
);
97 /*------------------------------------------------------------------------
98 A est une matrice de taille n*p
99 on ajoute a la ligne i, x fois la ligne j
100 A is a matrix of size n*p
101 we add x times the row j to the row i
102 ------------------------------------------------------------------------*/
104 static void ligne(Value
*a
,int i
,int j
,Value x
,int n
,int p
) {
114 value_addmul(*c1
, x
, *c2
);
121 /*------------------------------------------------------------------------
122 A est une matrice de taille n*p
123 on ajoute a la colonne i, x fois la colonne j
124 A is a matrix of size n*p
125 we add x times the column j to the column i
127 ------------------------------------------------------------------------*/
129 static void colonne(Value
*a
,int i
,int j
,Value x
,int n
,int p
) {
138 value_addmul(*c1
, x
, *c2
);
145 /*----------------------------------------------------------------------
146 trouve le numero de colonne du plus petit element non nul de
147 la ligne q, d'indice superieur a q, de la matrice A, mais
148 renvoie zero si tous les elements sont nuls sauf le qieme.
150 find the column number (greater than q) of the smallest non
151 null element of row q . it returns
152 0 if all the last elements of row q are null except the qth
154 ----------------------------------------------------------------------*/
156 static int petit_l(Value
*a
,int n
,int p
,int q
) {
158 int numero
=0, k
, tousnuls
;
162 value_init(minus
); value_init(comp
);
166 value_absolute(comp
,*c
);
167 if (value_notzero_p(comp
)) {
169 value_assign(minus
,comp
);
173 else if (value_ge(minus
,comp
)) {
174 value_assign(minus
,comp
);
181 value_clear(minus
); value_clear(comp
);
185 value_absolute(comp
,*c
);
186 if ((value_notzero_p(comp
))&&(value_ge(minus
,comp
))) {
187 value_clear(minus
); value_clear(comp
);
191 value_clear(minus
); value_clear(comp
);
197 /*----------------------------------------------------------------------
198 trouve le numero de ligne du plus petit element non nul de
199 la colonne q, d'indice superieur a q, de la matrice A, mais
200 renvoie zero si tous les elements sont nuls sauf le qieme.
202 find the row number (greater than q) of the smallest non
203 null element of column q . it returns
204 0 if all the last elements of column q are null except the qth
206 ----------------------------------------------------------------------*/
208 static int petit_c(Value
*a
,int n
,int p
,int q
) {
210 int numero
=0, k
, tousnuls
;
214 value_init(minus
); value_init(comp
);
218 value_absolute(comp
,*c
);
219 if (value_notzero_p(comp
)) {
221 value_assign(minus
,comp
);
225 else if (value_ge(minus
,comp
)) {
226 value_assign(minus
,comp
);
234 value_clear(minus
); value_clear(comp
);
238 value_absolute(comp
,*c
);
239 if ((value_notzero_p(comp
)) && (value_ge(minus
,comp
))) {
240 value_clear(minus
); value_clear(comp
);
244 value_clear(minus
); value_clear(comp
);
250 /*-----------------------------------------------------------------------
251 A est initialisee a une matrice "identite" de taille n*p
252 A is initialized to an "identity" matrix of size n*p
253 -----------------------------------------------------------------------*/
255 static void identite(Value
*a
,int n
,int p
) {
273 /*-----------------------------------------------------------------------
274 transpose la sous-matrice de A dont les indices sont
275 superieurs ou egaux a q
276 transposition of the sub-matrix of A composed of the elements
277 whose indices are greater or equal to q
278 -----------------------------------------------------------------------*/
280 static void transpose(Value
*a
,int n
,int q
) {
290 for(i
=q
+1;i
<=n
;i
++) {
293 value_assign(val
,*b
);
295 value_assign(*c
,val
);
303 /*----------------------------------------------------------------------
304 trouve le numero de colonne du premier element non divisible
305 par val dans la sous-matrice d'indices > q mais renvoie 0 sinon
307 find the column number of the first non-divisible by val element
308 in the sub-matrix of a composed of the elements of indices >q.
309 Return 0 is there is no such element
310 ----------------------------------------------------------------------*/
312 static int encore(Value
*a
,int n
,int p
,int q
,Value val
) {
318 if ((q
>=n
)||(q
>=p
)) return(0);
320 value_init(comp
); value_init(tmp
);
325 value_absolute(comp
,*c
);
326 if (value_zero_p(val
)) {
327 if (value_notzero_p(comp
)) {
334 value_modulus(tmp
,comp
,val
);
335 if (value_notzero_p(tmp
)) {
356 /*----------------------------------------------------------------------
357 transforme la matrice A (de taille n*p), a partir de la position
358 q*q en sa forme de smith, les matrices b et c subissant les memes
359 transformations respectivement sur les lignes et colonnes
361 transform the matrix A (size n*p), from position (q,q) into
362 its smith normal form. the same transformations are applied to
363 matrices b and c, respectively on rows and on columns
364 ----------------------------------------------------------------------*/
366 static void smith(Value
*a
,Value
*b
,Value
*c
,Value
*b_inverse
,Value
*c_inverse
,int n
,int p
,int q
) {
369 Value x
, pivot
, tmp
, x_inv
;
372 value_init(pivot
); value_init(tmp
);
373 value_init(x
); value_init(x_inv
);
375 if ((q
<=n
)&&(q
<=p
)) {
382 echange_l(a
,i
,q
,n
,p
);
383 echange_l(b
,i
,q
,n
,n
);
384 echange_c(b_inverse
,i
,q
,n
,n
);
387 value_assign(pivot
,*f
);
388 if (value_neg_p(pivot
)) {
391 moins_c(b_inverse
,q
,n
,n
);
392 value_oppose(pivot
,pivot
);
394 for(k
=q
+1;k
<=n
;k
++) {
396 if (value_notzero_p(*f
)) {
397 value_division(x
,*f
,pivot
);
398 value_modulus(tmp
,*f
,pivot
);
399 if (value_neg_p(tmp
))
400 value_decrement(x
,x
);
401 value_oppose(x_inv
,x
);
402 ligne(a
,k
,q
,x_inv
,n
,p
);
403 ligne(b
,k
,q
,x_inv
,n
,n
);
404 colonne(b_inverse
,q
,k
,x
,n
,n
);
413 echange_c(a
,i
,q
,n
,p
);
414 echange_c(c
,i
,q
,p
,p
);
415 echange_l(c_inverse
,i
,q
,p
,p
);
419 value_assign(pivot
,*f
);
420 if (value_neg_p(pivot
)) {
423 moins_l(c_inverse
,q
,p
,p
);
424 value_oppose(pivot
,pivot
);
426 for(k
=q
+1;k
<=p
;k
++) {
428 if (value_notzero_p(*f
)) {
429 value_division(x
,*f
,pivot
);
430 value_modulus(tmp
,*f
,pivot
);
431 if (value_neg_p(tmp
))
432 value_decrement(x
,x
);
433 value_oppose(x_inv
,x
);
434 colonne(a
,k
,q
,x_inv
,n
,p
);
435 colonne(c
,k
,q
,x_inv
,p
,p
);
436 ligne(c_inverse
,q
,k
,x
,p
,p
);
442 value_assign(pivot
,*(a
+(q
-1)+(q
-1)*p
));
443 if (value_neg_p(pivot
)) {
446 moins_c(b_inverse
,q
,n
,n
);
447 value_oppose(pivot
,pivot
);
450 i
=encore(a
,n
,p
,q
,pivot
);
453 value_set_si(x_inv
,-1);
454 colonne(a
,q
,i
,x
,n
,p
);
455 colonne(c
,q
,i
,x
,p
,p
);
456 ligne(c_inverse
,i
,q
,x_inv
,p
,p
);
457 smith(a
,b
,c
,b_inverse
,c_inverse
,n
,p
,q
);
459 else smith(a
,b
,c
,b_inverse
,c_inverse
,n
,p
,q
+1);
461 value_clear(pivot
); value_clear(tmp
);
462 value_clear(x
); value_clear(x_inv
);
467 /*----------------------------------------------------------------------
468 decompose la matrice A en le produit d'une matrice B
469 unimodulaire et d'une matrice triangulaire superieure
471 Decompose the matrix A in the product of a matrix B unimodular
472 and a matrix upper triangular, D is the inverse of B
473 ----------------------------------------------------------------------*/
475 static void hermite(Value
*a
,Value
*b
,Value
*d
,int n
,int p
,int q
) {
478 Value x
, pivot
, x_inv
, tmp
;
481 value_init(pivot
); value_init(tmp
);
482 value_init(x
); value_init(x_inv
);
484 if ((q
<=p
)&&(q
<=n
)) {
488 echange_l(a
,i
,q
,n
,p
);
489 echange_c(b
,i
,q
,n
,n
);
490 echange_l(d
,i
,q
,n
,n
);
494 value_assign(pivot
,*c1
);
495 if (value_neg_p(pivot
)) {
499 value_oppose(pivot
,pivot
);
501 for(k
=q
+1;k
<=n
;k
++) {
503 if (value_notzero_p(*c1
)) {
504 value_division(x
,*c1
,pivot
);
505 value_modulus(tmp
,*c1
,pivot
);
506 if (value_neg_p(tmp
))
507 value_decrement(x
,x
);
508 value_oppose(x_inv
,x
);
509 ligne(a
,k
,q
,x_inv
,n
,p
);
510 colonne(b
,q
,k
,x
,n
,n
);
511 ligne(d
,k
,q
,x_inv
,n
,n
);
517 value_assign(pivot
,*(c1
+(q
-1)*p
));
518 if (value_neg_p(pivot
)) {
522 value_oppose(pivot
,pivot
);
524 if (value_notzero_p(pivot
)) {
526 if (value_notzero_p(*c1
)) {
527 value_division(x
,*c1
,pivot
);
528 value_modulus(tmp
,*c1
,pivot
);
529 if (value_neg_p(tmp
))
530 value_decrement(x
,x
);
531 value_oppose(x_inv
,x
);
532 ligne(a
,k
,q
,x_inv
,n
,p
);
533 colonne(b
,q
,k
,x
,n
,n
);
534 ligne(d
,k
,q
,x_inv
,n
,n
);
539 hermite(a
,b
,d
,n
,p
,q
+1);
541 value_clear(pivot
); value_clear(tmp
);
542 value_clear(x
); value_clear(x_inv
);
546 /*----------------------------------------------------------------------
547 B est une g_base de dimension n dont les p premiers vecteurs
548 colonnes sont colineaires aux vecteurs colonnes de A
551 B is an integral (g_base ?) of dimension n whose p first columns
552 vectors are proportionnal to the column vectors of A. C is the
554 ----------------------------------------------------------------------*/
556 /** Convert PolmattoDarmat :
557 *** This function converts the matrix of a Polylib to a int * as necessary
558 *** for the functions in Darte's implementation.
560 *** Input : A Polylib Matrix ( a pointer to it );
561 *** Output : An int * with the matrix copied into it
563 static Value
*ConvertPolMattoDarMat(Matrix
*A
) {
568 result
= (Value
*)malloc(sizeof(Value
) * A
->NbRows
* A
->NbColumns
);
569 for(i
=0;i
<A
->NbRows
* A
->NbColumns
;i
++)
570 value_init(result
[i
]);
572 for (i
= 0; i
< A
->NbRows
; i
++)
573 for (j
= 0 ; j
< A
->NbColumns
; j
++)
574 value_assign(result
[i
*A
->NbColumns
+ j
],A
->p
[i
][j
]);
576 } /* ConvertPolMattoDarMat */
578 /** Convert DarmattoPolmat
579 *** This function converts the matrix from Darte representation to a matrix
582 *** Input : The matrix (a pointer to it), number of Rows, number of columns
583 *** Output : The matrix of the PolyLib
587 static Matrix
*ConvertDarMattoPolMat (Value
*A
, int NbRows
, int NbCols
) {
592 result
= Matrix_Alloc(NbRows
, NbCols
);
594 for (i
= 0; i
< NbRows
; i
++)
595 for (j
= 0; j
< NbCols
; j
++)
596 value_assign(result
->p
[i
][j
],A
[i
*NbCols
+ j
]);
598 } /* ConvertDarMattoPolMat */
601 *** Smith : This function takes a Matrix A of dim n * l as its input
602 *** and returns the three matrices U, V and Product such that
603 *** A = U * Product * V, where U is an unimodular matrix of dimension
604 *** n * n and V is an unimodular matrix of dimension l * l.
605 *** Product is a diagonal matrix of dimension n * l.
607 *** We use Alan Darte's implementation of Smith for computing
608 *** the Smith Normal Form
610 void Smith(Matrix
*A
, Matrix
**U
, Matrix
**V
, Matrix
**Product
)
615 u
= Identity(A
->NbRows
);
616 v
= Identity(A
->NbColumns
);
618 *U
= Identity(A
->NbRows
);
619 *V
= Identity(A
->NbColumns
);
621 *Product
= Matrix_Copy(A
);
622 smith((*Product
)->p_Init
, u
->p_Init
, v
->p_Init
, (*U
)->p_Init
, (*V
)->p_Init
,
623 A
->NbRows
, A
->NbColumns
, 1);
630 *** This function takes a Matrix as its input and finds its HNF
633 *** Input : A Matrix A (The Matrix A is not necessarily a Polylib matrix.
634 *** It is just a matrix as far as Hermite is concerned. It
635 *** does not even check if the matrix is a Polylib matrix or not)
636 *** Output : The Hnf matrix H and the Unimodular matrix U such that
639 *** We use Alan Darte's implementation of Hermite to compute the HNF.
640 *** Alan Darte's implementation computes the Upper Triangular HNF.
641 *** So We work on the fact that if A = H * U then
642 *** A (transpose) = U(transpose) * H (transpose)
643 *** There are a set of interface functions written in Interface.c
644 *** which convert a matrix from Polylib representationt to that of
645 *** Alan Darte's and vice versa.
647 *** This Function Does the Following
648 *** Step 1 : Given the matrix A it finds its Transpose.
649 *** Step 2 : Finds the HNF (Right Form) using Alan Darte's Algorithm.
650 *** Step 3 : The H1 and U1 obtained in Step2 are both Transposed to get
651 *** the actual H and U such that A = HU.
653 void Hermite (Matrix
*A
, Matrix
**H
, Matrix
**U
) {
656 Matrix
*transpose
, *tempH
, *tempU
;
657 Value
*darte_matA
, *darte_identite
, *darte_id_inv
;
659 transpose
= Transpose(A
);
660 darte_matA
= ConvertPolMattoDarMat(transpose
);
662 darte_identite
= (Value
*)malloc(sizeof(Value
) * A
->NbColumns
* A
->NbColumns
);
663 darte_id_inv
= (Value
*) malloc(sizeof(Value
) * A
->NbColumns
*A
->NbColumns
);
664 for (i
=0; i
< A
->NbColumns
* A
->NbColumns
; i
++)
665 value_init(darte_identite
[i
]);
666 for (i
=0; i
< A
->NbColumns
* A
->NbColumns
; i
++)
667 value_init(darte_id_inv
[i
]);
669 identite(darte_identite
, transpose
->NbRows
, transpose
->NbRows
);
670 identite(darte_id_inv
, transpose
->NbRows
, transpose
->NbRows
);
671 hermite(darte_matA
, darte_identite
, darte_id_inv
,A
->NbColumns
,A
->NbRows
, 1);
672 Matrix_Free (transpose
);
673 transpose
= ConvertDarMattoPolMat(darte_matA
, A
->NbColumns
, A
->NbRows
);
674 tempU
= ConvertDarMattoPolMat(darte_identite
, A
->NbColumns
, A
->NbColumns
);
676 /* Finding H Transpose */
677 tempH
= Transpose(transpose
);
678 Matrix_Free(transpose
);
680 /* Finding U Transpose */
681 transpose
= Transpose(tempU
);
683 H
[0] = Matrix_Copy(tempH
);
684 U
[0] = Matrix_Copy(transpose
);
687 Matrix_Free (transpose
);
690 for (i
=0; i
< A
->NbRows
* A
->NbColumns
; i
++)
691 value_clear(darte_matA
[i
]);
692 for (i
=0; i
< A
->NbColumns
* A
->NbColumns
; i
++)
693 value_clear(darte_identite
[i
]);
694 for (i
=0; i
< A
->NbColumns
* A
->NbColumns
; i
++)
695 value_clear(darte_id_inv
[i
]);
697 free (darte_identite
);