/*---------------------------------------------------------------------*/ static int exist_points(int pos,Polyhedron *Pol,Value *context) { Value LB, UB, k,tmp; value_init(LB); value_init(UB); value_init(k); value_init(tmp); value_set_si(LB,0); value_set_si(UB,0); /* Problem if UB or LB is INFINITY */ if (lower_upper_bounds(pos,Pol,context,&LB,&UB) !=0) { errormsg1("exist_points", "infdom", "infinite domain"); value_clear(LB); value_clear(UB); value_clear(k); value_clear(tmp); return -1; } value_set_si(context[pos],0); if(value_lt(UB,LB)) { value_clear(LB); value_clear(UB); value_clear(k); value_clear(tmp); return 0; } if (!Pol->next) { value_subtract(tmp,UB,LB); value_increment(tmp,tmp); value_clear(UB); value_clear(LB); value_clear(k); return (value_pos_p(tmp)); } for (value_assign(k,LB);value_le(k,UB);value_increment(k,k)) { /* insert k in context */ value_assign(context[pos],k); if (exist_points(pos+1,Pol->next,context) > 0 ) { value_clear(LB); value_clear(UB); value_clear(k); value_clear(tmp); return 1; } } /* Reset context */ value_set_si(context[pos],0); value_clear(UB); value_clear(LB); value_clear(k); value_clear(tmp); return 0; }
/* * Subtract two vectors 'p1' and 'p2' and store the result in 'p3' */ void Vector_Sub(Value *p1,Value *p2,Value *p3,unsigned length) { Value *cp1, *cp2, *cp3; int i; cp1=p1; cp2=p2; cp3=p3; for (i=0;i<length;i++) { /* *cp3++= *cp1++ - *cp2++ */ value_subtract(*cp3,*cp1,*cp2); cp1++; cp2++; cp3++; } } /* Vector_Sub */
/* * Given a rational matrix 'Mat'(k x k), compute its inverse rational matrix * 'MatInv' k x k. * The output is 1, * if 'Mat' is non-singular (invertible), otherwise the output is 0. Note:: * (1) Matrix 'Mat' is modified during the inverse operation. * (2) Matrix 'MatInv' must be preallocated before passing into this function. */ int Matrix_Inverse(Matrix *Mat,Matrix *MatInv ) { int i, k, j, c; Value x, gcd, piv; Value m1,m2; Value *den; if(Mat->NbRows != Mat->NbColumns) { fprintf(stderr,"Trying to invert a non-square matrix !\n"); return 0; } /* Initialize all the 'Value' variables */ value_init(x); value_init(gcd); value_init(piv); value_init(m1); value_init(m2); k = Mat->NbRows; /* Initialise MatInv */ Vector_Set(MatInv->p[0],0,k*k); /* Initialize 'MatInv' to Identity matrix form. Each diagonal entry is set*/ /* to 1. Last column of each row (denominator of each entry in a row) is */ /* also set to 1. */ for(i=0;i<k;++i) { value_set_si(MatInv->p[i][i],1); /* value_set_si(MatInv->p[i][k],1); /* denum */ } /* Apply Gauss-Jordan elimination method on the two matrices 'Mat' and */ /* 'MatInv' in parallel. */ for(i=0;i<k;++i) { /* Check if the diagonal entry (new pivot) is non-zero or not */ if(value_zero_p(Mat->p[i][i])) { /* Search for a non-zero pivot down the column(i) */ for(j=i;j<k;++j) if(value_notzero_p(Mat->p[j][i])) break; /* If no non-zero pivot is found, the matrix 'Mat' is non-invertible */ /* Return 0. */ if(j==k) { /* Clear all the 'Value' variables */ value_clear(x); value_clear(gcd); value_clear(piv); value_clear(m1); value_clear(m2); return 0; } /* Exchange the rows, row(i) and row(j) so that the diagonal element */ /* Mat->p[i][i] (pivot) is non-zero. Repeat the same operations on */ /* matrix 'MatInv'. */ for(c=0;c<k;++c) { /* Interchange rows, row(i) and row(j) of matrix 'Mat' */ value_assign(x,Mat->p[j][c]); value_assign(Mat->p[j][c],Mat->p[i][c]); value_assign(Mat->p[i][c],x); /* Interchange rows, row(i) and row(j) of matrix 'MatInv' */ value_assign(x,MatInv->p[j][c]); value_assign(MatInv->p[j][c],MatInv->p[i][c]); value_assign(MatInv->p[i][c],x); } } /* Make all the entries in column(i) of matrix 'Mat' zero except the */ /* diagonal entry. Repeat the same sequence of operations on matrix */ /* 'MatInv'. */ for(j=0;j<k;++j) { if (j==i) continue; /* Skip the pivot */ value_assign(x,Mat->p[j][i]); if(value_notzero_p(x)) { value_assign(piv,Mat->p[i][i]); value_gcd(gcd, x, piv); if (value_notone_p(gcd) ) { value_divexact(x, x, gcd); value_divexact(piv, piv, gcd); } for(c=((j>i)?i:0);c<k;++c) { value_multiply(m1,piv,Mat->p[j][c]); value_multiply(m2,x,Mat->p[i][c]); value_subtract(Mat->p[j][c],m1,m2); } for(c=0;c<k;++c) { value_multiply(m1,piv,MatInv->p[j][c]); value_multiply(m2,x,MatInv->p[i][c]); value_subtract(MatInv->p[j][c],m1,m2); } /* Simplify row(j) of the two matrices 'Mat' and 'MatInv' by */ /* dividing the rows with the common GCD. */ Vector_Gcd(&MatInv->p[j][0],k,&m1); Vector_Gcd(&Mat->p[j][0],k,&m2); value_gcd(gcd, m1, m2); if(value_notone_p(gcd)) { for(c=0;c<k;++c) { value_divexact(Mat->p[j][c], Mat->p[j][c], gcd); value_divexact(MatInv->p[j][c], MatInv->p[j][c], gcd); } } } } } /* Find common denom for each row */ den = (Value *)malloc(k*sizeof(Value)); value_set_si(x,1); for(j=0 ; j<k ; ++j) { value_init(den[j]); value_assign(den[j],Mat->p[j][j]); /* gcd is always positive */ Vector_Gcd(&MatInv->p[j][0],k,&gcd); value_gcd(gcd, gcd, den[j]); if (value_neg_p(den[j])) value_oppose(gcd,gcd); /* make denominator positive */ if (value_notone_p(gcd)) { for (c=0; c<k; c++) value_divexact(MatInv->p[j][c], MatInv->p[j][c], gcd); /* normalize */ value_divexact(den[j], den[j], gcd); } value_gcd(gcd, x, den[j]); value_divexact(m1, den[j], gcd); value_multiply(x,x,m1); } if (value_notone_p(x)) for(j=0 ; j<k ; ++j) { for (c=0; c<k; c++) { value_division(m1,x,den[j]); value_multiply(MatInv->p[j][c],MatInv->p[j][c],m1); /* normalize */ } } /* Clear all the 'Value' variables */ for(j=0 ; j<k ; ++j) { value_clear(den[j]); } value_clear(x); value_clear(gcd); value_clear(piv); value_clear(m1); value_clear(m2); free(den); return 1; } /* Matrix_Inverse */
/* * Basic hermite engine */ static int hermite(Matrix *H,Matrix *U,Matrix *Q) { int nc, nr, i, j, k, rank, reduced, pivotrow; Value pivot,x,aux; Value *temp1, *temp2; /* T -1 T */ /* Computes form: A = Q H and U A = H and U = Q */ if (!H) { errormsg1("Domlib", "nullH", "hermite: ? Null H"); return -1; } nc = H->NbColumns; nr = H->NbRows; temp1 = (Value *) malloc(nc * sizeof(Value)); temp2 = (Value *) malloc(nr * sizeof(Value)); if (!temp1 ||!temp2) { errormsg1("Domlib", "outofmem", "out of memory space"); return -1; } /* Initialize all the 'Value' variables */ value_init(pivot); value_init(x); value_init(aux); for(i=0;i<nc;i++) value_init(temp1[i]); for(i=0;i<nr;i++) value_init(temp2[i]); #ifdef DEBUG fprintf(stderr,"Start -----------\n"); Matrix_Print(stderr,0,H); #endif for (k=0, rank=0; k<nc && rank<nr; k=k+1) { reduced = 1; /* go through loop the first time */ #ifdef DEBUG fprintf(stderr, "Working on col %d. Rank=%d ----------\n", k+1, rank+1); #endif while (reduced) { reduced=0; /* 1. find pivot row */ value_absolute(pivot,H->p[rank][k]); /* the kth-diagonal element */ pivotrow = rank; /* find the row i>rank with smallest nonzero element in col k */ for (i=rank+1; i<nr; i++) { value_absolute(x,H->p[i][k]); if (value_notzero_p(x) && (value_lt(x,pivot) || value_zero_p(pivot))) { value_assign(pivot,x); pivotrow = i; } } /* 2. Bring pivot to diagonal (exchange rows pivotrow and rank) */ if (pivotrow != rank) { Vector_Exchange(H->p[pivotrow],H->p[rank],nc); if (U) Vector_Exchange(U->p[pivotrow],U->p[rank],nr); if (Q) Vector_Exchange(Q->p[pivotrow],Q->p[rank],nr); #ifdef DEBUG fprintf(stderr,"Exchange rows %d and %d -----------\n", rank+1, pivotrow+1); Matrix_Print(stderr,0,H); #endif } value_assign(pivot,H->p[rank][k]); /* actual ( no abs() ) pivot */ /* 3. Invert the row 'rank' if pivot is negative */ if (value_neg_p(pivot)) { value_oppose(pivot,pivot); /* pivot = -pivot */ for (j=0; j<nc; j++) value_oppose(H->p[rank][j],H->p[rank][j]); /* H->p[rank][j] = -(H->p[rank][j]); */ if (U) for (j=0; j<nr; j++) value_oppose(U->p[rank][j],U->p[rank][j]); /* U->p[rank][j] = -(U->p[rank][j]); */ if (Q) for (j=0; j<nr; j++) value_oppose(Q->p[rank][j],Q->p[rank][j]); /* Q->p[rank][j] = -(Q->p[rank][j]); */ #ifdef DEBUG fprintf(stderr,"Negate row %d -----------\n", rank+1); Matrix_Print(stderr,0,H); #endif } if (value_notzero_p(pivot)) { /* 4. Reduce the column modulo the pivot */ /* This eventually zeros out everything below the */ /* diagonal and produces an upper triangular matrix */ for (i=rank+1;i<nr;i++) { value_assign(x,H->p[i][k]); if (value_notzero_p(x)) { value_modulus(aux,x,pivot); /* floor[integer division] (corrected for neg x) */ if (value_neg_p(x) && value_notzero_p(aux)) { /* x=(x/pivot)-1; */ value_division(x,x,pivot); value_decrement(x,x); } else value_division(x,x,pivot); for (j=0; j<nc; j++) { value_multiply(aux,x,H->p[rank][j]); value_subtract(H->p[i][j],H->p[i][j],aux); } /* U->p[i][j] -= (x * U->p[rank][j]); */ if (U) for (j=0; j<nr; j++) { value_multiply(aux,x,U->p[rank][j]); value_subtract(U->p[i][j],U->p[i][j],aux); } /* Q->p[rank][j] += (x * Q->p[i][j]); */ if (Q) for(j=0;j<nr;j++) { value_addmul(Q->p[rank][j], x, Q->p[i][j]); } reduced = 1; #ifdef DEBUG fprintf(stderr, "row %d = row %d - %d row %d -----------\n", i+1, i+1, x, rank+1); Matrix_Print(stderr,0,H); #endif } /* if (x) */ } /* for (i) */ } /* if (pivot != 0) */ } /* while (reduced) */ /* Last finish up this column */ /* 5. Make pivot column positive (above pivot row) */ /* x should be zero for i>k */ if (value_notzero_p(pivot)) { for (i=0; i<rank; i++) { value_assign(x,H->p[i][k]); if (value_notzero_p(x)) { value_modulus(aux,x,pivot); /* floor[integer division] (corrected for neg x) */ if (value_neg_p(x) && value_notzero_p(aux)) { value_division(x,x,pivot); value_decrement(x,x); /* x=(x/pivot)-1; */ } else value_division(x,x,pivot); /* H->p[i][j] -= x * H->p[rank][j]; */ for (j=0; j<nc; j++) { value_multiply(aux,x,H->p[rank][j]); value_subtract(H->p[i][j],H->p[i][j],aux); } /* U->p[i][j] -= x * U->p[rank][j]; */ if (U) for (j=0; j<nr; j++) { value_multiply(aux,x,U->p[rank][j]); value_subtract(U->p[i][j],U->p[i][j],aux); } /* Q->p[rank][j] += x * Q->p[i][j]; */ if (Q) for (j=0; j<nr; j++) { value_addmul(Q->p[rank][j], x, Q->p[i][j]); } #ifdef DEBUG fprintf(stderr, "row %d = row %d - %d row %d -----------\n", i+1, i+1, x, rank+1); Matrix_Print(stderr,0,H); #endif } /* if (x) */ } /* for (i) */ rank++; } /* if (pivot!=0) */ } /* for (k) */ /* Clear all the 'Value' variables */ value_clear(pivot); value_clear(x); value_clear(aux); for(i=0;i<nc;i++) value_clear(temp1[i]); for(i=0;i<nr;i++) value_clear(temp2[i]); free(temp2); free(temp1); return rank; } /* Hermite */
/** * Tests Constraints_fullDimensionize by comparing the Ehrhart polynomials * @param A the input set of constraints * @param B the corresponding context * @param the number of samples to generate for the test * @return 1 if the Ehrhart polynomial had the same value for the * full-dimensional and non-full-dimensional sets of constraints, for their * corresponding sample parameters values. */ int test_Constraints_fullDimensionize(Matrix * A, Matrix * B, unsigned int nbSamples) { Matrix * Eqs= NULL, *ParmEqs=NULL, *VL=NULL; unsigned int * elimVars=NULL, * elimParms=NULL; Matrix * sample, * smallerSample=NULL; Matrix * transfSample=NULL; Matrix * parmVL=NULL; unsigned int i, j, r, nbOrigParms, nbParms; Value div, mod, *origVal=NULL, *fullVal=NULL; Matrix * VLInv; Polyhedron * P, *PC; Matrix * M, *C; Enumeration * origEP, * fullEP=NULL; const char **fullNames = NULL; int isOk = 1; /* holds the result */ /* compute the origial Ehrhart polynomial */ M = Matrix_Copy(A); C = Matrix_Copy(B); P = Constraints2Polyhedron(M, maxRays); PC = Constraints2Polyhedron(C, maxRays); origEP = Polyhedron_Enumerate(P, PC, maxRays, origNames); Matrix_Free(M); Matrix_Free(C); Polyhedron_Free(P); Polyhedron_Free(PC); /* compute the full-dimensional polyhedron corresponding to A and its Ehrhart polynomial */ M = Matrix_Copy(A); C = Matrix_Copy(B); nbOrigParms = B->NbColumns-2; Constraints_fullDimensionize(&M, &C, &VL, &Eqs, &ParmEqs, &elimVars, &elimParms, maxRays); if ((Eqs->NbRows==0) && (ParmEqs->NbRows==0)) { Matrix_Free(M); Matrix_Free(C); Matrix_Free(Eqs); Matrix_Free(ParmEqs); free(elimVars); free(elimParms); return 1; } nbParms = C->NbColumns-2; P = Constraints2Polyhedron(M, maxRays); PC = Constraints2Polyhedron(C, maxRays); namesWithoutElim(origNames, nbOrigParms, elimParms, &fullNames); fullEP = Polyhedron_Enumerate(P, PC, maxRays, fullNames); Matrix_Free(M); Matrix_Free(C); Polyhedron_Free(P); Polyhedron_Free(PC); /* make a set of sample parameter values and compare the corresponding Ehrhart polnomials */ sample = Matrix_Alloc(1,nbOrigParms); transfSample = Matrix_Alloc(1, nbParms); Lattice_extractSubLattice(VL, nbParms, &parmVL); VLInv = Matrix_Alloc(parmVL->NbRows, parmVL->NbRows+1); MatInverse(parmVL, VLInv); if (dbg) { show_matrix(parmVL); show_matrix(VLInv); } srand(nbSamples); value_init(mod); value_init(div); for (i = 0; i< nbSamples; i++) { /* create a random sample */ for (j=0; j< nbOrigParms; j++) { value_set_si(sample->p[0][j], rand()%100); } /* compute the corresponding value for the full-dimensional constraints */ valuesWithoutElim(sample, elimParms, &smallerSample); /* (N' i' 1)^T = VLinv.(N i 1)^T*/ for (r = 0; r < nbParms; r++) { Inner_Product(&(VLInv->p[r][0]), smallerSample->p[0], nbParms, &(transfSample->p[0][r])); /* add the constant part */ value_addto(transfSample->p[0][r], transfSample->p[0][r], VLInv->p[r][VLInv->NbColumns-2]); value_pdivision(div, transfSample->p[0][r], VLInv->p[r][VLInv->NbColumns-1]); value_subtract(mod, transfSample->p[0][r], div); /* if the parameters value does not belong to the validity lattice, the Ehrhart polynomial is zero. */ if (!value_zero_p(mod)) { fullEP = Enumeration_zero(nbParms, maxRays); break; } } /* compare the two forms of the Ehrhart polynomial.*/ if (origEP ==NULL) break; /* NULL has loose semantics for EPs */ origVal = compute_poly(origEP, sample->p[0]); fullVal = compute_poly(fullEP, transfSample->p[0]); if (!value_eq(*origVal, *fullVal)) { isOk = 0; printf("EPs don't match. \n Original value = "); value_print(stdout, VALUE_FMT, *origVal); printf("\n Original sample = ["); for (j=0; j<sample->NbColumns; j++) { value_print(stdout, VALUE_FMT, sample->p[0][j]); printf(" "); } printf("] \n EP = "); if(origEP!=NULL) { print_evalue(stdout, &(origEP->EP), origNames); } else { printf("NULL"); } printf(" \n Full-dimensional value = "); value_print(stdout, P_VALUE_FMT, *fullVal); printf("\n full-dimensional sample = ["); for (j=0; j<sample->NbColumns; j++) { value_print(stdout, VALUE_FMT, transfSample->p[0][j]); printf(" "); } printf("] \n EP = "); if(origEP!=NULL) { print_evalue(stdout, &(origEP->EP), fullNames); } else { printf("NULL"); } } if (dbg) { printf("\nOriginal value = "); value_print(stdout, VALUE_FMT, *origVal); printf("\nFull-dimensional value = "); value_print(stdout, P_VALUE_FMT, *fullVal); printf("\n"); } value_clear(*origVal); value_clear(*fullVal); } value_clear(mod); value_clear(div); Matrix_Free(sample); Matrix_Free(smallerSample); Matrix_Free(transfSample); Enumeration_Free(origEP); Enumeration_Free(fullEP); return isOk; } /* test_Constraints_fullDimensionize */