polylib 7.01
Lattice.c
Go to the documentation of this file.
1#include <polylib/polylib.h>
2#include <stdlib.h>
3
4// #define LATINTER_DEBUG 1
5// #define LATDIF_DEBUG 1
6
7static int value_prime_factors(Value n, Vector **result);
9 int row, int column, Matrix *A, Matrix *Intersection, Matrix *L,
10 LatticeUnion *Result);
11
12
13/*
14 * Print the contents of a list of Lattices 'Head'
15 */
16void PrintLatticeUnion(FILE *fp, char *format, LatticeUnion *Head) {
17
18 LatticeUnion *temp;
19
20 for (temp = Head; temp != NULL; temp = temp->next)
21 Matrix_Print(fp, format, temp->M);
22
23} /* PrintLatticeUnion */
24
25
26/*
27 * Free the memory allocated for a list of lattices 'Head'
28 */
30 while (Head) {
31 LatticeUnion *temp;
32 temp = Head;
33 Head = temp->next;
34 Matrix_Free(temp->M);
35 free(temp);
36 }
37} /* LatticeUnion_Free */
38
39
40/*
41 * Allocate a head for a list of Lattices
42 */
44
45 LatticeUnion *temp;
46
47 temp = malloc(sizeof(LatticeUnion));
48 temp->M = NULL;
49 temp->next = NULL;
50 return temp;
51} /* LatticeUnion_Alloc */
52
53
54/*
55 * Return True if lattice 'A' is empty, otherwise return False.
56 */
58 return(A == NULL || A->NbColumns == 0);
59} /* isEmptyLattice */
60
61
62/*
63 * Move the constant part (last line and last row) as first line and row
64 * of the matrix.
65 * This is useful to compute a HNF and keep the affine part (as top-left
66 * non-nul result).
67 * A = A' | c -> z | 0..0
68 * 0..0 | z c | A'
69 * Usage: modifies A in place.
70 */
72{
73 if(A->NbRows == 0 || A->NbColumns == 0)
74 return;
75
76 Value tmp;
77 value_init(tmp);
78 // puts the last column first:
79 for(int i=0; i<A->NbRows; i++) {
80 // on row i
81 value_assign(tmp, A->p[i][A->NbColumns-1]); // tmp = last col value
82 for(int j = A->NbColumns-1; j > 0; j--) {
83 value_assign(A->p[i][j], A->p[i][j-1]); // [j] <- [j-1]
84 }
85 value_assign(A->p[i][0], tmp); // [0]<- tmp
86 }
87 // then puts the last row first:
88 for(int j = 0; j < A->NbColumns; j++) {
89 value_assign(tmp, A->p[A->NbRows-1][j]); // tmp = last row value
90 for(int i = A->NbRows-1; i > 0; i--) {
91 value_assign(A->p[i][j], A->p[i-1][j]); // [i] <- [i-1]
92 }
93 value_assign(A->p[0][j], tmp); // [0]<- tmp
94 }
95 value_clear(tmp);
96} /* Matrix_Move_Homogeneous_Dim_First */
97
98
99/*
100 * Moves the constant part of a transformed lattice (first line and first row)
101 * as last line and row.
102 * This is useful to convert back the affine part at bottom-right after a HNF.
103 * A = A' | c <- z | 0..0
104 * 0..0 | z c | A'
105 * Usage: modifies A in place.
106 */
108{
109 if(A->NbRows == 0 || A->NbColumns == 0)
110 return;
111
112 Value tmp;
113 value_init(tmp);
114 // puts the first col in the end
115 for (int i = 0; i < A->NbRows; i++) {
116 value_assign(tmp,A->p[i][0]); // tmp = first col value
117 for (int j = 0; j < A->NbColumns-1; j++) {
118 value_assign(A->p[i][j],A->p[i][j+1]); // [i] <- [i+1]
119 }
120 value_assign(A->p[i][A->NbColumns-1],tmp); //[last] <- tmp
121 }
122 for (int j = 0; j < A->NbColumns; j++) {
123 value_assign(tmp,A->p[0][j]); // tmp first row value
124 for (int i = 0; i < A->NbRows-1; i++) {
125 value_assign(A->p[i][j],A->p[i+1][j]);
126 }
127 value_assign(A->p[A->NbRows-1][j],tmp);
128 }
129 value_clear(tmp);
130} /* Matrix_Move_Homogeneous_Dim_Last */
131
132
133/*
134 * Check if the matrix 'A' is in affine Hermite normal form.
135 */
137{
138 // Check the affine-homogeneous lattice (last line/column is first):
139 // Let A = L l
140 // 0..0 1
141 //
142 // A' = 0..0 1
143 // L l
144 //
145 // check if A' verifies:
146 // - first element of column (= pivot) greater than zero
147 // - all elements left of pivot lower than pivot.
148 //
149 // Example:
150 // 1 0 0 0
151 // * 0 0 0
152 // < + 0 0
153 // < < + 0
154 // * * * 0
155 // all < of a line are lower than the + (pivot) of this line
156 // * is anything.
157 // a column of zero is valid on the right of L.
158
159 int previous_nnl = -1;
160
161 if(value_notone_p(A->p[A->NbRows-1][A->NbColumns-1])) {
162 // the bottom right value should be 1.
163 return (False);
164 }
165
166 for (int j = 0; j < A->NbColumns - 1; j++) {
167 // consider column j of L
168 int nnl; // line number of the pivot (non-null line)
169
170 // find the line number of the first non-null element
171 for(nnl = 0; nnl<A->NbRows; nnl++) {
172 if(value_notzero_p(A->p[nnl][j]))
173 break;
174 }
175 if(nnl == A->NbRows) {
176 // this is a column of zeros, valid, just continue.
177 previous_nnl = nnl;
178 continue;
179 }
180 if(nnl <= previous_nnl) {
181 // there is a non-zero value higher than the previous column
182 return(False);
183 }
184 previous_nnl = nnl;
185
186 // The pivot is: A->p[nnl][j]
187 // check that the pivot is positive
188 if(value_neg_p(A->p[nnl][j])) {
189 return(False);
190 }
191
192 // check that the values left of pivot are lower than pivot
193 for(int i = 0; i < j; i++) {
194 if (value_ge(A->p[nnl][i], A->p[nnl][j])) {
195 return(False);
196 }
197 }
198 // check that the constant in l is lower than pivot
199 if (value_ge(A->p[nnl][A->NbColumns-1], A->p[nnl][j])) {
200 return(False);
201 }
202 }
203 return(True);
204} /* isNormalLattice */
205
206
207/*
208 * Return the affine Hermite normal form of the affine lattice 'A'. The
209 * affine Hermite form if a lattice is stored in 'H' and the unimodular
210 * matrix corresponding to A = H U is stored in the matrix 'U' (if not NULL)
211 *
212 * Algorithm:
213 * 1) move the homogeneous dimensions first (on top-left) in A
214 * 2) compute the left_hermite of the matrix A' = H' U'
215 * 3) move back the homogeneous dimensions (bottom-right) in A, H and U.
216 * Works also on non square matrices (lattices having less row than columns)
217 *
218 * U can be NULL (will be ignored)
219 * *H and *U can be NULL (will be allocated by left_hermite)
220 */
222{
223 // for left hermite to include the constant, move it on top-left:
225 left_hermite(A, H, U, NULL);
227 if(U)
229 Matrix_Move_Homogeneous_Dim_Last(A); // restore A as it was
230
231 return;
232} /* AffineHermite */
233
234
235// not used anymore:
236// /*
237// * Given a Polylib matrix 'A' that represents an affine function, return the
238// * affine Smith normal form 'Delta' of 'A' and unimodular matrices 'U' and 'V'
239// * such that 'A = U*Delta*V'.
240// * Algorithm:
241// * (1) Homogenize the Lattice.
242// * (2) Call Smith
243// * (3) The Smith Normal Form Delta must be Dehomogenized and also
244// * corresponding changes must be made to the Unimodular Matrices
245// * U and V.
246// * 4) Bring Delta into AffineSmith Form.
247// */
248// void AffineSmith(Matrix *A, Matrix **U, Matrix **V, Matrix **Diag) {
249
250// Matrix *temp;
251// Matrix *Uinv;
252// int i, j;
253// Value sum, quo, rem;
254
255// value_init(sum);
256// value_init(quo);
257// value_init(rem);
258// temp = Homogenise(A, True);
259// Smith(temp, U, V, Diag);
260// Matrix_Free(temp);
261
262// temp = Homogenise(*U, False);
263// Matrix_Free(*U);
264// *U = temp;
265
266// temp = Homogenise(*V, False);
267// Matrix_Free(*V);
268// *V = temp;
269
270// temp = Homogenise(*Diag, False);
271// Matrix_Free(*Diag);
272// *Diag = temp;
273
274// temp = Matrix_Copy(*U);
275// Uinv = Matrix_Alloc((*U)->NbColumns, (*U)->NbRows);
276// Matrix_Inverse(temp, Uinv);
277// Matrix_Free(temp);
278
279// for (i = 0; i < U[0]->NbRows - 1; i++) {
280// value_set_si(sum, 0);
281// for (j = 0; j < U[0]->NbColumns - 1; j++) {
282// value_addmul(sum, Uinv->p[i][j], U[0]->p[j][U[0]->NbColumns - 1]);
283// }
284// value_assign(Diag[0]->p[i][j], sum);
285// }
286// Matrix_Free(Uinv);
287// for (i = 0; i < U[0]->NbRows - 1; i++)
288// value_set_si(U[0]->p[i][U[0]->NbColumns - 1], 0);
289// for (i = 0; i < Diag[0]->NbRows - 1; i++) {
290// value_division(quo, Diag[0]->p[i][Diag[0]->NbColumns - 1],
291// Diag[0]->p[i][i]);
292// value_modulus(rem, Diag[0]->p[i][Diag[0]->NbColumns - 1], Diag[0]->p[i][i]);
293
294// /* Apparently the % operator is strange when sign are different */
295// if (value_neg_p(rem)) {
296// value_addto(rem, rem, Diag[0]->p[i][i]);
297// value_decrement(quo, quo);
298// };
299// value_assign(Diag[0]->p[i][Diag[0]->NbColumns - 1], rem);
300// value_assign(V[0]->p[i][V[0]->NbColumns - 1], quo);
301// }
302// value_clear(sum);
303// value_clear(quo);
304// value_clear(rem);
305// return;
306// } /* AffineSmith */
307
308/*
309 * count the number of columns of zeros on the right of the linear part
310 * of a lattice function
311 */
313{
314 int nb = 0;
315 for (int j = M->NbColumns-2; j >= 0; j--) {
316 int i;
317 for(i = 0; i < M->NbRows; i++) {
318 if(value_notzero_p(M->p[i][j])) {
319 break;
320 }
321 }
322 if(i != M->NbRows)
323 break;
324 nb++;
325 }
326 return nb;
327}
328
329
330/*
331 * Given two canonical lattices 'A' and 'B', check if lattice 'A' is included
332 * in 'B'.
333 *
334 * If 'A' is included in 'B' their intersection is 'A'.
335 */
337{
338 Matrix *temp;
339 Bool flag = False;
340
341 temp = LatticeIntersection(B, A);
342 if(temp) {
343 if(isSameLatticeSpace(temp, A))
344 flag = True;
345 Matrix_Free(temp);
346 }
347
348 return flag;
349} /* LatticeIncluded */
350
351
352/*
353 * Check if 'A' and 'B' spread the same points (ignore columns of zeros)
354 * 'A' and 'B' are canonical lattices
355 */
357{
358 if(A->NbRows != B->NbRows)
359 return(False);
360
361 for(int i = 0; i < A->NbRows; i++) {
362 int j;
363 // common part
364 for(j = 0; j < A->NbColumns - 1 && j < B->NbColumns - 1; j++) {
365 if(value_ne(A->p[i][j], B->p[i][j])) {
366 return(False);
367 }
368 }
369 // check zeros on the right of A and of B if A or B has more columns
370 // one of the two loops will be taken if A or B has more columns:
371 for(; j < A->NbColumns - 1; j++) {
372 if(value_notzero_p(A->p[i][j])) {
373 return(False);
374 }
375 }
376 for(; j < B->NbColumns - 1; j++) {
377 if(value_notzero_p(B->p[i][j])) {
378 return(False);
379 }
380 }
381 // same constant on the rightmost column
382 if(value_ne(A->p[i][A->NbColumns-1], B->p[i][B->NbColumns-1])) {
383 return(False);
384 }
385 }
386
387 return(True);
388}
389
390/*
391 * Check if 'A' and 'B' are the exact same (including same zero columns).
392 * 'A' and 'B' are canonical lattices
393 */
395{
396 if(A->NbRows != B->NbRows || A->NbColumns != B->NbColumns)
397 return (False);
398
399 for(int i = 0; i < A->NbRows; i++) {
400 for(int j = 0; j < A->NbColumns; j++) {
401 if(value_ne(A->p[i][j], B->p[i][j])) {
402 return(False);
403 }
404 }
405 }
406
407 return(True);
408} /* isEqualLattice */
409
410
411/*
412 * Return the Union of lattices that constitute the difference between
413 * two single lattices: 'A' - 'B'.
414 * The dimensions of A and B should be equal: same rows and columns (!=0)).
415 * If A = NULL consider the whole space spread by B (the same dimension
416 * maximal space).
417 *
418 * Allocates a LatticeUnion.
419 * If the difference is empty return NULL.
420 *
421 * Algorithm: compute the intersection of A and B and take it out of A
422 */
424{
425 Matrix *H, *X;
426 Matrix *Inter, *rest;
427 LatticeUnion *Result = NULL;
428
429 if(B->NbRows == 1) {
430 return(NULL);
431 }
432 // Checking inputs:
433 if(!A) {
434 // Value gcd;
435 // value_init(gcd);
436 A = Matrix_Alloc(B->NbRows, B->NbColumns);
437 Vector_Set(A->p[0], 0, A->NbRows * A->NbColumns);
438
439 // new method: is it right in cases where the lattice
440 // is not orthogonal?
441 // set 1's in the positions of the pivots of B
442 for(int c = 0; c < A->NbColumns - 1; c++) {
443 for(int l = 0; l < A->NbRows; l++) {
444 if(value_notzero_p(B->p[l][c])) {
445 // pivot of B
446 value_set_si(A->p[l][c], 1);
447 break;
448 }
449 }
450 }
451 // keep the constant so that the intersection is guaranteed non empty:
452 for(int l = 0; l < A->NbRows; l++)
453 value_assign(A->p[l][A->NbColumns - 1], B->p[l][B->NbColumns - 1]);
454
455 // // previous method was (not working):
456 // // Divide each column of A by its gcd to get the same dimension lattice
457 // // spreading the whole space of the dimension of B
458 // for(int j = 0; j < A->NbColumns - 1; j++) {
459 // int i;
460 // // value_set_si(gcd, 0);
461 // // initial gcd value (not necessary, 0 is good)
462 // for(i = 0; i < A->NbRows; i++) {
463 // if(value_notzero_p(A->p[i][j])) {
464 // value_assign(gcd, A->p[i][j]);
465 // break;
466 // }
467 // }
468 // // complete gcd computation
469 // for(i = i + 1; i < A->NbRows; i++) {
470 // value_gcd(gcd, gcd, A->p[i][j]);
471 // }
472
473 // if(value_notzero_p(gcd) && value_notone_p(gcd)) {
474 // // divide the column by its gcd:
475 // for(i = 0; i < A->NbRows; i++) {
476 // value_division(A->p[i][j], A->p[i][j], gcd);
477 // }
478 // }
479 // }
480 // value_clear(gcd);
481 X = NULL;
482 AffineHermite(A, &X, NULL);
483 Matrix_Free(A);
484 }
485 else {
486 if (A->NbRows != B->NbRows) {
487 errormsg1("LatticeDifference", "dimincomp",
488 "input lattices A and B have incompatible dimensions (rows)");
489 return NULL;
490 }
491 // NbColumn can be different if there is a column of zero in one of them
492
493 if(! isNormalLattice(A)) {
494 AffineHermite(A, &H, NULL);
495 X = H;
496 }
497 else {
498 X = Matrix_Copy(A);
499 }
500 }
501 if(isEmptyLattice(X)) {
502 Matrix_Free(X);
503 return(NULL);
504 }
505 #ifdef LATDIF_DEBUG
506 fprintf(stderr, "--- Entering LatDiff ---\n"
507 "A (normalized) = X = ");
508 Matrix_Print(stderr, P_VALUE_FMT, X);
509 fprintf(stderr, "B = ");
510 Matrix_Print(stderr, P_VALUE_FMT, B);
511 #endif
512
513 // calculate the intersection between X and B
514 Inter = LatticeIntersection(X, B);
515 if(!Inter) {
516 #ifdef LATDIF_DEBUG
517 fprintf(stderr, "Empty intersection, returning A\n");
518 #endif
519 // if empty intersection return a copy of A (normalized)
520 Result = LatticeUnion_Alloc();
521 Result->M = X;
522 return (Result);
523 }
524 #ifdef LATDIF_DEBUG
525 fprintf(stderr, "Inter = ");
526 Matrix_Print(stderr, P_VALUE_FMT, Inter);
527 #endif
528
529 // if Inter has only one column there is no pivot, the result is empty.
530 if(Inter->NbColumns == 1) {
531 Matrix_Free(Inter);
532 Matrix_Free(X);
533 return(NULL);
534 }
535
536 // Prepare for main loop:
537 // rest will be the rest of the lattice X to be treated
538 // (Intersection on first row(s)/column(s), X on bottom-right)
539 rest = Matrix_Copy(X);
540
541 // -------------- MAIN LOOP: column scan --------------------
542
543 // add each matrix with the row variant to the Result
544 for(int column = 0; column < Inter->NbColumns - 1; column++) {
545 int row;
546 for (row = 0; row < Inter->NbRows - 1; row++) {
547 if(value_notzero_p(Inter->p[row][column]))
548 break;
549 }
550 if(row == Inter->NbRows - 1) {
551 // no more pivot
552 break;
553 // // there is a problem, trying to compute an infinite lattice union
554 // errormsg1("LatticeDifference", "dimincomp",
555 // "Difference is infinite (incompatible dimensions: columns)");
556 // LatticeUnion_Free(Result);
557 // Result = NULL;
558 // goto LD_cleanup;
559 }
560 #ifdef LATDIF_DEBUG
561 fprintf(stderr, "+++ Enter main loop (%d, %d)\n", row, column);
562 fprintf(stderr, "+++ rest =\n");
563 Matrix_Print(stderr, P_VALUE_FMT, rest);
564 #endif
565
566 // this function does all the hard work:
567 Result = generate_lattice_union_row(row, column, X, Inter, rest, Result);
568 #ifdef LATDIF_DEBUG
569 fprintf(stderr, "+++ Intermediate result =\n");
570 PrintLatticeUnion(stderr, P_VALUE_FMT, Result);
571 #endif
572 }
573 // ------------ END MAIN LOOP --------------------
574
575 #ifdef LATDIF_DEBUG
576 if(!Result)
577 fprintf(stderr, "Empty Result\n");
578 fprintf(stderr, "--- Exit LatDiff ---\n\n");
579 #endif
580
581// LD_cleanup:
582 // cleanup
583 Matrix_Free(Inter);
584 Matrix_Free(rest);
585 Matrix_Free(X);
586
587 return Result;
588} /* LatticeDifference */
589
590
591/*
592 * Compute the intersection between two lattices.
593 * If the result is empty return NULL.
594 *
595 * Algorithm:
596 * Let:
597 * A = A' | a B = B' | b
598 * 0..0 | 1 0..0 | 1
599 *
600 * Build matrix Tmp as:
601 * 1 0...0 | 1 0...0
602 * a A' | b B'
603 * ------------+--------------
604 * 1 0...0 | 0 .. 0
605 * a A' | 0 .. 0
606 *
607 * Then computes H = left Hermite of Tmp
608 * H is of the form:
609 * H = D | 0 ... 0 D is a square matrix if A and B are square
610 * -----+-----------
611 * X | 1 0 ... 0
612 * | r R
613 *
614 * with R | r
615 * 0...0 | 1 being our result
616 *
617 * if the number above r is not 1 then the intersection is not integer
618 * (there is no solution to the intersection)
619 */
621{
622 Matrix *Tmp, *H, *Res;
623 #ifdef LATINTER_DEBUG
624 fprintf(stderr,"---Entering LatInter---\nMatrix A = ");
625 Matrix_Print(stderr, P_VALUE_FMT, A);
626 fprintf(stderr,"Matrix B = ");
627 Matrix_Print(stderr, P_VALUE_FMT, B);
628 #endif
629 if(A->NbRows != B->NbRows){
630 errormsg1("LatticeIntersection", "dimincomp", "incompatible dimensions!");
631 return NULL;
632 }
633
634 Tmp = Matrix_Alloc(A->NbRows*2, A->NbColumns + B->NbColumns);
635
636 // copying A in Tmp (twice):
637 value_assign(Tmp->p[0][0], A->p[A->NbRows-1][A->NbColumns-1]);
638 value_assign(Tmp->p[A->NbRows][0], A->p[A->NbRows-1][A->NbColumns-1]);
639 // constant vector a
640 for(int i = 1; i < A->NbRows; i++) {
641 value_assign(Tmp->p[i][0], A->p[i-1][A->NbColumns-1]);
642 value_assign(Tmp->p[i+A->NbRows][0], A->p[i-1][A->NbColumns-1]);
643 }
644 // matrix kernel A'
645 for(int i = 1 ; i < A->NbRows; i++) {
646 for(int j = 1; j < A->NbColumns; j++){
647 value_assign(Tmp->p[i][j], A->p[i-1][j-1]);
648 value_assign(Tmp->p[i+A->NbRows][j], A->p[i-1][j-1]);
649 }
650 }
651
652 // copying B into Tmp:
653 value_assign(Tmp->p[0][A->NbColumns], B->p[B->NbRows-1][B->NbColumns-1]);
654 // constant vector b
655 for (int i = 1; i < B->NbRows; i++) {
656 value_assign(Tmp->p[i][A->NbColumns], B->p[i-1][B->NbColumns-1]);
657 }
658 // matrix kernel B'
659 for (int i = 1; i < B->NbRows; i++){
660 for (int j = 1; j < B->NbColumns; j++) {
661 value_assign(Tmp->p[i][j+A->NbColumns], B->p[i-1][j-1]);
662 }
663 }
664 #ifdef LATINTER_DEBUG
665 fprintf(stderr,"H init = ");
666 Matrix_Print(stderr, P_VALUE_FMT, Tmp);
667 #endif
668
669 left_hermite(Tmp, &H, NULL, NULL);
670 #ifdef LATINTER_DEBUG
671 fprintf(stderr,"\nH = ");
672 Matrix_Print(stderr,P_VALUE_FMT,H);
673 #endif
674 Matrix_Free(Tmp);
675
676 // count the number of columns of zeros on the first NbRows rows of H.
677 // the matrix has A->NbColumns + B-> NbColumns columns.
678 int nbcol = 0;
679 for(int col_num = H->NbColumns-1 ; col_num >= 0; col_num--) {
680 int i;
681 for(i = 0; i < A->NbRows; i++) {
682 if(value_notzero_p(H->p[i][col_num]))
683 break;
684 }
685 if(i != A->NbRows) { // there is a non-zero value
686 break;
687 }
688 nbcol++;
689 }
690
691 if(value_notone_p(H->p[A->NbRows][H->NbColumns - nbcol])) {
692 #ifdef LATINTER_DEBUG
693 fprintf(stderr,"\nEmpty intersection\n");
694 #endif
695 Matrix_Free(H);
696 return NULL;
697 }
698
699 Res = Matrix_Alloc(A->NbRows, nbcol);
700 for (int i = 0; i < Res->NbRows; i++) {
701 for (int j = 0; j < Res->NbColumns; j++) {
702 value_assign(Res->p[i][j],
703 H->p[i + H->NbRows - Res->NbRows][j + H->NbColumns - Res->NbColumns]);
704 }
705 }
706 Matrix_Free(H);
708 #ifdef LATINTER_DEBUG
709 fprintf(stderr, "\nLatticeIntersection result = ");
710 Matrix_Print(stderr, P_VALUE_FMT, Res);
711 fprintf(stderr,"---Exiting LatInter---\n\n");
712 #endif
713
714 return(Res);
715}
716
717
718// Utilities for LatticeDifference:
719
720/*
721 * Compute the prime factors of Value n, including n itself if it is prime.
722 * reuses or allocates a Vector of Values
723 * returns the number of values put into the result
724 *
725 * *result is a vector of Values, that can be larger than the return value
726 */
727static int value_prime_factors(Value n, Vector **result)
728{
729 if(!*result) {
730 // allocate if NULL
731 *result = Vector_Alloc(10);
732 }
733
734 int tabsize = 0; // current size
735 Value div, rest, two, tmp;
736 value_init(div);
737 value_init(rest);
738 value_init(two);
739 value_init(tmp); // temp variable for tests
740
741 value_set_si(div, 2);
742 value_assign(rest, n);
743 value_set_si(two, 2);
744
745 while(True) {
746 value_multiply(tmp, div, div);
747 if(value_gt(tmp, rest)) // if(div * div > rest)
748 break; // exit while
749
750 value_modulus(tmp, rest, div);
751 if(value_zero_p(tmp)) { // if(rest % div == 0)
752
753 if((*result)->Size == tabsize) { // increase vector size if needed
754 *result = Vector_Realloc((*result), (*result)->Size * 2);
755 }
756 // add div to result
757 value_assign((*result)->p[tabsize], div);
758 tabsize++;
759
760 value_division(rest, rest, div); // rest /= div;
761 }
762 else{
763 // div = 2 / 3, 5, 7, 9, 11, ...
764 if(value_eq(div, two)) // if(div == 2)
765 value_set_si(div, 3); // div = 3;
766 else
767 value_addto(div, div, two); // div += 2;
768 }
769 }
770
771 // if something's left add it to the result:
772 if(value_notone_p(rest)) {
773 if((*result)->Size == tabsize){
774 (*result) = Vector_Realloc((*result), (*result)->Size+1);
775 }
776 value_assign((*result)->p[tabsize], rest);
777 tabsize++;
778 }
779 value_clear(rest);
780 value_clear(div);
781 value_clear(two);
782 value_clear(tmp);
783
784 return (tabsize);
785}
786
787
788/*
789 * Generate all variants of the pivot on line 'line_nb' in lattice matrix A
790 * - add all variants not intersecting Intersection to Result
791 * - replace the corresponding line of the rest by the intersection
792 * - replace the corresponding column of the rest by the intersection
793*
794 * The intersection line is used as a basis reference lattice, and all
795 * variants of the corresponding line in A are generated:
796 * if Intersection contains line "*..* p 0..0 c"
797 * and the corresponding pivot of A is pA
798 * then generate new lines : *..* p 0..0 c+pA; *..* p 0..0 c+2pA;
799 * *..* p 0..0 c+3pA; ...
800 * (optimized: p is decomposed in prime factors)
801 *
802 * Adjust the lines below (that need to be updated since p changes):
803 * - coefficients below the pivot p
804 * - constants for the non-zero coefficients
805 *
806 * Add all newly generated lattices to Result, and return the new Result.
807 */
809 int pivot_col, Matrix *A, Matrix *Intersection, Matrix *rest,
810 LatticeUnion *Result)
811{
812 Value step, multiply, modulo, ratio, tmp;
813 Vector *prime_factors = NULL; // Vector of Values, reuse memory several times
814 // (from previous step).
815 int num_factors;
816
817 value_init(step);
818 value_init(multiply);
819 value_init(modulo);
820 value_init(ratio);
821 value_init(tmp); // for computing tests on values
822
823
824 // simplify directly when building
825
826 // replace the current line in the rest with the one from the intersection
827 // will consider this line as basis for generating all variants
828 for(int i = 0; i < rest->NbColumns; i++) {
829 value_assign(rest->p[line_nb][i], Intersection->p[line_nb][i]);
830 }
831 // no need to update the constant of lines below the pivot here
832
833 // get the ratio between A and rest, to be used as multiplier for every
834 // generated new line
835 value_division(ratio, rest->p[line_nb][pivot_col], A->p[line_nb][pivot_col]);
836
837 #ifdef LATDIF_DEBUG
838 fprintf(stderr, "Considering line %d. Rest pivot = ", line_nb);
839 value_print(stderr, P_VALUE_FMT, rest->p[line_nb][pivot_col]);
840 fprintf(stderr, " Ratio = ");
841 value_print(stderr, P_VALUE_FMT, ratio);
842 fprintf(stderr, "\n");
843 #endif
844
845 // consider the decomposition in prime factors of the "pivot" = ratio
846 // (inters. pivot / A pivot):
847 // if the "pivot" is 15, will take out the right p%3==0/1/2 and p%5==0/1/2/3/4
848 // only one case p%15=c (the intersection) will not enter these (combination
849 // of) cases :)
850 // can be empty, if p=1 then size=0 and the whole loop is skipped.
851 // if a prime factor appears multiple times, multiply-accumulate:
852 // (2,2,2) -> (2,4,8)
853 num_factors = value_prime_factors(ratio, &prime_factors);
854 // prime factors of pivot ratio.
855
856 // scan the prime factors: prime_factors->p[p].
857 for(int p = 0; p < num_factors; p++) {
858 // if the previous prime factor is the same:
859 // example with: 3*3*3
860 // - step 0: m=3, it=1 (init=0):
861 // 3i + 0/1/2 -> if 3i+1 is the intersection, take out 3i+0 and 3i+2
862 // (add to result).
863 // Next step will not consider 3 * these (so 9i+0/3/6 and 9i+2/5/8).
864 // - step 1: m=9, it=3, (init=1):
865 // 9i + 1/4/7 -> if 9i+7 is the intersection, take out 9i+1 and 9i+4
866 // - step 2: m=27, it=9, (init=7):
867 // 27i+ 7/16/25
868
869 // general case:
870 // if same prime factor as previously:
871 // * iterator step = previous multiplier
872 // * multiply = prime factor * previous multiplier
873 // else (new multiplier):
874 // * iteration step = 1 (* initial pivot of A)
875 // * multiply = prime factor (* initial pivot of A)
876 // (initial pivot of A always divides the pivot of the intersection)
877 if(p>0 && value_eq(prime_factors->p[p-1], prime_factors->p[p])) {
878 value_assign(step, multiply);
879 // step = multiply (from previous iteration)
880 value_multiply(multiply, multiply, prime_factors->p[p]);
881 // multiply = multiply*prime_factors->p[p];
882 }
883 else {
884 value_assign(step, A->p[line_nb][pivot_col]);
885 value_multiply(multiply, prime_factors->p[p], A->p[line_nb][pivot_col]);
886 }
887 #ifdef LATDIF_DEBUG
888 fprintf(stderr, "multiply = ");
889 value_print(stderr, P_VALUE_FMT, multiply);
890 fprintf(stderr, ", step = ");
891 value_print(stderr, P_VALUE_FMT, step);
892 fprintf(stderr, "\n");
893 #endif
894
895 // Iterate on each possible 'modulo':
896 // from a possible intersection value, to 'multiply', with step 'step'
897 // -> init loop value = intersection constant % iterator step
898 for(value_modulus(modulo,
899 Intersection->p[line_nb][Intersection->NbColumns-1], step);
900 value_lt(modulo, multiply);
901 value_addto(modulo, modulo, step)) {
902 // consider line: multiply * x + modulo
903 #ifdef LATDIF_DEBUG
904 fprintf(stderr, " -> considering line: ");
905 value_print(stderr, P_VALUE_FMT, multiply);
906 fprintf(stderr, " * x + ");
907 value_print(stderr, P_VALUE_FMT, modulo);
908 #endif
909
910 value_modulus(tmp, Intersection->p[line_nb][Intersection->NbColumns-1],
911 multiply);
912 if(value_eq(tmp, modulo)) {
913 // no need to do anything there, this modulo hits the intersection
914 // and will be considered in the rest :)
915 #ifdef LATDIF_DEBUG
916 fprintf(stderr, " -> part of the intersection, ignoring\n");
917 #endif
918 }
919 else {
920 LatticeUnion *newResult;
921 // this line does not hit the intersection, add it to the result.
922 #ifdef LATDIF_DEBUG
923 fprintf(stderr, " -> add it to result\n");
924 #endif
925
926 Matrix *newLat = Matrix_Copy(rest); // get a copy of rest
927 // and update current line. New pivot:
928 value_assign(newLat->p[line_nb][pivot_col], multiply);
929 // New constant:
930 value_assign(newLat->p[line_nb][newLat->NbColumns-1], modulo);
931
932 // adjust the rows below: they change depending on the changed pivot
933 // and constant: if a coefficient below the pivot is not zero, set
934 // it to the intersection coef., and recompute the constant
935 // accordingly (adding (modulo/step))
936 for(int ll = line_nb + 1; ll < A->NbRows; ll++) {
937 if(value_notzero_p(newLat->p[ll][pivot_col])) {
938 // new coefficient: set it to the one of the intersection
939 value_assign(newLat->p[ll][pivot_col],
940 Intersection->p[ll][pivot_col]);
941 // adjust constant:
942 value_division(tmp, modulo, step); // iteration number 0/1/2/...
943 value_addmul(newLat->p[ll][newLat->NbColumns-1],
944 tmp, A->p[ll][pivot_col]); // multiplied by pivot A
945 }
946 }
947
948 // link newResult to Result
949 newResult = LatticeUnion_Alloc();
950 newResult->M = NULL; // set by Hermite
951 newResult->next = Result;
952 Result = newResult;
953 // transforms the new lattice to HNF and store it into Result
954 AffineHermite(newLat, &Result->M, NULL);
955 Matrix_Free(newLat);
956 }
957 }
958 }
959
960 // adjust the column below the pivot in rest (from the intersection)
961 for(int ll = line_nb+1; ll < A->NbRows; ll++) {
962 value_assign(rest->p[ll][pivot_col], Intersection->p[ll][pivot_col]);
963 }
964
965 // cleanup
966 if(prime_factors)
968 value_clear(tmp);
969 value_clear(ratio);
970 value_clear(modulo);
971 value_clear(multiply);
972 value_clear(step);
973
974 return (Result);
975} /* generate_lattice_union_row */
LatticeUnion * LatticeUnion_Alloc(void)
Definition: Lattice.c:43
LatticeUnion * LatticeDifference(Matrix *A, Matrix *B)
Definition: Lattice.c:423
void Matrix_Move_Homogeneous_Dim_First(Matrix *A)
Definition: Lattice.c:71
int LatCountZeroCols(Matrix *M)
Definition: Lattice.c:312
static LatticeUnion * generate_lattice_union_row(int row, int column, Matrix *A, Matrix *Intersection, Matrix *L, LatticeUnion *Result)
Definition: Lattice.c:808
Bool isSameLatticeSpace(Matrix *A, Matrix *B)
Definition: Lattice.c:356
Matrix * LatticeIntersection(Matrix *A, Matrix *B)
Definition: Lattice.c:620
Bool isEqualLattice(Matrix *A, Matrix *B)
Definition: Lattice.c:394
void AffineHermite(Matrix *A, Matrix **H, Matrix **U)
Definition: Lattice.c:221
static int value_prime_factors(Value n, Vector **result)
Definition: Lattice.c:727
Bool isNormalLattice(Matrix *A)
Definition: Lattice.c:136
void LatticeUnion_Free(LatticeUnion *Head)
Definition: Lattice.c:29
Bool isEmptyLattice(Matrix *A)
Definition: Lattice.c:57
Bool LatticeIncluded(Matrix *A, Matrix *B)
Definition: Lattice.c:336
void PrintLatticeUnion(FILE *fp, char *format, LatticeUnion *Head)
Definition: Lattice.c:16
void Matrix_Move_Homogeneous_Dim_Last(Matrix *A)
Definition: Lattice.c:107
Matrix * Matrix_Copy(Matrix const *Src)
Definition: Matop.c:98
#define value_gt(v1, v2)
Definition: arithmetique.h:507
#define value_notzero_p(val)
Definition: arithmetique.h:579
#define value_notone_p(val)
Definition: arithmetique.h:581
#define value_ne(v1, v2)
Definition: arithmetique.h:506
#define value_zero_p(val)
Definition: arithmetique.h:578
#define value_assign(v1, v2)
Definition: arithmetique.h:485
int Value
Definition: arithmetique.h:294
#define value_set_si(val, i)
Definition: arithmetique.h:486
#define value_addmul(ref, val1, val2)
Definition: arithmetique.h:542
#define value_eq(v1, v2)
Definition: arithmetique.h:505
#define value_clear(val)
Definition: arithmetique.h:488
#define value_division(ref, val1, val2)
Definition: arithmetique.h:550
#define value_multiply(ref, val1, val2)
Definition: arithmetique.h:546
#define value_print(Dst, fmt, val)
Definition: arithmetique.h:490
#define value_lt(v1, v2)
Definition: arithmetique.h:509
#define value_modulus(ref, val1, val2)
Definition: arithmetique.h:552
#define value_addto(ref, val1, val2)
Definition: arithmetique.h:540
#define value_ge(v1, v2)
Definition: arithmetique.h:508
#define value_neg_p(val)
Definition: arithmetique.h:575
#define value_init(val)
Definition: arithmetique.h:484
void errormsg1(const char *f, const char *msgname, const char *msg)
Definition: errormsg.c:25
factor prime_factors(int n)
Definition: factors.c:11
Matrix * Matrix_Alloc(unsigned NbRows, unsigned NbColumns)
Definition: matrix.c:24
void Matrix_Print(FILE *Dst, const char *Format, Matrix *Mat)
Definition: matrix.c:118
void left_hermite(Matrix *A, Matrix **Hp, Matrix **Qp, Matrix **Up)
Definition: matrix.c:523
void Matrix_Free(Matrix *Mat)
Definition: matrix.c:69
static int n
Definition: polyparam.c:278
Definition: types.h:82
Matrix * M
Definition: types.h:239
struct lattice_union * next
Definition: types.h:240
Definition: types.h:88
unsigned NbRows
Definition: types.h:89
Value ** p
Definition: types.h:90
unsigned NbColumns
Definition: types.h:89
Bool
Definition: types.h:45
@ True
Definition: types.h:45
@ False
Definition: types.h:45
#define P_VALUE_FMT
Definition: types.h:42
void Vector_Free(Vector *vector)
Definition: vector.c:187
void Vector_Set(Value *p, int n, unsigned length)
Definition: vector.c:248
Vector * Vector_Alloc(unsigned length)
Definition: vector.c:134
Vector * Vector_Realloc(Vector *V, unsigned newlength)
Definition: vector.c:160