static ppl_Constraint_t cloog_matrix_to_ppl_constraint (CloogMatrix *matrix, int row) { int j; ppl_Constraint_t cstr; ppl_Coefficient_t coef; ppl_Linear_Expression_t expr; ppl_dimension_type dim = matrix->NbColumns - 2; ppl_new_Coefficient (&coef); ppl_new_Linear_Expression_with_dimension (&expr, dim); for (j = 1; j < matrix->NbColumns - 1; j++) { ppl_assign_Coefficient_from_mpz_t (coef, matrix->p[row][j]); ppl_Linear_Expression_add_to_coefficient (expr, j - 1, coef); } ppl_assign_Coefficient_from_mpz_t (coef, matrix->p[row][matrix->NbColumns - 1]); ppl_Linear_Expression_add_to_inhomogeneous (expr, coef); ppl_delete_Coefficient (coef); if (value_zero_p (matrix->p[row][0])) ppl_new_Constraint (&cstr, expr, PPL_CONSTRAINT_TYPE_EQUAL); else ppl_new_Constraint (&cstr, expr, PPL_CONSTRAINT_TYPE_GREATER_OR_EQUAL); ppl_delete_Linear_Expression (expr); return cstr; }
/* * Return the component of 'p' with minimum non-zero absolute value. 'index' * points to the component index that has the minimum value. If no such value * and index is found, Value 1 is returned. */ void Vector_Min_Not_Zero(Value *p,unsigned length,int *index,Value *min) { Value aux; int i; i = First_Non_Zero(p, length); if (i == -1) { value_set_si(*min,1); return; } *index = i; value_absolute(*min, p[i]); value_init(aux); for (i = i+1; i < length; i++) { if (value_zero_p(p[i])) continue; value_absolute(aux, p[i]); if (value_lt(aux,*min)) { value_assign(*min,aux); *index = i; } } value_clear(aux); } /* Vector_Min_Not_Zero */
static Matrix *Polyhedron2standard_form(Polyhedron *P, Matrix **T) { int i, j; int rows; unsigned dim = P->Dimension; Matrix *M2; Matrix *H, *U; Matrix M; assert(P->NbEq == 0); Polyhedron_Remove_Positivity_Constraint(P); for (i = 0; i < P->NbConstraints; ++i) assert(value_zero_p(P->Constraint[i][1+dim])); Polyhedron_Matrix_View(P, &M, P->NbConstraints); H = standard_constraints(&M, 0, &rows, &U); *T = homogenize(U); Matrix_Free(U); M2 = Matrix_Alloc(rows, 2+dim+rows); for (i = dim; i < H->NbRows; ++i) { Vector_Copy(H->p[i], M2->p[i-dim]+1, dim); value_set_si(M2->p[i-dim][1+i], -1); } for (i = 0, j = H->NbRows-dim; i < dim; ++i) { if (First_Non_Zero(H->p[i], i) == -1) continue; Vector_Oppose(H->p[i], M2->p[j]+1, dim); value_set_si(M2->p[j][1+j+dim], 1); ++j; } Matrix_Free(H); return M2; }
enum lp_result PL_polyhedron_opt(Polyhedron *P, Value *obj, Value denom, enum lp_dir dir, Value *opt) { int i; int first = 1; Value val, d; enum lp_result res = lp_empty; POL_ENSURE_VERTICES(P); if (emptyQ(P)) return res; value_init(val); value_init(d); for (i = 0; i < P->NbRays; ++ i) { Inner_Product(P->Ray[i]+1, obj, P->Dimension+1, &val); if (value_zero_p(P->Ray[i][0]) && value_notzero_p(val)) { res = lp_unbounded; break; } if (value_zero_p(P->Ray[i][1+P->Dimension])) { if ((dir == lp_min && value_neg_p(val)) || (dir == lp_max && value_pos_p(val))) { res = lp_unbounded; break; } } else { res = lp_ok; value_multiply(d, denom, P->Ray[i][1+P->Dimension]); if (dir == lp_min) mpz_cdiv_q(val, val, d); else mpz_fdiv_q(val, val, d); if (first || (dir == lp_min ? value_lt(val, *opt) : value_gt(val, *opt))) value_assign(*opt, val); first = 0; } } value_clear(d); value_clear(val); return res; }
int Vector_IsZero(Value * v, unsigned length) { unsigned i; if (value_notzero_p(v[0])) return 0; else { value_set_si(v[0], 1); for (i=length-1; value_zero_p(v[i]); i--); value_set_si(v[0], 0); return (i==0); } }
/** * Computes the intersection of two linear lattices, whose base vectors are * respectively represented in A and B. * If I and/or Lb is set to NULL, then the matrix is allocated. * Else, the matrix is assumed to be allocated already. * I and Lb are rk x rk, where rk is the rank of A (or B). * @param A the full-row rank matrix whose column-vectors are the basis for the * first linear lattice. * @param B the matrix whose column-vectors are the basis for the second linear * lattice. * @param Lb the matrix such that B.Lb = I, where I is the intersection. * @return their intersection. */ static void linearInter(Matrix * A, Matrix * B, Matrix ** I, Matrix **Lb) { Matrix * AB=NULL; int rk = A->NbRows; int a = A->NbColumns; int b = B->NbColumns; int i,j, z=0; Matrix * H, *U, *Q; /* ensure that the spanning vectors are in the same space */ assert(B->NbRows==rk); /* 1- build the matrix * (A 0 1) * (0 B 1) */ AB = Matrix_Alloc(2*rk, a+b+rk); Matrix_copySubMatrix(A, 0, 0, rk, a, AB, 0, 0); Matrix_copySubMatrix(B, 0, 0, rk, b, AB, rk, a); for (i=0; i< rk; i++) { value_set_si(AB->p[i][a+b+i], 1); value_set_si(AB->p[i+rk][a+b+i], 1); } if (dbgCompParm) { show_matrix(AB); } /* 2- Compute its left Hermite normal form. AB.U = [H 0] */ left_hermite(AB, &H, &Q, &U); Matrix_Free(AB); Matrix_Free(Q); /* count the number of non-zero colums in H */ for (z=H->NbColumns-1; value_zero_p(H->p[H->NbRows-1][z]); z--); z++; if (dbgCompParm) { show_matrix(H); printf("z=%d\n", z); } Matrix_Free(H); /* if you split U in 9 submatrices, you have: * A.U_13 = -U_33 * B.U_23 = -U_33, * where the nb of cols of U_{*3} equals the nb of zero-cols of H * U_33 is a (the smallest) combination of col-vectors of A and B at the same * time: their intersection. */ Matrix_subMatrix(U, a+b, z, U->NbColumns, U->NbColumns, I); Matrix_subMatrix(U, a, z, a+b, U->NbColumns, Lb); if (dbgCompParm) { show_matrix(U); } Matrix_Free(U); } /* linearInter */
static __isl_give isl_mat *extract_equalities(isl_ctx *ctx, Matrix *M) { int i, j; int n; isl_val *v; isl_mat *eq; n = 0; for (i = 0; i < M->NbRows; ++i) if (value_zero_p(M->p[i][0])) ++n; eq = isl_mat_alloc(ctx, n, M->NbColumns - 1); for (i = 0; i < M->NbRows; ++i) { if (!value_zero_p(M->p[i][0])) continue; for (j = 0; j < M->NbColumns - 1; ++j) { v = isl_val_int_from_gmp(ctx, M->p[i][1 + j]); eq = isl_mat_set_element_val(eq, i, j, v); } } return eq; }
/** Removes the equalities that involve only parameters, by eliminating some * parameters in the polyhedron's constraints and in the context.<p> * <b>Updates M and Ctxt.</b> * @param M1 the polyhedron's constraints * @param Ctxt1 the constraints of the polyhedron's context * @param renderSpace tells if the returned equalities must be expressed in the * parameters space (renderSpace=0) or in the combined var/parms space * (renderSpace = 1) * @param elimParms the list of parameters that have been removed: an array * whose 1st element is the number of elements in the list. (returned) * @return the system of equalities that involve only parameters. */ Matrix * Constraints_Remove_parm_eqs(Matrix ** M1, Matrix ** Ctxt1, int renderSpace, unsigned int ** elimParms) { int i, j, k, nbEqsParms =0; int nbEqsM, nbEqsCtxt, allZeros, nbTautoM = 0, nbTautoCtxt = 0; Matrix * M = (*M1); Matrix * Ctxt = (*Ctxt1); int nbVars = M->NbColumns-Ctxt->NbColumns; Matrix * Eqs; Matrix * EqsMTmp; /* 1- build the equality matrix(ces) */ nbEqsM = 0; for (i=0; i< M->NbRows; i++) { k = First_Non_Zero(M->p[i], M->NbColumns); /* if it is a tautology, count it as such */ if (k==-1) { nbTautoM++; } else { /* if it only involves parameters, count it */ if (k>= nbVars+1) nbEqsM++; } } nbEqsCtxt = 0; for (i=0; i< Ctxt->NbRows; i++) { if (value_zero_p(Ctxt->p[i][0])) { if (First_Non_Zero(Ctxt->p[i], Ctxt->NbColumns)==-1) { nbTautoCtxt++; } else { nbEqsCtxt ++; } } } nbEqsParms = nbEqsM + nbEqsCtxt; /* nothing to do in this case */ if (nbEqsParms+nbTautoM+nbTautoCtxt==0) { (*elimParms) = (unsigned int*) malloc(sizeof(int)); (*elimParms)[0] = 0; if (renderSpace==0) { return Matrix_Alloc(0,Ctxt->NbColumns); } else { return Matrix_Alloc(0,M->NbColumns); } } Eqs= Matrix_Alloc(nbEqsParms, Ctxt->NbColumns); EqsMTmp= Matrix_Alloc(nbEqsParms, M->NbColumns); /* copy equalities from the context */ k = 0; for (i=0; i< Ctxt->NbRows; i++) { if (value_zero_p(Ctxt->p[i][0]) && First_Non_Zero(Ctxt->p[i], Ctxt->NbColumns)!=-1) { Vector_Copy(Ctxt->p[i], Eqs->p[k], Ctxt->NbColumns); Vector_Copy(Ctxt->p[i]+1, EqsMTmp->p[k]+nbVars+1, Ctxt->NbColumns-1); k++; } } for (i=0; i< M->NbRows; i++) { j=First_Non_Zero(M->p[i], M->NbColumns); /* copy equalities that involve only parameters from M */ if (j>=nbVars+1) { Vector_Copy(M->p[i]+nbVars+1, Eqs->p[k]+1, Ctxt->NbColumns-1); Vector_Copy(M->p[i]+nbVars+1, EqsMTmp->p[k]+nbVars+1, Ctxt->NbColumns-1); /* mark these equalities for removal */ value_set_si(M->p[i][0], 2); k++; } /* mark the all-zero equalities for removal */ if (j==-1) { value_set_si(M->p[i][0], 2); } } /* 2- eliminate parameters until all equalities are used or until we find a contradiction (overconstrained system) */ (*elimParms) = (unsigned int *) malloc((Eqs->NbRows+1) * sizeof(int)); (*elimParms)[0] = 0; allZeros = 0; for (i=0; i< Eqs->NbRows; i++) { /* find a variable that can be eliminated */ k = First_Non_Zero(Eqs->p[i], Eqs->NbColumns); if (k!=-1) { /* nothing special to do for tautologies */ /* if there is a contradiction, return empty matrices */ if (k==Eqs->NbColumns-1) { printf("Contradiction in %dth row of Eqs: ",k); show_matrix(Eqs); Matrix_Free(Eqs); Matrix_Free(EqsMTmp); (*M1) = Matrix_Alloc(0, M->NbColumns); Matrix_Free(M); (*Ctxt1) = Matrix_Alloc(0,Ctxt->NbColumns); Matrix_Free(Ctxt); free(*elimParms); (*elimParms) = (unsigned int *) malloc(sizeof(int)); (*elimParms)[0] = 0; if (renderSpace==1) { return Matrix_Alloc(0,(*M1)->NbColumns); } else { return Matrix_Alloc(0,(*Ctxt1)->NbColumns); } } /* if we have something we can eliminate, do it in 3 places: Eqs, Ctxt, and M */ else { k--; /* k is the rank of the variable, now */ (*elimParms)[0]++; (*elimParms)[(*elimParms[0])]=k; for (j=0; j< Eqs->NbRows; j++) { if (i!=j) { eliminate_var_with_constr(Eqs, i, Eqs, j, k); eliminate_var_with_constr(EqsMTmp, i, EqsMTmp, j, k+nbVars); } } for (j=0; j< Ctxt->NbRows; j++) { if (value_notzero_p(Ctxt->p[i][0])) { eliminate_var_with_constr(Eqs, i, Ctxt, j, k); } } for (j=0; j< M->NbRows; j++) { if (value_cmp_si(M->p[i][0], 2)) { eliminate_var_with_constr(EqsMTmp, i, M, j, k+nbVars); } } } } /* if (k==-1): count the tautologies in Eqs to remove them later */ else { allZeros++; } } /* elimParms may have been overallocated. Now we know how many parms have been eliminated so we can reallocate the right amount of memory. */ if (!realloc((*elimParms), ((*elimParms)[0]+1)*sizeof(int))) { fprintf(stderr, "Constraints_Remove_parm_eqs > cannot realloc()"); } Matrix_Free(EqsMTmp); /* 3- remove the "bad" equalities from the input matrices and copy the equalities involving only parameters */ EqsMTmp = Matrix_Alloc(M->NbRows-nbEqsM-nbTautoM, M->NbColumns); k=0; for (i=0; i< M->NbRows; i++) { if (value_cmp_si(M->p[i][0], 2)) { Vector_Copy(M->p[i], EqsMTmp->p[k], M->NbColumns); k++; } } Matrix_Free(M); (*M1) = EqsMTmp; EqsMTmp = Matrix_Alloc(Ctxt->NbRows-nbEqsCtxt-nbTautoCtxt, Ctxt->NbColumns); k=0; for (i=0; i< Ctxt->NbRows; i++) { if (value_notzero_p(Ctxt->p[i][0])) { Vector_Copy(Ctxt->p[i], EqsMTmp->p[k], Ctxt->NbColumns); k++; } } Matrix_Free(Ctxt); (*Ctxt1) = EqsMTmp; if (renderSpace==0) {/* renderSpace=0: equalities in the parameter space */ EqsMTmp = Matrix_Alloc(Eqs->NbRows-allZeros, Eqs->NbColumns); k=0; for (i=0; i<Eqs->NbRows; i++) { if (First_Non_Zero(Eqs->p[i], Eqs->NbColumns)!=-1) { Vector_Copy(Eqs->p[i], EqsMTmp->p[k], Eqs->NbColumns); k++; } } } else {/* renderSpace=1: equalities rendered in the combined space */ EqsMTmp = Matrix_Alloc(Eqs->NbRows-allZeros, (*M1)->NbColumns); k=0; for (i=0; i<Eqs->NbRows; i++) { if (First_Non_Zero(Eqs->p[i], Eqs->NbColumns)!=-1) { Vector_Copy(Eqs->p[i], &(EqsMTmp->p[k][nbVars]), Eqs->NbColumns); k++; } } } Matrix_Free(Eqs); Eqs = EqsMTmp; return Eqs; } /* Constraints_Remove_parm_eqs */
/* Assumes C is a linear cone (i.e. with apex zero). * All equalities are removed first to speed up the computation * in zsolve. */ Matrix *Cone_Hilbert_Basis(Polyhedron *C, unsigned MaxRays) { unsigned dim; int i; Matrix *M2, *M3, *T; Matrix *CV = NULL; LinearSystem initialsystem; ZSolveMatrix matrix; ZSolveVector rhs; ZSolveContext ctx; remove_all_equalities(&C, NULL, NULL, &CV, 0, MaxRays); dim = C->Dimension; for (i = 0; i < C->NbConstraints; ++i) assert(value_zero_p(C->Constraint[i][1+dim]) || First_Non_Zero(C->Constraint[i]+1, dim) == -1); M2 = Polyhedron2standard_form(C, &T); matrix = Matrix2zsolve(M2); Matrix_Free(M2); rhs = createVector(matrix->Height); for (i = 0; i < matrix->Height; i++) rhs[i] = 0; initialsystem = createLinearSystem(); setLinearSystemMatrix(initialsystem, matrix); deleteMatrix(matrix); setLinearSystemRHS(initialsystem, rhs); deleteVector(rhs); setLinearSystemLimit(initialsystem, -1, 0, MAXINT, 0); setLinearSystemEquationType(initialsystem, -1, EQUATION_EQUAL, 0); ctx = createZSolveContextFromSystem(initialsystem, NULL, 0, 0, NULL, NULL); zsolveSystem(ctx, 0); M2 = VectorArray2Matrix(ctx->Homs, C->Dimension); deleteZSolveContext(ctx, 1); Matrix_Transposition(T); M3 = Matrix_Alloc(M2->NbRows, M2->NbColumns); Matrix_Product(M2, T, M3); Matrix_Free(M2); Matrix_Free(T); if (CV) { Matrix *T, *M; T = Transpose(CV); M = Matrix_Alloc(M3->NbRows, T->NbColumns); Matrix_Product(M3, T, M); Matrix_Free(M3); Matrix_Free(CV); Matrix_Free(T); Polyhedron_Free(C); M3 = M; } return M3; }
/* * 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 */
/* GaussSimplify -- Given Mat1, a matrix of equalities, performs Gaussian elimination. Find a minimum basis, Returns the rank. Mat1 is context, Mat2 is reduced in context of Mat1 */ int GaussSimplify(Matrix *Mat1,Matrix *Mat2) { int NbRows = Mat1->NbRows; int NbCols = Mat1->NbColumns; int *column_index; int i, j, k, n, t, pivot, Rank; Value gcd, tmp, *cp; column_index=(int *)malloc(NbCols * sizeof(int)); if (!column_index) { errormsg1("GaussSimplify", "outofmem", "out of memory space\n"); Pol_status = 1; return 0; } /* Initialize all the 'Value' variables */ value_init(gcd); value_init(tmp); Rank=0; for (j=0; j<NbCols; j++) { /* for each column starting at */ for (i=Rank; i<NbRows; i++) /* diagonal, look down to find */ if (value_notzero_p(Mat1->p[i][j])) /* the first non-zero entry */ break; if (i!=NbRows) { /* was one found ? */ if (i!=Rank) /* was it found below the diagonal?*/ Vector_Exchange(Mat1->p[Rank],Mat1->p[i],NbCols); /* Normalize the pivot row */ Vector_Gcd(Mat1->p[Rank],NbCols,&gcd); /* If (gcd >= 2) */ value_set_si(tmp,2); if (value_ge(gcd,tmp)) { cp = Mat1->p[Rank]; for (k=0; k<NbCols; k++,cp++) value_division(*cp,*cp,gcd); } if (value_neg_p(Mat1->p[Rank][j])) { cp = Mat1->p[Rank]; for (k=0; k<NbCols; k++,cp++) value_oppose(*cp,*cp); } /* End of normalize */ pivot=i; for (i=0;i<NbRows;i++) /* Zero out the rest of the column */ if (i!=Rank) { if (value_notzero_p(Mat1->p[i][j])) { Value a, a1, a2, a1abs, a2abs; value_init(a); value_init(a1); value_init(a2); value_init(a1abs); value_init(a2abs); value_assign(a1,Mat1->p[i][j]); value_absolute(a1abs,a1); value_assign(a2,Mat1->p[Rank][j]); value_absolute(a2abs,a2); value_gcd(a, a1abs, a2abs); value_divexact(a1, a1, a); value_divexact(a2, a2, a); value_oppose(a1,a1); Vector_Combine(Mat1->p[i],Mat1->p[Rank],Mat1->p[i],a2, a1,NbCols); Vector_Normalize(Mat1->p[i],NbCols); value_clear(a); value_clear(a1); value_clear(a2); value_clear(a1abs); value_clear(a2abs); } } column_index[Rank]=j; Rank++; } } /* end of Gauss elimination */ if (Mat2) { /* Mat2 is a transformation matrix (i,j->f(i,j)).... can't scale it because can't scale both sides of -> */ /* normalizes an affine transformation */ /* priority of forms */ /* 1. i' -> i (identity) */ /* 2. i' -> i + constant (uniform) */ /* 3. i' -> constant (broadcast) */ /* 4. i' -> j (permutation) */ /* 5. i' -> j + constant ( ) */ /* 6. i' -> i + j + constant (non-uniform) */ for (k=0; k<Rank; k++) { j = column_index[k]; for (i=0; i<(Mat2->NbRows-1);i++) { /* all but the last row 0...0 1 */ if ((i!=j) && value_notzero_p(Mat2->p[i][j])) { /* Remove dependency of i' on j */ Value a, a1, a1abs, a2, a2abs; value_init(a); value_init(a1); value_init(a2); value_init(a1abs); value_init(a2abs); value_assign(a1,Mat2->p[i][j]); value_absolute(a1abs,a1); value_assign(a2,Mat1->p[k][j]); value_absolute(a2abs,a2); value_gcd(a, a1abs, a2abs); value_divexact(a1, a1, a); value_divexact(a2, a2, a); value_oppose(a1,a1); if (value_one_p(a2)) { Vector_Combine(Mat2->p[i],Mat1->p[k],Mat2->p[i],a2, a1,NbCols); /* Vector_Normalize(Mat2->p[i],NbCols); -- can't do T */ } /* otherwise, can't do it without mult lhs prod (2i,3j->...) */ value_clear(a); value_clear(a1); value_clear(a2); value_clear(a1abs); value_clear(a2abs); } else if ((i==j) && value_zero_p(Mat2->p[i][j])) { /* 'i' does not depend on j */ for (n=j+1; n < (NbCols-1); n++) { if (value_notzero_p(Mat2->p[i][n])) { /* i' depends on some n */ value_set_si(tmp,1); Vector_Combine(Mat2->p[i],Mat1->p[k],Mat2->p[i],tmp, tmp,NbCols); break; } /* if 'i' depends on just a constant, then leave it alone.*/ } } } } /* Check last row of transformation Mat2 */ for (j=0; j<(NbCols-1); j++) if (value_notzero_p(Mat2->p[Mat2->NbRows-1][j])) { errormsg1("GaussSimplify", "corrtrans", "Corrupted transformation\n"); break; } if (value_notone_p(Mat2->p[Mat2->NbRows-1][NbCols-1])) { errormsg1("GaussSimplify", "corrtrans", "Corrupted transformation\n"); } } value_clear(gcd); value_clear(tmp); free(column_index); return Rank; } /* GaussSimplify */
/* INDEX = 1 .... Dimension */ int PolyhedronLTQ (Polyhedron *Pol1,Polyhedron *Pol2,int INDEX, int PDIM, int NbMaxConstrs) { int res, dim, i, j, k; Polyhedron *Q1, *Q2, *Q3, *Q4, *Q; Matrix *Mat; if (Pol1->next || Pol2->next) { errormsg1("PolyhedronLTQ", "compoly", "Can only compare polyhedra"); return 0; } if (Pol1->Dimension != Pol2->Dimension) { errormsg1("PolyhedronLTQ","diffdim","Polyhedra are not same dimension"); return 0; } dim = Pol1->Dimension+2; POL_ENSURE_FACETS(Pol1); POL_ENSURE_VERTICES(Pol1); POL_ENSURE_FACETS(Pol2); POL_ENSURE_VERTICES(Pol2); #ifdef DEBUG fprintf(stdout, "P1\n"); Polyhedron_Print(stdout,P_VALUE_FMT,Pol1); fprintf(stdout, "P2\n"); Polyhedron_Print(stdout,P_VALUE_FMT,Pol2); #endif /* Create the Line to add */ k = Pol1->Dimension-INDEX+1-PDIM; Mat = Matrix_Alloc(k,dim); Vector_Set(Mat->p_Init,0,dim*k); for(j=0,i=INDEX;j<k;i++,j++) value_set_si(Mat->p[j][i],1); Q1 = AddRays(Mat->p[0],k,Pol1,NbMaxConstrs); Q2 = AddRays(Mat->p[0],k,Pol2,NbMaxConstrs); #ifdef DEBUG fprintf(stdout, "Q1\n"); Polyhedron_Print(stdout,P_VALUE_FMT,Q1); fprintf(stdout, "Q2\n"); Polyhedron_Print(stdout,P_VALUE_FMT,Q2); #endif Matrix_Free(Mat); Q = DomainIntersection(Q1,Q2,NbMaxConstrs); #ifdef DEBUG fprintf(stdout, "Q\n"); Polyhedron_Print(stdout,P_VALUE_FMT,Q); #endif Domain_Free(Q1); Domain_Free(Q2); if (emptyQ(Q)) res = 0; /* not comparable */ else { Q1 = DomainIntersection(Pol1,Q,NbMaxConstrs); Q2 = DomainIntersection(Pol2,Q,NbMaxConstrs); #ifdef DEBUG fprintf(stdout, "Q1\n"); Polyhedron_Print(stdout,P_VALUE_FMT,Q1); fprintf(stdout, "Q2\n"); Polyhedron_Print(stdout,P_VALUE_FMT,Q2); #endif k = Q1->NbConstraints + Q2->NbConstraints; Mat = Matrix_Alloc(k, dim); Vector_Set(Mat->p_Init,0,k*dim); /* First compute surrounding polyhedron */ j=0; for (i=0; i<Q1->NbConstraints; i++) { if ((value_one_p(Q1->Constraint[i][0])) && (value_pos_p(Q1->Constraint[i][INDEX]))) { /* keep Q1's lower bounds */ for (k=0; k<dim; k++) value_assign(Mat->p[j][k],Q1->Constraint[i][k]); j++; } } for (i=0; i<Q2->NbConstraints; i++) { if ((value_one_p(Q2->Constraint[i][0])) && (value_neg_p(Q2->Constraint[i][INDEX]))) { /* and keep Q2's upper bounds */ for (k=0; k<dim; k++) value_assign(Mat->p[j][k],Q2->Constraint[i][k]); j++; } } Q4 = AddConstraints(Mat->p[0], j, Q, NbMaxConstrs); Matrix_Free(Mat); #ifdef debug fprintf(stderr, "Q4 surrounding polyhedron\n"); Polyhderon_Print(stderr,P_VALUE_FMT, Q4); #endif /* if surrounding polyhedron is empty, D1>D2 */ if (emptyQ(Q4)) { res = 1; #ifdef debug fprintf(stderr, "Surrounding polyhedron is empty\n"); #endif goto LTQdone2; } /* Test if Q1 < Q2 */ /* Build a constraint array for >= Q1 and <= Q2 */ Mat = Matrix_Alloc(2,dim); Vector_Set(Mat->p_Init,0,2*dim); /* Choose a contraint from Q1 */ for (i=0; i<Q1->NbConstraints; i++) { if (value_zero_p(Q1->Constraint[i][0])) { /* Equality */ if (value_zero_p(Q1->Constraint[i][INDEX])) { /* Ignore side constraint (they are in Q) */ continue; } else if (value_neg_p(Q1->Constraint[i][INDEX])) { /* copy -constraint to Mat */ value_set_si(Mat->p[0][0],1); for (k=1; k<dim; k++) value_oppose(Mat->p[0][k],Q1->Constraint[i][k]); } else { /* Copy constraint to Mat */ value_set_si(Mat->p[0][0],1); for (k=1; k<dim; k++) value_assign(Mat->p[0][k],Q1->Constraint[i][k]); } } else if(value_neg_p(Q1->Constraint[i][INDEX])) { /* Upper bound -- make a lower bound from it */ value_set_si(Mat->p[0][0],1); for (k=1; k<dim; k++) value_oppose(Mat->p[0][k],Q1->Constraint[i][k]); } else { /* Lower or side bound -- ignore it */ continue; } /* Choose a constraint from Q2 */ for (j=0; j<Q2->NbConstraints; j++) { if (value_zero_p(Q2->Constraint[j][0])) { /* equality */ if (value_zero_p(Q2->Constraint[j][INDEX])) { /* Ignore side constraint (they are in Q) */ continue; } else if (value_pos_p(Q2->Constraint[j][INDEX])) { /* Copy -constraint to Mat */ value_set_si(Mat->p[1][0],1); for (k=1; k<dim; k++) value_oppose(Mat->p[1][k],Q2->Constraint[j][k]); } else { /* Copy constraint to Mat */ value_set_si(Mat->p[1][0],1); for (k=1; k<dim; k++) value_assign(Mat->p[1][k],Q2->Constraint[j][k]); }; } else if (value_pos_p(Q2->Constraint[j][INDEX])) { /* Lower bound -- make an upper bound from it */ value_set_si(Mat->p[1][0],1); for(k=1;k<dim;k++) value_oppose(Mat->p[1][k],Q2->Constraint[j][k]); } else { /* Upper or side bound -- ignore it */ continue; }; #ifdef DEBUG fprintf(stdout, "i=%d j=%d M=\n", i+1, j+1); Matrix_Print(stdout,P_VALUE_FMT,Mat); #endif /* Add Mat to Q and see if anything is made */ Q3 = AddConstraints(Mat->p[0],2,Q,NbMaxConstrs); #ifdef DEBUG fprintf(stdout, "Q3\n"); Polyhedron_Print(stdout,P_VALUE_FMT,Q3); #endif if (!emptyQ(Q3)) { Domain_Free(Q3); #ifdef DEBUG fprintf(stdout, "not empty\n"); #endif res = -1; goto LTQdone; } #ifdef DEBUG fprintf(stdout,"empty\n"); #endif Domain_Free(Q3); } /* end for j */ } /* end for i */ res = 1; LTQdone: Matrix_Free(Mat); LTQdone2: Domain_Free(Q4); Domain_Free(Q1); Domain_Free(Q2); } Domain_Free(Q); #ifdef DEBUG fprintf(stdout, "res = %d\n", res); #endif return res; } /* PolyhedronLTQ */