/*--------------------------------------------------------------*/ int Polyhedron_Not_Empty(Polyhedron *P,Polyhedron *C,int MAXRAYS) { int res,i; Value *context; Polyhedron *L; POL_ENSURE_FACETS(P); POL_ENSURE_VERTICES(P); POL_ENSURE_FACETS(C); POL_ENSURE_VERTICES(C); /* Create a context vector size dim+2 and set it to all zeros */ context = (Value *) malloc((P->Dimension+2)*sizeof(Value)); /* Initialize array 'context' */ for (i=0;i<(P->Dimension+2);i++) value_init(context[i]); Vector_Set(context,0,(P->Dimension+2)); /* Set context[P->Dimension+1] = 1 (the constant) */ value_set_si(context[P->Dimension+1],1); L = Polyhedron_Scan(P,C,MAXRAYS); res = exist_points(1,L,context); Domain_Free(L); /* Clear array 'context' */ for (i=0;i<(P->Dimension+2);i++) value_clear(context[i]); free(context); return res; }
/* * Given Lattice 'Lat' and a Polyhderon 'Poly', allocate space, and return * the Z-polyhderon corresponding to the image of the polyhderon 'Poly' by the * lattice 'Lat'. If the input lattice 'Lat' is not integeral, it integralises * it, i.e. the lattice of the Z-polyhderon returned is integeral. */ ZPolyhedron *ZPolyhedron_Alloc(Lattice *Lat, Polyhedron *Poly) { ZPolyhedron *A; POL_ENSURE_FACETS(Poly); POL_ENSURE_VERTICES(Poly); if(Lat->NbRows != Poly->Dimension+1) { fprintf(stderr,"\nInZPolyAlloc - The Lattice and the Polyhedron"); fprintf(stderr," are not compatible to form a ZPolyhedra\n"); return NULL; } if((!(isEmptyLattice(Lat))) && (!isfulldim (Lat))) { fprintf(stderr,"\nZPolAlloc: Lattice not Full Dimensional\n"); return NULL; } A = (ZPolyhedron *)malloc(sizeof(ZPolyhedron)); if (!A) { fprintf(stderr,"ZPolAlloc : Out of Memory\n"); return NULL; } A->next = NULL; A->P = Domain_Copy(Poly); A->Lat = Matrix_Copy(Lat); if(IsLattice(Lat) == False) { ZPolyhedron *Res; Res = IntegraliseLattice (A); ZPolyhedron_Free (A); return Res; } return A; } /* ZPolyhedron_Alloc */
static enum order_sign interval_minmax(Polyhedron *I) { int i; int min = 1; int max = -1; assert(I->Dimension == 1); POL_ENSURE_VERTICES(I); for (i = 0; i < I->NbRays; ++i) { if (value_pos_p(I->Ray[i][1])) max = 1; else if (value_neg_p(I->Ray[i][1])) min = -1; else { if (max < 0) max = 0; if (min > 0) min = 0; } } if (min > 0) return order_gt; if (max < 0) return order_lt; if (min == max) return order_eq; if (max == 0) return order_le; if (min == 0) return order_ge; return order_unknown; }
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; }
/* Compute integer hull of truncated linear cone C, i.e., of C with * the origin removed. * Here, we do this by first computing the Hilbert basis of C * and then discarding elements from this basis that are rational * overconvex combinations of other elements in the basis. */ Matrix *Cone_Hilbert_Integer_Hull(Polyhedron *C, struct barvinok_options *options) { int i, j, k; Matrix *hilbert = Cone_Hilbert_Basis(C, options->MaxRays); Matrix *rays, *hull; unsigned dim = C->Dimension; Value tmp; unsigned MaxRays = options->MaxRays; /* When checking for redundant points below, we want to * check if there are any _rational_ solutions. */ POL_UNSET(options->MaxRays, POL_INTEGER); POL_ENSURE_VERTICES(C); rays = Matrix_Alloc(C->NbRays-1, C->Dimension); for (i = 0, j = 0; i < C->NbRays; ++i) { if (value_notzero_p(C->Ray[i][1+C->Dimension])) continue; Vector_Copy(C->Ray[i]+1, rays->p[j++], C->Dimension); } /* We only sort the pointers into the big Value array */ qsort(rays->p, rays->NbRows, sizeof(Value *), lex_cmp); qsort(hilbert->p, hilbert->NbRows, sizeof(Value *), lex_cmp); /* Remove rays from Hilbert basis */ for (i = 0, j = 0, k = 0; i < hilbert->NbRows && j < rays->NbRows; ++i) { if (Vector_Equal(hilbert->p[i], rays->p[j], C->Dimension)) ++j; else hilbert->p[k++] = hilbert->p[i]; } hilbert->NbRows = k; /* Now remove points that are overconvex combinations of other points */ value_init(tmp); for (i = 0; hilbert->NbRows > 1 && i < hilbert->NbRows; ++i) { Matrix *LP; Vector *obj; int nray = rays->NbRows; int npoint = hilbert->NbRows; enum lp_result result; LP = Matrix_Alloc(dim + 1 + nray + (npoint-1), 2 + nray + (npoint-1)); for (j = 0; j < dim; ++j) { for (k = 0; k < nray; ++k) value_assign(LP->p[j][k+1], rays->p[k][j]); for (k = 0; k < npoint; ++k) { if (k == i) value_oppose(LP->p[j][1+nray+npoint-1], hilbert->p[k][j]); else value_assign(LP->p[j][1+nray+k-(k>i)], hilbert->p[k][j]); } } value_set_si(LP->p[dim][0], 1); for (k = 0; k < nray+npoint-1; ++k) value_set_si(LP->p[dim][1+k], 1); value_set_si(LP->p[dim][LP->NbColumns-1], -1); for (k = 0; k < LP->NbColumns-2; ++k) { value_set_si(LP->p[dim+1+k][0], 1); value_set_si(LP->p[dim+1+k][1+k], 1); } /* Somewhat arbitrary objective function. */ obj = Vector_Alloc(LP->NbColumns-1); value_set_si(obj->p[0], 1); value_set_si(obj->p[obj->Size-1], 1); result = constraints_opt(LP, obj->p, obj->p[0], lp_min, &tmp, options); /* If the LP is not empty, the point can be discarded */ if (result != lp_empty) { hilbert->NbRows--; if (i < hilbert->NbRows) hilbert->p[i] = hilbert->p[hilbert->NbRows]; --i; } Matrix_Free(LP); Vector_Free(obj); } value_clear(tmp); hull = Matrix_Alloc(rays->NbRows + hilbert->NbRows, dim+1); for (i = 0; i < rays->NbRows; ++i) { Vector_Copy(rays->p[i], hull->p[i], dim); value_set_si(hull->p[i][dim], 1); } for (i = 0; i < hilbert->NbRows; ++i) { Vector_Copy(hilbert->p[i], hull->p[rays->NbRows+i], dim); value_set_si(hull->p[rays->NbRows+i][dim], 1); } Matrix_Free(rays); Matrix_Free(hilbert); options->MaxRays = MaxRays; return hull; }
/* * Topologically sort 'n' polyhdera and return 0 on failure, otherwise return * 1 on success. Here 'L' is a an array of pointers to polyhedra, 'n' is the * number of polyhedra, 'index' is the level to consider for partial ordering * 'pdim' is the parameter space dimension, 'time' is an array of 'n' integers * to store logical time values, 'pvect', if not NULL, is an array of 'n' * integers that contains a permutation specification after call and MAXRAYS is * the workspace size for polyhedra operations. */ int PolyhedronTSort (Polyhedron **L,unsigned int n,unsigned int index,unsigned int pdim,int *time,int *pvect,unsigned int MAXRAYS) { unsigned int const nbcells = ((n*(n-1))>>1); /* Number of memory cells to allocate, see below */ int *dag; /* The upper triangular matrix */ int **p; /* Array of matrix row addresses */ unsigned int i, j, k; unsigned int t, nb, isroot; if (n<2) return 0; /* we need an upper triangular matrix (example with n=4): . o o o . . o o . are unuseful cells, o are useful cells . . . o . . . . so we need to allocate (n)(n-1)/2 cells - dag will point to this memory. - p[i] will point to row i of the matrix p[0] = dag - 1 (such that p[0][1] == dag[0]) p[1] = dag - 1 + (n-1) p[2] = dag - 1 + (n-1) + (n-2) ... p[i] = p[i-1] + (n-1-i) */ /* malloc n(n-1)/2 for dag and n-1 for p (node n does not have any row) */ dag = (int *) malloc(nbcells*sizeof(int)); if (!dag) return 0; p = (int **) malloc ((n-1) * sizeof(int *)); if (!p) { free(dag); return 0; } /* Initialize 'p' and 'dag' */ p[0] = dag-1; for (i=1; i<n-1; i++) p[i] = p[i-1] + (n-1)-i; for (i=0; i<nbcells; i++) dag[i] = -2; /* -2 means 'not computed yet' */ for (i=0; i<n; i++) time[i] = -1; /* Compute the dag using transitivity to reduce the number of */ /* PolyhedronLTQ calls. */ for (i=0; i<n-1; i++) { POL_ENSURE_FACETS(L[i]); POL_ENSURE_VERTICES(L[i]); for (j=i+1; j<n; j++) { if (p[i][j] == -2) /* not computed yes */ p[i][j] = PolyhedronLTQ(L[i], L[j], index, pdim, MAXRAYS); if (p[i][j] != 0) { /* if p[i][j] is 1 or -1, look for -p[i][j] on the same row: p[i][j] == -p[i][k] ==> p[j][k] = p[i][k] (transitivity) note: p[r][c] == -p[c][r], use this to avoid reading or writing under the matrix diagonal */ /* first, k<i so look for p[i][j] == p[k][i] (i.e. -p[i][k]) */ for (k=0; k<i; k++) if (p[k][i] == p[i][j]) p[k][j] = p[k][i]; /* then, i<k<j so look for p[i][j] == -p[i][k] */ for (k=i+1; k<j; k++) if (p[i][k] == -p[i][j]) p[k][j] = -p[i][k]; /* last, k>j same search but */ for (k=j+1; k<n; k++) if (p[i][k] == -p[i][j]) p[j][k] = p[i][k]; } } } /* walk thru the dag to compute the partial order (and optionally the permutation) Note: this is not the fastest way to do it but it takes negligible time compared to a single call of PolyhedronLTQ ! Each macro-step (while loop) gives the same logical time to all found roots and optionally add these nodes in the permutation vector */ t = 0; /* current logical time, assigned to current roots and increased by 1 at the end of each step */ nb = 0; /* number of processed nodes (have been given a time) */ while (nb<n) { for (i=0; i<n; i++) { /* search for roots */ /* for any node, if it's not already been given a logical time then walk thru the node row; if we find a 1 at some column j, it means that node j preceeds the current node, so it is not a root */ if (time[i]<0) { isroot = 1; /* assume that it is until it is definitely not */ /* first search on a column */ for (j=0; j<i; j++) { if (p[j][i]==-1) { /* found a node lower than it */ isroot = 0; break; } } if /*still*/ (isroot) for (j=i+1; j<n; j++) { if (p[i][j]==1) { /* greater than this node */ isroot = 0; break; } } if (isroot) { /* then it definitely is */ time[i] = t; /* this node gets current logical time */ if (pvect) pvect[nb] = i+1; /* nodes will be numbered from 1 to n */ nb++; /* one more node processed */ } } } /* now make roots become neutral, i.e. non comparable with all other nodes */ for (i=0; i<n; i++) { if (time[i]==t) { for (j=0; j<i; j++) p[j][i] = 0; for (j=i+1; j<n; j++) p[i][j] = 0; } } t++; /* ready for next set of root nodes */ } free (p); /* let's be clean, collect the garbage */ free (dag); return 1; } /* PolyhedronTSort */
/* 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 */