/* * lib_cone.cpp * * Created on: Sep 29, 2010 * Author: anders */ #include "gfanlib_zcone.h" #include #include #include #include #ifdef HAVE_CDD_SETOPER_H #include #include #else #ifdef HAVE_CDDLIB_SETOPER_H #include #include #else #include #include #endif //HAVE_CDDLIB_SETOPER_H #endif //HAVE_CDD_SETOPER_H namespace gfan{ static void cddinitGmp() { static bool initialized; if(!initialized) { dd_set_global_constants(); /* First, this must be called. */ initialized=true; } } class LpSolver { static dd_MatrixPtr ZMatrix2MatrixGmp(ZMatrix const &g, dd_ErrorType *Error) { int n=g.getWidth(); dd_MatrixPtr M=NULL; dd_rowrange m_input,i; dd_colrange d_input,j; dd_RepresentationType rep=dd_Inequality; // dd_boolean found=dd_FALSE, newformat=dd_FALSE, successful=dd_FALSE; char command[dd_linelenmax], comsave[dd_linelenmax]; dd_NumberType NT; (*Error)=dd_NoError; rep=dd_Inequality; // newformat=dd_TRUE; m_input=g.getHeight(); d_input=n+1; NT=dd_Rational; M=dd_CreateMatrix(m_input, d_input); M->representation=rep; M->numbtype=NT; for (i = 0; i < m_input; i++) { dd_set_si(M->matrix[i][0],0); for (j = 1; j < d_input; j++) { g[i][j-1].setGmp(mpq_numref(M->matrix[i][j])); mpz_set_ui(mpq_denref(M->matrix[i][j]), 1); mpq_canonicalize(M->matrix[i][j]); } } // successful=dd_TRUE; return M; } static dd_MatrixPtr ZMatrix2MatrixGmp(ZMatrix const &inequalities, ZMatrix const &equations, dd_ErrorType *err) { ZMatrix g=inequalities; g.append(equations); int numberOfInequalities=inequalities.getHeight(); int numberOfRows=g.getHeight(); dd_MatrixPtr A=NULL; cddinitGmp(); A=ZMatrix2MatrixGmp(g, err); for(int i=numberOfInequalities;ilinset,i+1); return A; } static ZMatrix getConstraints(dd_MatrixPtr A, bool returnEquations) { int rowsize=A->rowsize; int n=A->colsize-1; ZMatrix ret(0,n); for(int i=0;ilinset); if(isEquation==returnEquations) { QVector v(n); for(int j=0;jmatrix[i][j+1]); ret.appendRow(QToZVectorPrimitive(v)); } } return ret; } static bool isFacet(ZMatrix const &g, int index) { bool ret; // dd_MatrixPtr M=NULL,M2=NULL,M3=NULL; dd_MatrixPtr M=NULL; // dd_colrange d; dd_ErrorType err=dd_NoError; // dd_rowset redrows,linrows,ignoredrows, basisrows; // dd_colset ignoredcols, basiscols; // dd_DataFileType inputfile; FILE *reading=NULL; cddinitGmp(); M=ZMatrix2MatrixGmp(g, &err); if (err!=dd_NoError) goto _L99; // d=M->colsize; static dd_Arow temp; dd_InitializeArow(g.getWidth()+1,&temp); ret= !dd_Redundant(M,index+1,temp,&err); dd_FreeMatrix(M); dd_FreeArow(g.getWidth()+1,temp); if (err!=dd_NoError) goto _L99; return ret; _L99: assert(0); return false; } /* Heuristic for checking if inequality of full dimensional cone is a facet. If the routine returns true then the inequality is a facet. If it returns false it is unknown. */ static bool fastIsFacetCriterion(ZMatrix const &normals, int i) { int n=normals.getWidth(); for(int j=0;j > Container; Container container; int tableSize; public: class iterator { class MyHashMap &hashMap; int index; // having index==-1 means that we are before/after the elements. std::set::iterator i; public: bool operator++() { if(index==-1)goto search; i++; while(i==hashMap.container[index].end()) { search: index++; if(index>=hashMap.tableSize){ index=-1; return false; } i=hashMap.container[index].begin(); } return true; } ZVector const & operator*()const { return *i; } ZVector operator*() { return *i; } iterator(MyHashMap &hashMap_): hashMap(hashMap_) { index=-1; } }; unsigned int function(const ZVector &v) { unsigned int ret=0; int n=v.size(); for(int i=0;i>29)+v.UNCHECKEDACCESS(i).hashValue(); return ret%tableSize; } MyHashMap(int tableSize_): container(tableSize_), tableSize(tableSize_) { assert(tableSize_>0); } void insert(const ZVector &v) { container[function(v)].insert(v); } void erase(ZVector const &v) { container[function(v)].erase(v); } iterator begin() { iterator ret(*this); ++ ret; return ret; } int size() { iterator i=begin(); int ret=0; do{ret++;}while(++i); return ret; } }; static ZMatrix normalizedWithSumsAndDuplicatesRemoved(ZMatrix const &a) { // TODO: write a version of this function which will work faster if the entries fit in 32bit if(a.getHeight()==0)return a; int n=a.getWidth(); ZVector temp1(n); // ZVector temp2(n); ZMatrix ret(0,n); MyHashMap b(a.getHeight()); for(int i=0;ilinset,i+1); A->objective=dd_LPmax; dd_rowset impl_linset; dd_rowset redset; dd_rowindex newpos; if(removeInequalityRedundancies) dd_MatrixCanonicalize(&A, &impl_linset, &redset, &newpos, &err); else dd_MatrixCanonicalizeLinearity(&A, &impl_linset, &newpos, &err); if (err!=dd_NoError) goto _L99; { int n=A->colsize-1; equations=ZMatrix(0,n); //TODO: the number of rows needed is actually known inequalities=ZMatrix(0,n); //is known by set_card(). That might save some copying. { int rowsize=A->rowsize; QVector point(n); for(int i=0;imatrix[i][j+1]); ((set_member(i+1,A->linset))?equations:inequalities).appendRow(QToZVectorPrimitive(point)); } } assert(set_card(A->linset)==equations.getHeight()); assert(A->rowsize==equations.getHeight()+inequalities.getHeight()); set_free(impl_linset); if(removeInequalityRedundancies) set_free(redset); free(newpos); dd_FreeMatrix(A); return; } _L99: assert(!"Cddlib reported error when called by Gfanlib."); } ZVector relativeInteriorPoint(const ZMatrix &inequalities, const ZMatrix &equations) { QVector retUnscaled(inequalities.getWidth()); cddinitGmp(); int numberOfEqualities=equations.getHeight(); int numberOfInequalities=inequalities.getHeight(); int numberOfRows=numberOfEqualities+numberOfInequalities; // dd_rowset r=NULL; ZMatrix g=inequalities; g.append(equations); dd_LPSolverType solver=dd_DualSimplex; dd_MatrixPtr A=NULL; dd_ErrorType err=dd_NoError; A=ZMatrix2MatrixGmp(g,&err); if (err!=dd_NoError) goto _L99; { dd_LPSolutionPtr lps1; dd_LPPtr lp,lp1; for(int i=0;imatrix[i][0],-1); for(int i=numberOfInequalities;ilinset,i+1); A->objective=dd_LPmax; lp=dd_Matrix2LP(A, &err); if (err!=dd_NoError) goto _L99; lp1=dd_MakeLPforInteriorFinding(lp); dd_LPSolve(lp1,solver,&err); if (err!=dd_NoError) goto _L99; lps1=dd_CopyLPSolution(lp1); assert(!dd_Negative(lps1->optvalue)); for (int j=1; j <(lps1->d)-1; j++) retUnscaled[j-1]=Rational(lps1->sol[j]); dd_FreeLPData(lp); dd_FreeLPSolution(lps1); dd_FreeLPData(lp1); dd_FreeMatrix(A); return QToZVectorPrimitive(retUnscaled); } _L99: assert(0); return QToZVectorPrimitive(retUnscaled); } void dual(ZMatrix const &inequalities, ZMatrix const &equations, ZMatrix &dualInequalities, ZMatrix &dualEquations) { int result; dd_MatrixPtr A=NULL; dd_ErrorType err=dd_NoError; cddinitGmp(); A=ZMatrix2MatrixGmp(inequalities, equations, &err); dd_PolyhedraPtr poly; poly=dd_DDMatrix2Poly2(A, dd_LexMin, &err); if (poly->child==NULL || poly->child->CompStatus!=dd_AllFound) assert(0); dd_MatrixPtr A2=dd_CopyGenerators(poly); dualInequalities=getConstraints(A2,false); dualEquations=getConstraints(A2,true); dd_FreeMatrix(A2); dd_FreeMatrix(A); dd_FreePolyhedra(poly); return; _L99: assert(0); } // this procedure is take from cddio.c. static void dd_ComputeAinc(dd_PolyhedraPtr poly) { /* This generates the input incidence array poly->Ainc, and two sets: poly->Ared, poly->Adom. */ dd_bigrange k; dd_rowrange i,m1; dd_colrange j; dd_boolean redundant; dd_MatrixPtr M=NULL; mytype sum,temp; dd_init(sum); dd_init(temp); if (poly->AincGenerated==dd_TRUE) goto _L99; M=dd_CopyOutput(poly); poly->n=M->rowsize; m1=poly->m1; /* this number is same as poly->m, except when poly is given by nonhomogeneous inequalty: !(poly->homogeneous) && poly->representation==Inequality, it is poly->m+1. See dd_ConeDataLoad. */ poly->Ainc=(set_type*)calloc(m1, sizeof(set_type)); for(i=1; i<=m1; i++) set_initialize(&(poly->Ainc[i-1]),poly->n); set_initialize(&(poly->Ared), m1); set_initialize(&(poly->Adom), m1); for (k=1; k<=poly->n; k++){ for (i=1; i<=poly->m; i++){ dd_set(sum,dd_purezero); for (j=1; j<=poly->d; j++){ dd_mul(temp,poly->A[i-1][j-1],M->matrix[k-1][j-1]); dd_add(sum,sum,temp); } if (dd_EqualToZero(sum)) { set_addelem(poly->Ainc[i-1], k); } } if (!(poly->homogeneous) && poly->representation==dd_Inequality){ if (dd_EqualToZero(M->matrix[k-1][0])) { set_addelem(poly->Ainc[m1-1], k); /* added infinity inequality (1,0,0,...,0) */ } } } for (i=1; i<=m1; i++){ if (set_card(poly->Ainc[i-1])==M->rowsize){ set_addelem(poly->Adom, i); } } for (i=m1; i>=1; i--){ if (set_card(poly->Ainc[i-1])==0){ redundant=dd_TRUE; set_addelem(poly->Ared, i); }else { redundant=dd_FALSE; for (k=1; k<=m1; k++) { if (k!=i && !set_member(k, poly->Ared) && !set_member(k, poly->Adom) && set_subset(poly->Ainc[i-1], poly->Ainc[k-1])){ if (!redundant){ redundant=dd_TRUE; } set_addelem(poly->Ared, i); } } } } dd_FreeMatrix(M); poly->AincGenerated=dd_TRUE; _L99:; dd_clear(sum); dd_clear(temp); } std::vector > extremeRaysInequalityIndices(const ZMatrix &inequalities) { int dim2=inequalities.getHeight(); if(dim2==0)return std::vector >(); // int dimension=inequalities.getWidth(); dd_MatrixPtr A=NULL; dd_ErrorType err=dd_NoError; cddinitGmp(); A=ZMatrix2MatrixGmp(inequalities, &err); dd_PolyhedraPtr poly; poly=dd_DDMatrix2Poly2(A, dd_LexMin, &err); if (poly->child==NULL || poly->child->CompStatus!=dd_AllFound) assert(0); if (poly->AincGenerated==dd_FALSE) dd_ComputeAinc(poly); std::vector > ret; /* How do we interpret the cddlib output? For a long ting gfan has been using poly->n as the number of rays of the cone and thus returned sets of indices that actually gave the lineality space. The mistake was then caught later in PolyhedralCone. On Feb 17 2009 gfan was changed to check the length of each set to make sure that it does not specify the lineality space and only return those sets giving rise to rays. This does not seem to be the best strategy and might even be wrong. */ for (int k=1; k<=poly->n; k++) { int length=0; for (int i=1; i<=poly->m1; i++) if(set_member(k,poly->Ainc[i-1]))length++; if(length!=dim2) { std::vector v(length); int j=0; for (int i=1; i<=poly->m1; i++) if(set_member(k,poly->Ainc[i-1]))v[j++]=i-1; ret.push_back(v); } } dd_FreeMatrix(A); dd_FreePolyhedra(poly); return ret; _L99: assert(0); return std::vector >(); } }; LpSolver lpSolver; bool ZCone::isInStateMinimum(int s)const { return state>=s; } bool operator<(ZCone const &a, ZCone const &b) { assert(a.state>=3); assert(b.state>=3); if(a.nb.n)return false; if(a.equations1)//there can be no implied equation unless we have at least two inequalities lpSolver.removeRedundantRows(inequalities,equations,false); assert(inequalities.getWidth()==equations.getWidth()); } if((state<2) && (s>=2) && !(preassumptions&PCP_facetsKnown)) { /* if(inequalities.size()>25) { IntegerVectorList h1; IntegerVectorList h2; bool a=false; for(IntegerVectorList::const_iterator i=inequalities.begin();i!=inequalities.end();i++) { if(a) h1.push_back(*i); else h2.push_back(*i); a=!a; } PolyhedralCone c1(h1,equations); PolyhedralCone c2(h2,equations); c1.ensureStateAsMinimum(2); c2.ensureStateAsMinimum(2); inequalities=c1.inequalities; for(IntegerVectorList::const_iterator i=c2.inequalities.begin();i!=c2.inequalities.end();i++) inequalities.push_back(*i); } */ if(equations.getHeight()) { QMatrix m=ZToQMatrix(equations); m.reduce(); m.REformToRREform(); ZMatrix inequalities2(0,equations.getWidth()); for(int i=0;i=3)) { QMatrix equations2=ZToQMatrix(equations); equations2.reduce(false,false,true); equations2.REformToRREform(true); for(int i=0;iambientDimension()<getInequalities(); // if (this->areFacetsKnown()) // s<<"FACETS"<getEquations(); // if (this->areImpliedEquationsKnown()) // s<<"LINEAR_SPAN"<extremeRays(); // s<<"RAYS"<generatorsOfLinealitySpace(); // s<<"LINEALITY_SPACE"<>>>>>> chg: status update 17.07. } ZCone::ZCone(int ambientDimension): preassumptions(PCP_impliedEquationsKnown|PCP_facetsKnown), state(1), n(ambientDimension), multiplicity(1), linearForms(ZMatrix(0,ambientDimension)), inequalities(ZMatrix(0,ambientDimension)), equations(ZMatrix(0,ambientDimension)), haveExtremeRaysBeenCached(false) { } ZCone::ZCone(ZMatrix const &inequalities_, ZMatrix const &equations_, int preassumptions_): preassumptions(preassumptions_), state(0), n(inequalities_.getWidth()), multiplicity(1), linearForms(ZMatrix(0,inequalities_.getWidth())), inequalities(inequalities_), equations(equations_), haveExtremeRaysBeenCached(false) { assert(preassumptions_<4);//OTHERWISE WE ARE DOING SOMETHING STUPID LIKE SPECIFYING AMBIENT DIMENSION assert(equations_.getWidth()==n); ensureStateAsMinimum(1); } void ZCone::canonicalize() { ensureStateAsMinimum(3); } void ZCone::findFacets() { ensureStateAsMinimum(2); } ZMatrix ZCone::getFacets()const { ensureStateAsMinimum(2); return inequalities; } void ZCone::findImpliedEquations() { ensureStateAsMinimum(1); } ZMatrix ZCone::getImpliedEquations()const { ensureStateAsMinimum(1); return equations; } ZVector ZCone::getRelativeInteriorPoint()const { ensureStateAsMinimum(1); // assert(state>=1); return lpSolver.relativeInteriorPoint(inequalities,equations); } ZVector ZCone::getUniquePoint()const { ZMatrix rays=extremeRays(); ZVector ret(n); for(int i=0;i=1); ensureStateAsMinimum(1); return ambientDimension()-equations.getHeight(); } int ZCone::dimensionOfLinealitySpace()const { ZMatrix temp=inequalities; temp.append(equations); ZCone temp2(ZMatrix(0,n),temp); return temp2.dimension(); } bool ZCone::isOrigin()const { return dimension()==0; } bool ZCone::isFullSpace()const { for(int i=0;i=1); for(int i=0;i=2); ensureStateAsMinimum(2); return codimension()+inequalities.getHeight()+dimensionOfLinealitySpace()==n; } ZCone ZCone::linealitySpace()const { ZCone ret(ZMatrix(0,n),combineOnTop(equations,inequalities)); // ret.ensureStateAsMinimum(state); return ret; } ZCone ZCone::dualCone()const { ensureStateAsMinimum(1); // assert(state>=1); ZMatrix dualInequalities,dualEquations; lpSolver.dual(inequalities,equations,dualInequalities,dualEquations); ZCone ret(dualInequalities,dualEquations); ret.ensureStateAsMinimum(state); return ret; } ZCone ZCone::negated()const { ZCone ret(-inequalities,equations,(areFacetsKnown()?PCP_facetsKnown:0)|(areImpliedEquationsKnown()?PCP_impliedEquationsKnown:0)); // ret.ensureStateAsMinimum(state); return ret; } ZMatrix ZCone::extremeRays(ZMatrix const *generatorsOfLinealitySpace)const { // assert((dimension()==ambientDimension()) || (state>=3)); if(dimension()!=ambientDimension()) ensureStateAsMinimum(3); if(haveExtremeRaysBeenCached)return cachedExtremeRays; ZMatrix ret(0,n); std::vector > indices=lpSolver.extremeRaysInequalityIndices(inequalities); for(unsigned i=0;i asVector(inequalities.getHeight()); for(unsigned j=0;jequations; ZVector theInequality; for(unsigned j=0;jequations,inequalities)); QMatrix temp=combineOnTop(linealitySpaceOrth.reduceAndComputeKernel(),ZToQMatrix(equations)); thePrimitiveVector=QToZVectorPrimitive(temp.reduceAndComputeVectorInKernel()); } if(!contains(thePrimitiveVector))thePrimitiveVector=-thePrimitiveVector; ret.appendRow(thePrimitiveVector); } cachedExtremeRays=ret; haveExtremeRaysBeenCached=true; return ret; } Integer ZCone::getMultiplicity()const { return multiplicity; } void ZCone::setMultiplicity(Integer const &m) { multiplicity=m; } ZMatrix ZCone::getLinearForms()const { return linearForms; } void ZCone::setLinearForms(ZMatrix const &linearForms_) { linearForms=linearForms_; } ZMatrix ZCone::quotientLatticeBasis()const { // assert(isInStateMinimum(1));// Implied equations must have been computed in order to know the span of the cone ensureStateAsMinimum(1); int a=equations.getHeight(); int b=inequalities.getHeight(); // Implementation below could be moved to nonLP part of code. // small vector space defined by a+b equations.... big by a equations. ZMatrix M=combineLeftRight(combineLeftRight( equations.transposed(), inequalities.transposed()), ZMatrix::identity(n)); M.reduce(false,true); /* [A|B|I] is reduced to [A'|B'|C'] meaning [A'|B']=C'[A|B] and A'=C'A. [A'|B'] is in row echelon form, implying that the rows of C' corresponding to zero rows of [A'|B'] generate the lattice cokernel of [A|B] - that is the linealityspace intersected with Z^n. [A'] is in row echelon form, implying that the rows of C' corresponding to zero rows of [A'] generate the lattice cokernel of [A] - that is the span of the cone intersected with Z^n. It is clear that the second row set is a superset of the first. Their difference is a basis for the quotient. */ ZMatrix ret(0,n); for(int i=0;i=1)?PCP_impliedEquationsKnown:0); ret.ensureStateAsMinimum(state); return ret; } ZMatrix ZCone::getInequalities()const { return inequalities; } ZMatrix ZCone::getEquations()const { return equations; } ZMatrix ZCone::generatorsOfSpan()const { ensureStateAsMinimum(1); QMatrix l=ZToQMatrix(equations); return QToZMatrixPrimitive(l.reduceAndComputeKernel()); } ZMatrix ZCone::generatorsOfLinealitySpace()const { QMatrix l=ZToQMatrix(combineOnTop(inequalities,equations)); return QToZMatrixPrimitive(l.reduceAndComputeKernel()); } };