2 This file is part of PolyLib.
4 PolyLib is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 PolyLib is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with PolyLib. If not, see <http://www.gnu.org/licenses/>.
19 #include <polylib/polylib.h>
21 /* nota bene: on stocke les matrices par lignes */
22 /* nota bene: matrices are stored in row major order */
24 /*------------------------------------------------------------------------
25 change les signes de la ligne i de la matrice A
26 change the sign of row i of matrix A
27 ------------------------------------------------------------------------*/
29 static void moins_l(Value
*a
,int i
,int n
,int p
) {
43 /*------------------------------------------------------------------------
44 change les signes de la colonne i de la matrice A
45 change the sign of column i of matrix A
46 ------------------------------------------------------------------------*/
48 static void moins_c(Value
*a
,int i
,int n
,int p
) {
62 /*------------------------------------------------------------------------
63 echange les lignes i et j de la matrice A
64 exchange row i and j of matrix A
65 ------------------------------------------------------------------------*/
67 static void echange_l(Value
*a
,int i
,int j
,int n
,int p
) {
79 value_assign(*c1
,*c2
);
88 /*------------------------------------------------------------------------
89 echange les colonnes i et j de la matrice A
90 exchange columns i and j of matrix A
91 ------------------------------------------------------------------------*/
93 static void echange_c(Value
*a
,int i
,int j
,int n
,int p
) {
105 value_assign(*c1
,*c2
);
114 /*------------------------------------------------------------------------
115 A est une matrice de taille n*p
116 on ajoute a la ligne i, x fois la ligne j
117 A is a matrix of size n*p
118 we add x times the row j to the row i
119 ------------------------------------------------------------------------*/
121 static void ligne(Value
*a
,int i
,int j
,Value x
,int n
,int p
) {
131 value_addmul(*c1
, x
, *c2
);
138 /*------------------------------------------------------------------------
139 A est une matrice de taille n*p
140 on ajoute a la colonne i, x fois la colonne j
141 A is a matrix of size n*p
142 we add x times the column j to the column i
144 ------------------------------------------------------------------------*/
146 static void colonne(Value
*a
,int i
,int j
,Value x
,int n
,int p
) {
155 value_addmul(*c1
, x
, *c2
);
162 /*----------------------------------------------------------------------
163 trouve le numero de colonne du plus petit element non nul de
164 la ligne q, d'indice superieur a q, de la matrice A, mais
165 renvoie zero si tous les elements sont nuls sauf le qieme.
167 find the column number (greater than q) of the smallest non
168 null element of row q . it returns
169 0 if all the last elements of row q are null except the qth
171 ----------------------------------------------------------------------*/
173 static int petit_l(Value
*a
,int n
,int p
,int q
) {
175 int numero
=0, k
, tousnuls
;
179 value_init(minus
); value_init(comp
);
183 value_absolute(comp
,*c
);
184 if (value_notzero_p(comp
)) {
186 value_assign(minus
,comp
);
190 else if (value_ge(minus
,comp
)) {
191 value_assign(minus
,comp
);
198 value_clear(minus
); value_clear(comp
);
202 value_absolute(comp
,*c
);
203 if ((value_notzero_p(comp
))&&(value_ge(minus
,comp
))) {
204 value_clear(minus
); value_clear(comp
);
208 value_clear(minus
); value_clear(comp
);
214 /*----------------------------------------------------------------------
215 trouve le numero de ligne du plus petit element non nul de
216 la colonne q, d'indice superieur a q, de la matrice A, mais
217 renvoie zero si tous les elements sont nuls sauf le qieme.
219 find the row number (greater than q) of the smallest non
220 null element of column q . it returns
221 0 if all the last elements of column q are null except the qth
223 ----------------------------------------------------------------------*/
225 static int petit_c(Value
*a
,int n
,int p
,int q
) {
227 int numero
=0, k
, tousnuls
;
231 value_init(minus
); value_init(comp
);
235 value_absolute(comp
,*c
);
236 if (value_notzero_p(comp
)) {
238 value_assign(minus
,comp
);
242 else if (value_ge(minus
,comp
)) {
243 value_assign(minus
,comp
);
251 value_clear(minus
); value_clear(comp
);
255 value_absolute(comp
,*c
);
256 if ((value_notzero_p(comp
)) && (value_ge(minus
,comp
))) {
257 value_clear(minus
); value_clear(comp
);
261 value_clear(minus
); value_clear(comp
);
267 /*-----------------------------------------------------------------------
268 A est initialisee a une matrice "identite" de taille n*p
269 A is initialized to an "identity" matrix of size n*p
270 -----------------------------------------------------------------------*/
272 static void identite(Value
*a
,int n
,int p
) {
290 /*-----------------------------------------------------------------------
291 transpose la sous-matrice de A dont les indices sont
292 superieurs ou egaux a q
293 transposition of the sub-matrix of A composed of the elements
294 whose indices are greater or equal to q
295 -----------------------------------------------------------------------*/
297 static void transpose(Value
*a
,int n
,int q
) {
307 for(i
=q
+1;i
<=n
;i
++) {
310 value_assign(val
,*b
);
312 value_assign(*c
,val
);
320 /*----------------------------------------------------------------------
321 trouve le numero de colonne du premier element non divisible
322 par val dans la sous-matrice d'indices > q mais renvoie 0 sinon
324 find the column number of the first non-divisible by val element
325 in the sub-matrix of a composed of the elements of indices >q.
326 Return 0 is there is no such element
327 ----------------------------------------------------------------------*/
329 static int encore(Value
*a
,int n
,int p
,int q
,Value val
) {
335 if ((q
>=n
)||(q
>=p
)) return(0);
337 value_init(comp
); value_init(tmp
);
342 value_absolute(comp
,*c
);
343 if (value_zero_p(val
)) {
344 if (value_notzero_p(comp
)) {
351 value_modulus(tmp
,comp
,val
);
352 if (value_notzero_p(tmp
)) {
373 /*----------------------------------------------------------------------
374 transforme la matrice A (de taille n*p), a partir de la position
375 q*q en sa forme de smith, les matrices b et c subissant les memes
376 transformations respectivement sur les lignes et colonnes
378 transform the matrix A (size n*p), from position (q,q) into
379 its smith normal form. the same transformations are applied to
380 matrices b and c, respectively on rows and on columns
381 ----------------------------------------------------------------------*/
383 static void smith(Value
*a
,Value
*b
,Value
*c
,Value
*b_inverse
,Value
*c_inverse
,int n
,int p
,int q
) {
386 Value x
, pivot
, tmp
, x_inv
;
389 value_init(pivot
); value_init(tmp
);
390 value_init(x
); value_init(x_inv
);
392 if ((q
<=n
)&&(q
<=p
)) {
399 echange_l(a
,i
,q
,n
,p
);
400 echange_l(b
,i
,q
,n
,n
);
401 echange_c(b_inverse
,i
,q
,n
,n
);
404 value_assign(pivot
,*f
);
405 if (value_neg_p(pivot
)) {
408 moins_c(b_inverse
,q
,n
,n
);
409 value_oppose(pivot
,pivot
);
411 for(k
=q
+1;k
<=n
;k
++) {
413 if (value_notzero_p(*f
)) {
414 value_division(x
,*f
,pivot
);
415 value_modulus(tmp
,*f
,pivot
);
416 if (value_neg_p(tmp
))
417 value_decrement(x
,x
);
418 value_oppose(x_inv
,x
);
419 ligne(a
,k
,q
,x_inv
,n
,p
);
420 ligne(b
,k
,q
,x_inv
,n
,n
);
421 colonne(b_inverse
,q
,k
,x
,n
,n
);
430 echange_c(a
,i
,q
,n
,p
);
431 echange_c(c
,i
,q
,p
,p
);
432 echange_l(c_inverse
,i
,q
,p
,p
);
436 value_assign(pivot
,*f
);
437 if (value_neg_p(pivot
)) {
440 moins_l(c_inverse
,q
,p
,p
);
441 value_oppose(pivot
,pivot
);
443 for(k
=q
+1;k
<=p
;k
++) {
445 if (value_notzero_p(*f
)) {
446 value_division(x
,*f
,pivot
);
447 value_modulus(tmp
,*f
,pivot
);
448 if (value_neg_p(tmp
))
449 value_decrement(x
,x
);
450 value_oppose(x_inv
,x
);
451 colonne(a
,k
,q
,x_inv
,n
,p
);
452 colonne(c
,k
,q
,x_inv
,p
,p
);
453 ligne(c_inverse
,q
,k
,x
,p
,p
);
459 value_assign(pivot
,*(a
+(q
-1)+(q
-1)*p
));
460 if (value_neg_p(pivot
)) {
463 moins_c(b_inverse
,q
,n
,n
);
464 value_oppose(pivot
,pivot
);
467 i
=encore(a
,n
,p
,q
,pivot
);
470 value_set_si(x_inv
,-1);
471 colonne(a
,q
,i
,x
,n
,p
);
472 colonne(c
,q
,i
,x
,p
,p
);
473 ligne(c_inverse
,i
,q
,x_inv
,p
,p
);
474 smith(a
,b
,c
,b_inverse
,c_inverse
,n
,p
,q
);
476 else smith(a
,b
,c
,b_inverse
,c_inverse
,n
,p
,q
+1);
478 value_clear(pivot
); value_clear(tmp
);
479 value_clear(x
); value_clear(x_inv
);
484 /*----------------------------------------------------------------------
485 decompose la matrice A en le produit d'une matrice B
486 unimodulaire et d'une matrice triangulaire superieure
488 Decompose the matrix A in the product of a matrix B unimodular
489 and a matrix upper triangular, D is the inverse of B
490 ----------------------------------------------------------------------*/
492 static void hermite(Value
*a
,Value
*b
,Value
*d
,int n
,int p
,int q
) {
495 Value x
, pivot
, x_inv
, tmp
;
498 value_init(pivot
); value_init(tmp
);
499 value_init(x
); value_init(x_inv
);
501 if ((q
<=p
)&&(q
<=n
)) {
505 echange_l(a
,i
,q
,n
,p
);
506 echange_c(b
,i
,q
,n
,n
);
507 echange_l(d
,i
,q
,n
,n
);
511 value_assign(pivot
,*c1
);
512 if (value_neg_p(pivot
)) {
516 value_oppose(pivot
,pivot
);
518 for(k
=q
+1;k
<=n
;k
++) {
520 if (value_notzero_p(*c1
)) {
521 value_division(x
,*c1
,pivot
);
522 value_modulus(tmp
,*c1
,pivot
);
523 if (value_neg_p(tmp
))
524 value_decrement(x
,x
);
525 value_oppose(x_inv
,x
);
526 ligne(a
,k
,q
,x_inv
,n
,p
);
527 colonne(b
,q
,k
,x
,n
,n
);
528 ligne(d
,k
,q
,x_inv
,n
,n
);
534 value_assign(pivot
,*(c1
+(q
-1)*p
));
535 if (value_neg_p(pivot
)) {
539 value_oppose(pivot
,pivot
);
541 if (value_notzero_p(pivot
)) {
543 if (value_notzero_p(*c1
)) {
544 value_division(x
,*c1
,pivot
);
545 value_modulus(tmp
,*c1
,pivot
);
546 if (value_neg_p(tmp
))
547 value_decrement(x
,x
);
548 value_oppose(x_inv
,x
);
549 ligne(a
,k
,q
,x_inv
,n
,p
);
550 colonne(b
,q
,k
,x
,n
,n
);
551 ligne(d
,k
,q
,x_inv
,n
,n
);
556 hermite(a
,b
,d
,n
,p
,q
+1);
558 value_clear(pivot
); value_clear(tmp
);
559 value_clear(x
); value_clear(x_inv
);
563 /*----------------------------------------------------------------------
564 B est une g_base de dimension n dont les p premiers vecteurs
565 colonnes sont colineaires aux vecteurs colonnes de A
568 B is an integral (g_base ?) of dimension n whose p first columns
569 vectors are proportionnal to the column vectors of A. C is the
571 ----------------------------------------------------------------------*/
573 /** Convert PolmattoDarmat :
574 *** This function converts the matrix of a Polylib to a int * as necessary
575 *** for the functions in Darte's implementation.
577 *** Input : A Polylib Matrix ( a pointer to it );
578 *** Output : An int * with the matrix copied into it
580 static Value
*ConvertPolMattoDarMat(Matrix
*A
) {
585 result
= (Value
*)malloc(sizeof(Value
) * A
->NbRows
* A
->NbColumns
);
586 for(i
=0;i
<A
->NbRows
* A
->NbColumns
;i
++)
587 value_init(result
[i
]);
589 for (i
= 0; i
< A
->NbRows
; i
++)
590 for (j
= 0 ; j
< A
->NbColumns
; j
++)
591 value_assign(result
[i
*A
->NbColumns
+ j
],A
->p
[i
][j
]);
593 } /* ConvertPolMattoDarMat */
595 /** Convert DarmattoPolmat
596 *** This function converts the matrix from Darte representation to a matrix
599 *** Input : The matrix (a pointer to it), number of Rows, number of columns
600 *** Output : The matrix of the PolyLib
604 static Matrix
*ConvertDarMattoPolMat (Value
*A
, int NbRows
, int NbCols
) {
609 result
= Matrix_Alloc(NbRows
, NbCols
);
611 for (i
= 0; i
< NbRows
; i
++)
612 for (j
= 0; j
< NbCols
; j
++)
613 value_assign(result
->p
[i
][j
],A
[i
*NbCols
+ j
]);
615 } /* ConvertDarMattoPolMat */
618 *** Smith : This function takes a Matrix A of dim n * l as its input
619 *** and returns the three matrices U, V and Product such that
620 *** A = U * Product * V, where U is an unimodular matrix of dimension
621 *** n * n and V is an unimodular matrix of dimension l * l.
622 *** Product is a diagonal matrix of dimension n * l.
624 *** We use Alan Darte's implementation of Smith for computing
625 *** the Smith Normal Form
627 void Smith(Matrix
*A
, Matrix
**U
, Matrix
**V
, Matrix
**Product
)
632 u
= Identity(A
->NbRows
);
633 v
= Identity(A
->NbColumns
);
635 *U
= Identity(A
->NbRows
);
636 *V
= Identity(A
->NbColumns
);
638 *Product
= Matrix_Copy(A
);
639 smith((*Product
)->p_Init
, u
->p_Init
, v
->p_Init
, (*U
)->p_Init
, (*V
)->p_Init
,
640 A
->NbRows
, A
->NbColumns
, 1);
647 *** This function takes a Matrix as its input and finds its HNF
650 *** Input : A Matrix A (The Matrix A is not necessarily a Polylib matrix.
651 *** It is just a matrix as far as Hermite is concerned. It
652 *** does not even check if the matrix is a Polylib matrix or not)
653 *** Output : The Hnf matrix H and the Unimodular matrix U such that
656 *** We use Alan Darte's implementation of Hermite to compute the HNF.
657 *** Alan Darte's implementation computes the Upper Triangular HNF.
658 *** So We work on the fact that if A = H * U then
659 *** A (transpose) = U(transpose) * H (transpose)
660 *** There are a set of interface functions written in Interface.c
661 *** which convert a matrix from Polylib representationt to that of
662 *** Alan Darte's and vice versa.
664 *** This Function Does the Following
665 *** Step 1 : Given the matrix A it finds its Transpose.
666 *** Step 2 : Finds the HNF (Right Form) using Alan Darte's Algorithm.
667 *** Step 3 : The H1 and U1 obtained in Step2 are both Transposed to get
668 *** the actual H and U such that A = HU.
670 void Hermite (Matrix
*A
, Matrix
**H
, Matrix
**U
) {
673 Matrix
*transpose
, *tempH
, *tempU
;
674 Value
*darte_matA
, *darte_identite
, *darte_id_inv
;
676 transpose
= Transpose(A
);
677 darte_matA
= ConvertPolMattoDarMat(transpose
);
679 darte_identite
= (Value
*)malloc(sizeof(Value
) * A
->NbColumns
* A
->NbColumns
);
680 darte_id_inv
= (Value
*) malloc(sizeof(Value
) * A
->NbColumns
*A
->NbColumns
);
681 for (i
=0; i
< A
->NbColumns
* A
->NbColumns
; i
++)
682 value_init(darte_identite
[i
]);
683 for (i
=0; i
< A
->NbColumns
* A
->NbColumns
; i
++)
684 value_init(darte_id_inv
[i
]);
686 identite(darte_identite
, transpose
->NbRows
, transpose
->NbRows
);
687 identite(darte_id_inv
, transpose
->NbRows
, transpose
->NbRows
);
688 hermite(darte_matA
, darte_identite
, darte_id_inv
,A
->NbColumns
,A
->NbRows
, 1);
689 Matrix_Free (transpose
);
690 transpose
= ConvertDarMattoPolMat(darte_matA
, A
->NbColumns
, A
->NbRows
);
691 tempU
= ConvertDarMattoPolMat(darte_identite
, A
->NbColumns
, A
->NbColumns
);
693 /* Finding H Transpose */
694 tempH
= Transpose(transpose
);
695 Matrix_Free(transpose
);
697 /* Finding U Transpose */
698 transpose
= Transpose(tempU
);
700 H
[0] = Matrix_Copy(tempH
);
701 U
[0] = Matrix_Copy(transpose
);
704 Matrix_Free (transpose
);
707 for (i
=0; i
< A
->NbRows
* A
->NbColumns
; i
++)
708 value_clear(darte_matA
[i
]);
709 for (i
=0; i
< A
->NbColumns
* A
->NbColumns
; i
++)
710 value_clear(darte_identite
[i
]);
711 for (i
=0; i
< A
->NbColumns
* A
->NbColumns
; i
++)
712 value_clear(darte_id_inv
[i
]);
714 free (darte_identite
);