source: git/gfanlib/gfanlib_zcone.cpp @ 24aeb0f

spielwiese
Last change on this file since 24aeb0f was 24aeb0f, checked in by Hans Schoenemann <hannes@…>, 11 years ago
fix: cddlib detection for fedora
  • Property mode set to 100644
File size: 33.7 KB
Line 
1/*
2 * lib_cone.cpp
3 *
4 *  Created on: Sep 29, 2010
5 *      Author: anders
6 */
7
8#include "gfanlib_zcone.h"
9
10#include <vector>
11#include <set>
12
13#ifdef HAVE_CONFIG_H
14#include "config.h"
15#endif /* HAVE_CONFIG_H */
16#ifdef HAVE_CDD_SETOPER_H
17#include "cdd/setoper.h"
18#include "cdd/cdd.h"
19#elif HAVE_CDDLIB_SETOPER_H
20#include "cddlib/setoper.h"
21#include "cddlib/cdd.h"
22#else
23#include "setoper.h"
24#include "cdd.h"
25#endif
26
27namespace gfan{
28
29  static void cddinitGmp()
30  {
31    static bool initialized;
32    if(!initialized)
33      {
34        dd_set_global_constants();  /* First, this must be called. */
35        initialized=true;
36      }
37  }
38
39
40class LpSolver
41{
42  static dd_MatrixPtr ZMatrix2MatrixGmp(ZMatrix const &g, dd_ErrorType *Error)
43  {
44    int n=g.getWidth();
45    dd_MatrixPtr M=NULL;
46    dd_rowrange m_input,i;
47    dd_colrange d_input,j;
48    dd_RepresentationType rep=dd_Inequality;
49    // dd_boolean found=dd_FALSE, newformat=dd_FALSE, successful=dd_FALSE;
50    // char command[dd_linelenmax], comsave[dd_linelenmax];
51    dd_NumberType NT;
52
53    (*Error)=dd_NoError;
54
55    rep=dd_Inequality; // newformat=dd_TRUE;
56
57    m_input=g.getHeight();
58    d_input=n+1;
59
60    NT=dd_Rational;
61
62    M=dd_CreateMatrix(m_input, d_input);
63    M->representation=rep;
64    M->numbtype=NT;
65
66    for (i = 0; i < m_input; i++) {
67      dd_set_si(M->matrix[i][0],0);
68      for (j = 1; j < d_input; j++) {
69        g[i][j-1].setGmp(mpq_numref(M->matrix[i][j]));
70        mpz_init_set_ui(mpq_denref(M->matrix[i][j]), 1);
71        mpq_canonicalize(M->matrix[i][j]);
72      }
73    }
74
75    // successful=dd_TRUE;
76
77    return M;
78  }
79  static dd_MatrixPtr ZMatrix2MatrixGmp(ZMatrix const &inequalities, ZMatrix const &equations, dd_ErrorType *err)
80  {
81    ZMatrix g=inequalities;
82    g.append(equations);
83    int numberOfInequalities=inequalities.getHeight();
84    int numberOfRows=g.getHeight();
85    dd_MatrixPtr A=NULL;
86    cddinitGmp();
87    A=ZMatrix2MatrixGmp(g, err);
88    for(int i=numberOfInequalities;i<numberOfRows;i++)
89      set_addelem(A->linset,i+1);
90    return A;
91  }
92  static ZMatrix getConstraints(dd_MatrixPtr A, bool returnEquations)
93  {
94    int rowsize=A->rowsize;
95    int n=A->colsize-1;
96
97    ZMatrix ret(0,n);
98    for(int i=0;i<rowsize;i++)
99      {
100        bool isEquation=set_member(i+1,A->linset);
101        if(isEquation==returnEquations)
102          {
103            QVector v(n);
104            for(int j=0;j<n;j++)v[j]=Rational(A->matrix[i][j+1]);
105            ret.appendRow(QToZVectorPrimitive(v));
106          }
107      }
108    return ret;
109  }
110  static bool isFacet(ZMatrix const &g, int index)
111  {
112    bool ret;
113    dd_MatrixPtr M=NULL/*,M2=NULL,M3=NULL*/;
114    // dd_colrange d;
115    dd_ErrorType err=dd_NoError;
116    // dd_rowset redrows,linrows,ignoredrows, basisrows;
117    // dd_colset ignoredcols, basiscols;
118    // dd_DataFileType inputfile;
119    // FILE *reading=NULL;
120
121    cddinitGmp();
122
123    M=ZMatrix2MatrixGmp(g, &err);
124    if (err!=dd_NoError) goto _L99;
125
126    // d=M->colsize;
127
128    static dd_Arow temp;
129    dd_InitializeArow(g.getWidth()+1,&temp);
130
131    ret= !dd_Redundant(M,index+1,temp,&err);
132
133    dd_FreeMatrix(M);
134    dd_FreeArow(g.getWidth()+1,temp);
135
136    if (err!=dd_NoError) goto _L99;
137    return ret;
138   _L99:
139    assert(0);
140    return false;
141  }
142
143  /*
144    Heuristic for checking if inequality of full dimensional cone is a
145    facet. If the routine returns true then the inequality is a
146    facet. If it returns false it is unknown.
147   */
148  static bool fastIsFacetCriterion(ZMatrix const &normals, int i)
149  {
150    int n=normals.getWidth();
151    for(int j=0;j<n;j++)
152      if(normals[i][j].sign()!=0)
153        {
154          int sign=normals[i][j].sign();
155          bool isTheOnly=true;
156          for(int k=0;k<normals.getHeight();k++)
157            if(k!=i)
158              {
159                if(normals[i][j].sign()==sign)
160                  {
161                    isTheOnly=false;
162                    break;
163                  }
164              }
165          if(isTheOnly)return true;
166        }
167    return false;
168  }
169
170  static bool fastIsFacet(ZMatrix const &normals, int i)
171  {
172    if(fastIsFacetCriterion(normals,i))return true;
173    return isFacet(normals,i);
174  }
175
176  class MyHashMap
177  {
178    typedef std::vector<std::set<ZVector> > Container;
179    Container container;
180    int tableSize;
181  public:
182    class iterator
183    {
184      class MyHashMap &hashMap;
185      int index; // having index==-1 means that we are before/after the elements.
186      std::set<ZVector>::iterator i;
187    public:
188      bool operator++()
189      {
190        if(index==-1)goto search;
191        i++;
192        while(i==hashMap.container[index].end())
193          {
194            search:
195            index++;
196            if(index>=hashMap.tableSize){
197              index=-1;
198              return false;
199            }
200            i=hashMap.container[index].begin();
201          }
202        return true;
203      }
204      ZVector const & operator*()const
205      {
206        return *i;
207      }
208      ZVector operator*()
209      {
210        return *i;
211      }
212      iterator(MyHashMap &hashMap_):
213        hashMap(hashMap_)
214        {
215          index=-1;
216        }
217    };
218    unsigned int function(const ZVector &v)
219    {
220      unsigned int ret=0;
221      int n=v.size();
222      for(int i=0;i<n;i++)
223        ret=(ret<<3)+(ret>>29)+v.UNCHECKEDACCESS(i).hashValue();
224      return ret%tableSize;
225    }
226    MyHashMap(int tableSize_):
227      container(tableSize_),
228      tableSize(tableSize_)
229      {
230        assert(tableSize_>0);
231      }
232    void insert(const ZVector &v)
233    {
234      container[function(v)].insert(v);
235    }
236    void erase(ZVector const &v)
237    {
238      container[function(v)].erase(v);
239    }
240    iterator begin()
241    {
242      iterator ret(*this);
243      ++    ret;
244      return ret;
245    }
246    int size()
247    {
248      iterator i=begin();
249      int ret=0;
250      do{ret++;}while(++i);
251      return ret;
252    }
253  };
254
255
256  static ZMatrix normalizedWithSumsAndDuplicatesRemoved(ZMatrix const &a)
257  {
258    // TODO: write a version of this function which will work faster if the entries fit in 32bit
259    if(a.getHeight()==0)return a;
260    int n=a.getWidth();
261    ZVector temp1(n);
262//    ZVector temp2(n);
263    ZMatrix ret(0,n);
264    MyHashMap b(a.getHeight());
265
266    for(int i=0;i<a.getHeight();i++)
267      {
268        assert(!(a[i].isZero()));
269        b.insert(a[i].normalized());
270      }
271
272      {
273        MyHashMap::iterator i=b.begin();
274
275        do
276          {
277            MyHashMap::iterator j=i;
278            while(++j)
279              {
280                ZVector const &I=*i;
281                ZVector const &J=*j;
282                for(int k=0;k<n;k++)temp1[k]=I.UNCHECKEDACCESS(k)+J.UNCHECKEDACCESS(k);
283//                normalizedLowLevel(temp1,temp2);
284//                b.erase(temp2);//this can never remove *i or *j
285                b.erase(temp1.normalized());//this can never remove *i or *j
286              }
287          }
288          while(++i);
289      }
290    ZMatrix original(0,n);
291    {
292      MyHashMap::iterator i=b.begin();
293      do
294        {
295          original.appendRow(*i);
296        }
297      while(++i);
298    }
299
300    for(int i=0;i!=original.getHeight();i++)
301      for(int j=0;j!=a.getHeight();j++)
302        if(!dependent(original[i],a[j]))
303            {
304              ZVector const &I=original[i];
305              ZVector const &J=a[j];
306              for(int k=0;k<n;k++)temp1[k]=I.UNCHECKEDACCESS(k)+J.UNCHECKEDACCESS(k);
307//              normalizedLowLevel(temp1,temp2);
308//              b.erase(temp2);//this can never remove *i or *j
309              b.erase(temp1.normalized());//this can never remove *i or *j
310            }
311        {
312          MyHashMap::iterator i=b.begin();
313          do
314          {
315            ZVector temp=*i;
316            ret.appendRow(temp);
317          }
318          while(++i);
319      }
320    return ret;
321  }
322public:
323  static ZMatrix fastNormals(ZMatrix const &inequalities)
324  {
325    ZMatrix normals=normalizedWithSumsAndDuplicatesRemoved(inequalities);
326    for(int i=0;i!=normals.getHeight();i++)
327      if(!fastIsFacet(normals,i))
328        {
329          normals[i]=normals[normals.getHeight()-1];
330          normals.eraseLastRow();
331          i--;
332        }
333    return normals;
334  }
335  void removeRedundantRows(ZMatrix &inequalities, ZMatrix &equations, bool removeInequalityRedundancies)
336  {
337    cddinitGmp();
338    int numberOfEqualities=equations.getHeight();
339    int numberOfInequalities=inequalities.getHeight();
340    int numberOfRows=numberOfEqualities+numberOfInequalities;
341
342    if(numberOfRows==0)return;//the full space, so description is already irredundant
343
344    // dd_rowset r=NULL;
345    ZMatrix g=inequalities;
346    g.append(equations);
347
348    // dd_LPSolverType solver=dd_DualSimplex;
349    dd_MatrixPtr A=NULL;
350    dd_ErrorType err=dd_NoError;
351
352    A=ZMatrix2MatrixGmp(g,&err);
353    if (err!=dd_NoError) goto _L99;
354
355    for(int i=numberOfInequalities;i<numberOfRows;i++)
356      set_addelem(A->linset,i+1);
357
358    A->objective=dd_LPmax;
359
360    dd_rowset impl_linset;
361    dd_rowset redset;
362    dd_rowindex newpos;
363
364    if(removeInequalityRedundancies)
365      dd_MatrixCanonicalize(&A, &impl_linset, &redset, &newpos, &err);
366    else
367      dd_MatrixCanonicalizeLinearity(&A, &impl_linset, &newpos, &err);
368
369    if (err!=dd_NoError) goto _L99;
370
371    {
372      int n=A->colsize-1;
373      equations=ZMatrix(0,n);     //TODO: the number of rows needed is actually known
374      inequalities=ZMatrix(0,n);  //is known by set_card(). That might save some copying.
375
376      {
377        int rowsize=A->rowsize;
378        QVector point(n);
379        for(int i=0;i<rowsize;i++)
380          {
381            for(int j=0;j<n;j++)point[j]=Rational(A->matrix[i][j+1]);
382            ((set_member(i+1,A->linset))?equations:inequalities).appendRow(QToZVectorPrimitive(point));
383          }
384      }
385      assert(set_card(A->linset)==equations.getHeight());
386      assert(A->rowsize==equations.getHeight()+inequalities.getHeight());
387
388      set_free(impl_linset);
389      if(removeInequalityRedundancies)
390        set_free(redset);
391      free(newpos);
392
393      dd_FreeMatrix(A);
394      return;
395    }
396   _L99:
397    assert(!"Cddlib reported error when called by Gfanlib.");
398  }
399  ZVector relativeInteriorPoint(const ZMatrix &inequalities, const ZMatrix &equations)
400  {
401    QVector retUnscaled(inequalities.getWidth());
402    cddinitGmp();
403    int numberOfEqualities=equations.getHeight();
404    int numberOfInequalities=inequalities.getHeight();
405    int numberOfRows=numberOfEqualities+numberOfInequalities;
406
407    // dd_rowset r=NULL;
408    ZMatrix g=inequalities;
409    g.append(equations);
410
411    dd_LPSolverType solver=dd_DualSimplex;
412    dd_MatrixPtr A=NULL;
413    dd_ErrorType err=dd_NoError;
414
415    A=ZMatrix2MatrixGmp(g,&err);
416    if (err!=dd_NoError) goto _L99;
417    {
418      dd_LPSolutionPtr lps1;
419      dd_LPPtr lp,lp1;
420
421      for(int i=0;i<numberOfInequalities;i++)
422        dd_set_si(A->matrix[i][0],-1);
423      for(int i=numberOfInequalities;i<numberOfRows;i++)
424        set_addelem(A->linset,i+1);
425
426      A->objective=dd_LPmax;
427      lp=dd_Matrix2LP(A, &err);
428      if (err!=dd_NoError) goto _L99;
429
430      lp1=dd_MakeLPforInteriorFinding(lp);
431      dd_LPSolve(lp1,solver,&err);
432      if (err!=dd_NoError) goto _L99;
433
434      lps1=dd_CopyLPSolution(lp1);
435
436      assert(!dd_Negative(lps1->optvalue));
437
438      for (int j=1; j <(lps1->d)-1; j++)
439        retUnscaled[j-1]=Rational(lps1->sol[j]);
440
441      dd_FreeLPData(lp);
442      dd_FreeLPSolution(lps1);
443      dd_FreeLPData(lp1);
444      dd_FreeMatrix(A);
445      return QToZVectorPrimitive(retUnscaled);
446    }
447_L99:
448    assert(0);
449    return QToZVectorPrimitive(retUnscaled);
450  }
451  void dual(ZMatrix const &inequalities, ZMatrix const &equations, ZMatrix &dualInequalities, ZMatrix &dualEquations)
452  {
453    // int result;
454
455    dd_MatrixPtr A=NULL;
456    dd_ErrorType err=dd_NoError;
457
458    cddinitGmp();
459
460    A=ZMatrix2MatrixGmp(inequalities, equations, &err);
461
462    dd_PolyhedraPtr poly;
463    poly=dd_DDMatrix2Poly2(A, dd_LexMin, &err);
464
465    if (poly->child==NULL || poly->child->CompStatus!=dd_AllFound) assert(0);
466
467    dd_MatrixPtr      A2=dd_CopyGenerators(poly);
468
469    dualInequalities=getConstraints(A2,false);
470    dualEquations=getConstraints(A2,true);
471
472    dd_FreeMatrix(A2);
473    dd_FreeMatrix(A);
474    dd_FreePolyhedra(poly);
475
476    return;
477   // _L99:
478   //  assert(0);
479  }
480  // this procedure is take from cddio.c.
481  static void dd_ComputeAinc(dd_PolyhedraPtr poly)
482  {
483  /* This generates the input incidence array poly->Ainc, and
484     two sets: poly->Ared, poly->Adom.
485  */
486    dd_bigrange k;
487    dd_rowrange i,m1;
488    dd_colrange j;
489    dd_boolean redundant;
490    dd_MatrixPtr M=NULL;
491    mytype sum,temp;
492
493    dd_init(sum); dd_init(temp);
494    if (poly->AincGenerated==dd_TRUE) goto _L99;
495
496    M=dd_CopyOutput(poly);
497    poly->n=M->rowsize;
498    m1=poly->m1;
499
500    /* this number is same as poly->m, except when
501        poly is given by nonhomogeneous inequalty:
502        !(poly->homogeneous) && poly->representation==Inequality,
503        it is poly->m+1.   See dd_ConeDataLoad.
504     */
505    poly->Ainc=(set_type*)calloc(m1, sizeof(set_type));
506    for(i=1; i<=m1; i++) set_initialize(&(poly->Ainc[i-1]),poly->n);
507    set_initialize(&(poly->Ared), m1);
508    set_initialize(&(poly->Adom), m1);
509
510    for (k=1; k<=poly->n; k++){
511      for (i=1; i<=poly->m; i++){
512        dd_set(sum,dd_purezero);
513        for (j=1; j<=poly->d; j++){
514          dd_mul(temp,poly->A[i-1][j-1],M->matrix[k-1][j-1]);
515          dd_add(sum,sum,temp);
516        }
517        if (dd_EqualToZero(sum)) {
518          set_addelem(poly->Ainc[i-1], k);
519        }
520      }
521      if (!(poly->homogeneous) && poly->representation==dd_Inequality){
522        if (dd_EqualToZero(M->matrix[k-1][0])) {
523          set_addelem(poly->Ainc[m1-1], k);  /* added infinity inequality (1,0,0,...,0) */
524        }
525      }
526    }
527
528    for (i=1; i<=m1; i++){
529      if (set_card(poly->Ainc[i-1])==M->rowsize){
530        set_addelem(poly->Adom, i);
531      }
532    }
533    for (i=m1; i>=1; i--){
534      if (set_card(poly->Ainc[i-1])==0){
535        redundant=dd_TRUE;
536        set_addelem(poly->Ared, i);
537      }else {
538        redundant=dd_FALSE;
539        for (k=1; k<=m1; k++) {
540          if (k!=i && !set_member(k, poly->Ared)  && !set_member(k, poly->Adom) &&
541              set_subset(poly->Ainc[i-1], poly->Ainc[k-1])){
542            if (!redundant){
543              redundant=dd_TRUE;
544            }
545            set_addelem(poly->Ared, i);
546          }
547        }
548      }
549    }
550    dd_FreeMatrix(M);
551    poly->AincGenerated=dd_TRUE;
552  _L99:;
553    dd_clear(sum);  dd_clear(temp);
554  }
555
556
557  std::vector<std::vector<int> > extremeRaysInequalityIndices(const ZMatrix &inequalities)
558  {
559    int dim2=inequalities.getHeight();
560    if(dim2==0)return std::vector<std::vector<int> >();
561    // int dimension=inequalities.getWidth();
562
563    dd_MatrixPtr A=NULL;
564    dd_ErrorType err=dd_NoError;
565
566    cddinitGmp();
567    A=ZMatrix2MatrixGmp(inequalities, &err);
568
569    dd_PolyhedraPtr poly;
570    poly=dd_DDMatrix2Poly2(A, dd_LexMin, &err);
571
572    if (poly->child==NULL || poly->child->CompStatus!=dd_AllFound) assert(0);
573    if (poly->AincGenerated==dd_FALSE) dd_ComputeAinc(poly);
574
575    std::vector<std::vector<int> > ret;
576
577    /*
578      How do we interpret the cddlib output?  For a long ting gfan has
579      been using poly->n as the number of rays of the cone and thus
580      returned sets of indices that actually gave the lineality
581      space. The mistake was then caught later in PolyhedralCone. On Feb
582      17 2009 gfan was changed to check the length of each set to make
583      sure that it does not specify the lineality space and only return
584      those sets giving rise to rays.  This does not seem to be the best
585      strategy and might even be wrong.
586     */
587
588
589    for (int k=1; k<=poly->n; k++)
590      {
591        int length=0;
592        for (int i=1; i<=poly->m1; i++)
593          if(set_member(k,poly->Ainc[i-1]))length++;
594        if(length!=dim2)
595          {
596            std::vector<int> v(length);
597            int j=0;
598            for (int i=1; i<=poly->m1; i++)
599              if(set_member(k,poly->Ainc[i-1]))v[j++]=i-1;
600            ret.push_back(v);
601          }
602      }
603
604    dd_FreeMatrix(A);
605    dd_FreePolyhedra(poly);
606
607    return ret;
608   // _L99:
609   //  assert(0);
610   //  return std::vector<std::vector<int> >();
611  }
612
613};
614
615LpSolver lpSolver;
616
617bool ZCone::isInStateMinimum(int s)const
618{
619  return state>=s;
620}
621
622
623bool operator<(ZCone const &a, ZCone const &b)
624{
625  assert(a.state>=3);
626  assert(b.state>=3);
627
628  if(a.n<b.n)return true;
629  if(a.n>b.n)return false;
630
631  if(a.equations<b.equations)return true;
632  if(b.equations<a.equations)return false;
633
634  if(a.inequalities<b.inequalities)return true;
635  if(b.inequalities<a.inequalities)return false;
636
637  return false;
638}
639
640
641bool operator!=(ZCone const &a, ZCone const &b)
642{
643  return (a<b)||(b<a);
644}
645
646
647void ZCone::ensureStateAsMinimum(int s)const
648{
649  if((state<1) && (s==1))
650    {
651     {
652        QMatrix m=ZToQMatrix(equations);
653        m.reduce();
654        m.removeZeroRows();
655
656        ZMatrix newInequalities(0,inequalities.getWidth());
657        for(int i=0;i<inequalities.getHeight();i++)
658          {
659            QVector w=ZToQVector(inequalities[i]);
660            w=m.canonicalize(w);
661            if(!w.isZero())
662              newInequalities.appendRow(QToZVectorPrimitive(w));
663          }
664
665        inequalities=newInequalities;
666        inequalities.sortAndRemoveDuplicateRows();
667        equations=QToZMatrixPrimitive(m);
668      }
669
670      if(!(preassumptions&PCP_impliedEquationsKnown))
671      if(inequalities.getHeight()>1)//there can be no implied equation unless we have at least two inequalities
672        lpSolver.removeRedundantRows(inequalities,equations,false);
673
674      assert(inequalities.getWidth()==equations.getWidth());
675      }
676  if((state<2) && (s>=2) && !(preassumptions&PCP_facetsKnown))
677    {
678/*       if(inequalities.size()>25)
679         {
680          IntegerVectorList h1;
681          IntegerVectorList h2;
682          bool a=false;
683          for(IntegerVectorList::const_iterator i=inequalities.begin();i!=inequalities.end();i++)
684            {
685              if(a)
686                h1.push_back(*i);
687              else
688                h2.push_back(*i);
689              a=!a;
690            }
691          PolyhedralCone c1(h1,equations);
692          PolyhedralCone c2(h2,equations);
693          c1.ensureStateAsMinimum(2);
694          c2.ensureStateAsMinimum(2);
695          inequalities=c1.inequalities;
696          for(IntegerVectorList::const_iterator i=c2.inequalities.begin();i!=c2.inequalities.end();i++)
697            inequalities.push_back(*i);
698        }
699*/
700      if(equations.getHeight())
701        {
702          QMatrix m=ZToQMatrix(equations);
703          m.reduce();
704          m.REformToRREform(true);
705          ZMatrix inequalities2(0,equations.getWidth());
706          for(int i=0;i<inequalities.getHeight();i++)
707            {
708              inequalities2.appendRow(QToZVectorPrimitive(m.canonicalize(ZToQVector(inequalities[i]))));
709            }
710          inequalities=LpSolver::fastNormals(inequalities2);
711          goto noFallBack;
712        // fallBack://alternativ (disabled)
713        //   lpSolver.removeRedundantRows(inequalities,equations,true);
714        noFallBack:;
715        }
716      else
717        inequalities=LpSolver::fastNormals(inequalities);
718    }
719  if((state<3) && (s>=3))
720    {
721      QMatrix equations2=ZToQMatrix(equations);
722      equations2.reduce(false,false,true);
723      equations2.REformToRREform();
724      for(int i=0;i<inequalities.getHeight();i++)
725        {
726          inequalities[i]=QToZVectorPrimitive(equations2.canonicalize(ZToQVector(inequalities[i])));
727        }
728      inequalities.sortRows();
729      equations=QToZMatrixPrimitive(equations2);
730    }
731  if(state<s)
732    state=s;
733}
734
735void operator<<(std::ostream &f, ZCone const &c)
736{
737  f<<"Ambient dimension:"<<c.n<<std::endl;
738  f<<"Inequalities:"<<std::endl;
739  f<<c.inequalities<<std::endl;
740  f<<"Equations:"<<std::endl;
741  f<<c.equations<<std::endl;
742}
743
744
745ZCone::ZCone(int ambientDimension):
746  preassumptions(PCP_impliedEquationsKnown|PCP_facetsKnown),
747  state(1),
748  n(ambientDimension),
749  multiplicity(1),
750  linearForms(ZMatrix(0,ambientDimension)),
751  inequalities(ZMatrix(0,ambientDimension)),
752  equations(ZMatrix(0,ambientDimension)),
753  haveExtremeRaysBeenCached(false)
754{
755}
756
757
758ZCone::ZCone(ZMatrix const &inequalities_, ZMatrix const &equations_, int preassumptions_):
759  preassumptions(preassumptions_),
760  state(0),
761  n(inequalities_.getWidth()),
762  multiplicity(1),
763  linearForms(ZMatrix(0,inequalities_.getWidth())),
764  inequalities(inequalities_),
765  equations(equations_),
766  haveExtremeRaysBeenCached(false)
767  {
768  assert(preassumptions_<4);//OTHERWISE WE ARE DOING SOMETHING STUPID LIKE SPECIFYING AMBIENT DIMENSION
769  assert(equations_.getWidth()==n);
770  ensureStateAsMinimum(1);
771}
772
773void ZCone::canonicalize()
774{
775  ensureStateAsMinimum(3);
776}
777
778void ZCone::findFacets()
779{
780  ensureStateAsMinimum(2);
781}
782
783ZMatrix ZCone::getFacets()const
784{
785  ensureStateAsMinimum(2);
786  return inequalities;
787}
788
789void ZCone::findImpliedEquations()
790{
791  ensureStateAsMinimum(1);
792}
793
794ZMatrix ZCone::getImpliedEquations()const
795{
796  ensureStateAsMinimum(1);
797  return equations;
798}
799
800ZVector ZCone::getRelativeInteriorPoint()const
801{
802  ensureStateAsMinimum(1);
803//  assert(state>=1);
804
805  return lpSolver.relativeInteriorPoint(inequalities,equations);
806}
807
808ZVector ZCone::getUniquePoint()const
809{
810  ZMatrix rays=extremeRays();
811  ZVector ret(n);
812  for(int i=0;i<rays.getHeight();i++)
813    ret+=rays[i];
814
815  return ret;
816}
817
818ZVector ZCone::getUniquePointFromExtremeRays(ZMatrix const &extremeRays)const
819{
820  ZVector ret(n);
821  for(int i=0;i<extremeRays.getHeight();i++)
822    if(contains(extremeRays[i]))ret+=extremeRays[i];
823  return ret;
824}
825
826
827int ZCone::ambientDimension()const
828{
829  return n;
830}
831
832
833int ZCone::codimension()const
834{
835  return ambientDimension()-dimension();
836}
837
838
839int ZCone::dimension()const
840{
841//  assert(state>=1);
842  ensureStateAsMinimum(1);
843  return ambientDimension()-equations.getHeight();
844}
845
846
847int ZCone::dimensionOfLinealitySpace()const
848{
849  ZMatrix temp=inequalities;
850  temp.append(equations);
851  ZCone temp2(ZMatrix(0,n),temp);
852  return temp2.dimension();
853}
854
855
856bool ZCone::isOrigin()const
857{
858  return dimension()==0;
859}
860
861
862bool ZCone::isFullSpace()const
863{
864  for(int i=0;i<inequalities.getHeight();i++)
865    if(!inequalities[i].isZero())return false;
866  for(int i=0;i<equations.getHeight();i++)
867    if(!equations[i].isZero())return false;
868  return true;
869}
870
871
872ZCone intersection(const ZCone &a, const ZCone &b)
873{
874  assert(a.ambientDimension()==b.ambientDimension());
875  ZMatrix inequalities=a.inequalities;
876  inequalities.append(b.inequalities);
877  ZMatrix equations=a.equations;
878  equations.append(b.equations);
879
880  equations.sortAndRemoveDuplicateRows();
881  inequalities.sortAndRemoveDuplicateRows();
882
883  {
884    ZMatrix Aequations=a.equations;
885    ZMatrix Ainequalities=a.inequalities;
886    Aequations.sortAndRemoveDuplicateRows();
887    Ainequalities.sortAndRemoveDuplicateRows();
888    if((Ainequalities.getHeight()==inequalities.getHeight()) && (Aequations.getHeight()==equations.getHeight()))return a;
889    ZMatrix Bequations=b.equations;
890    ZMatrix Binequalities=b.inequalities;
891    Bequations.sortAndRemoveDuplicateRows();
892    Binequalities.sortAndRemoveDuplicateRows();
893    if((Binequalities.getHeight()==inequalities.getHeight()) && (Bequations.getHeight()==equations.getHeight()))return b;
894  }
895
896  return ZCone(inequalities,equations);
897}
898
899/*
900PolyhedralCone product(const PolyhedralCone &a, const PolyhedralCone &b)
901{
902  IntegerVectorList equations2;
903  IntegerVectorList inequalities2;
904
905  int n1=a.n;
906  int n2=b.n;
907
908  for(IntegerVectorList::const_iterator i=a.equations.begin();i!=a.equations.end();i++)
909    equations2.push_back(concatenation(*i,IntegerVector(n2)));
910  for(IntegerVectorList::const_iterator i=b.equations.begin();i!=b.equations.end();i++)
911    equations2.push_back(concatenation(IntegerVector(n1),*i));
912  for(IntegerVectorList::const_iterator i=a.inequalities.begin();i!=a.inequalities.end();i++)
913    inequalities2.push_back(concatenation(*i,IntegerVector(n2)));
914  for(IntegerVectorList::const_iterator i=b.inequalities.begin();i!=b.inequalities.end();i++)
915    inequalities2.push_back(concatenation(IntegerVector(n1),*i));
916
917  PolyhedralCone ret(inequalities2,equations2,n1+n2);
918  ret.setMultiplicity(a.getMultiplicity()*b.getMultiplicity());
919  ret.setLinearForm(concatenation(a.getLinearForm(),b.getLinearForm()));
920
921  ret.ensureStateAsMinimum(a.state);
922  ret.ensureStateAsMinimum(b.state);
923
924  return ret;
925}*/
926
927
928ZCone ZCone::positiveOrthant(int dimension)
929{
930  return ZCone(ZMatrix::identity(dimension),ZMatrix(0,dimension));
931}
932
933
934ZCone ZCone::givenByRays(ZMatrix const &generators, ZMatrix const &linealitySpace)
935{
936  ZCone dual(generators,linealitySpace);
937  ZMatrix inequalities=dual.extremeRays();
938  ZMatrix equations=dual.generatorsOfLinealitySpace();
939
940  return ZCone(inequalities,equations,3);
941}
942
943
944bool ZCone::containsPositiveVector()const
945{
946  ZCone temp=intersection(*this,ZCone::positiveOrthant(n));
947  return temp.getRelativeInteriorPoint().isPositive();
948}
949
950
951bool ZCone::contains(ZVector const &v)const
952{
953  for(int i=0;i<equations.getHeight();i++)
954    {
955      if(!dot(equations[i],v).isZero())return false;
956    }
957  for(int i=0;i<inequalities.getHeight();i++)
958    {
959      if(dot(inequalities[i],v).sign()<0)return false;
960    }
961  return true;
962}
963
964
965bool ZCone::containsRowsOf(ZMatrix const &m)const
966{
967  for(int i=0;i<m.getHeight();i++)
968    if(!contains(m[i]))return false;
969  return true;
970}
971
972
973bool ZCone::contains(ZCone const &c)const
974{
975  ZCone c2=intersection(*this,c);
976  ZCone c3=c;
977  c2.canonicalize();
978  c3.canonicalize();
979  return !(c2!=c3);
980}
981
982
983bool ZCone::containsRelatively(ZVector const &v)const
984{
985  ensureStateAsMinimum(1);
986//  assert(state>=1);
987  for(int i=0;i<equations.getHeight();i++)
988    {
989      if(!dot(equations[i],v).isZero())return false;
990    }
991  for(int i=0;i<inequalities.getHeight();i++)
992    {
993      if(dot(inequalities[i],v).sign()<=0)return false;
994    }
995  return true;
996}
997
998
999bool ZCone::isSimplicial()const
1000{
1001//  assert(state>=2);
1002  ensureStateAsMinimum(2);
1003  return codimension()+inequalities.getHeight()+dimensionOfLinealitySpace()==n;
1004}
1005
1006
1007ZCone ZCone::linealitySpace()const
1008{
1009  ZCone ret(ZMatrix(0,n),combineOnTop(equations,inequalities));
1010//  ret.ensureStateAsMinimum(state);
1011  return ret;
1012}
1013
1014
1015ZCone ZCone::dualCone()const
1016{
1017  ensureStateAsMinimum(1);
1018//  assert(state>=1);
1019
1020  ZMatrix dualInequalities,dualEquations;
1021  lpSolver.dual(inequalities,equations,dualInequalities,dualEquations);
1022  ZCone ret(dualInequalities,dualEquations);
1023  ret.ensureStateAsMinimum(state);
1024
1025  return ret;
1026}
1027
1028
1029ZCone ZCone::negated()const
1030{
1031  ZCone ret(-inequalities,equations,(areFacetsKnown()?PCP_facetsKnown:0)|(areImpliedEquationsKnown()?PCP_impliedEquationsKnown:0));
1032//  ret.ensureStateAsMinimum(state);
1033  return ret;
1034}
1035
1036
1037ZMatrix ZCone::extremeRays(ZMatrix const *generatorsOfLinealitySpace)const
1038{
1039//  assert((dimension()==ambientDimension()) || (state>=3));
1040  if(dimension()!=ambientDimension())
1041    ensureStateAsMinimum(3);
1042
1043  if(haveExtremeRaysBeenCached)return cachedExtremeRays;
1044  ZMatrix ret(0,n);
1045  std::vector<std::vector<int> > indices=lpSolver.extremeRaysInequalityIndices(inequalities);
1046
1047  for(unsigned i=0;i<indices.size();i++)
1048    {
1049      /* At this point we know lineality space, implied equations and
1050         also inequalities for the ray. To construct a vector on the
1051         ray which is stable under (or indendent of) angle and
1052         linarity preserving transformation we find the dimension 1
1053         subspace orthorgonal to the implied equations and the
1054         lineality space and pick a suitable primitive generator */
1055
1056          /* To be more precise,
1057           * let E be the set of equations, and v the inequality defining a  ray R.
1058           * We wish to find a vector satisfying these, but it must also be orthogonal
1059           * to the lineality space of the cone, that is, in the span of {E,v}.
1060           * One way to get such a vector is to project v to E an get a vector p.
1061           * Then v-p is in the span of {E,v} by construction.
1062           * The vector v-p is also in the orthogonal complement to E by construction,
1063           * that is, the span of R.
1064           * We wish to argue that it is not zero.
1065           * That would imply that v=p, meaning that v is in the span of the equations.
1066           * However, that would contradict that R is a ray.
1067           * In case v-p does not satisfy the inequality v (is this possible?), we change the sign.
1068           *
1069           * As a consequence we need the following procedure
1070           * primitiveProjection():
1071           *    Input: E,v
1072           *    Output: A primitive representation of the vector v-p, where p is the projection of v onto E
1073           *
1074           * Notice that the output is a Q linear combination of the input and that p is
1075           * a linear combination of E. The check that p has been computed correctly,
1076           * it suffices to check that v-p satisfies the equations E.
1077           * The routine will actually first compute a multiple of v-p.
1078           * It will do this using floating point arithmetics. It will then transform
1079           * the coefficients to get the multiple of v-p into integers. Then it
1080           * verifies in exact arithmetics, that with these coefficients we get a point
1081           * satisfying E. It then returns the primitive vector on the ray v-p.
1082           * In case of a failure it falls back to an implementation using rational arithmetics.
1083           */
1084
1085
1086          std::vector<int> asVector(inequalities.getHeight());
1087          for(unsigned j=0;j<indices[i].size();j++){asVector[indices[i][j]]=1;}
1088          ZMatrix equations=this->equations;
1089          ZVector theInequality;
1090
1091          for(unsigned j=0;j<asVector.size();j++)
1092            if(asVector[j])
1093              equations.appendRow(inequalities[j]);
1094            else
1095              theInequality=inequalities[j];
1096
1097          assert(!theInequality.isZero());
1098
1099          ZVector thePrimitiveVector;
1100          if(generatorsOfLinealitySpace)
1101          {
1102            QMatrix temp=ZToQMatrix(combineOnTop(equations,*generatorsOfLinealitySpace));
1103            thePrimitiveVector=QToZVectorPrimitive(temp.reduceAndComputeVectorInKernel());
1104          }
1105          else
1106          {
1107            QMatrix linealitySpaceOrth=ZToQMatrix(combineOnTop(this->equations,inequalities));
1108
1109
1110            QMatrix temp=combineOnTop(linealitySpaceOrth.reduceAndComputeKernel(),ZToQMatrix(equations));
1111            thePrimitiveVector=QToZVectorPrimitive(temp.reduceAndComputeVectorInKernel());
1112          }
1113          if(!contains(thePrimitiveVector))thePrimitiveVector=-thePrimitiveVector;
1114          ret.appendRow(thePrimitiveVector);
1115    }
1116
1117  cachedExtremeRays=ret;
1118  haveExtremeRaysBeenCached=true;
1119
1120  return ret;
1121}
1122
1123
1124Integer ZCone::getMultiplicity()const
1125{
1126  return multiplicity;
1127}
1128
1129
1130void ZCone::setMultiplicity(Integer const &m)
1131{
1132  multiplicity=m;
1133}
1134
1135
1136ZMatrix ZCone::getLinearForms()const
1137{
1138  return linearForms;
1139}
1140
1141
1142void ZCone::setLinearForms(ZMatrix const &linearForms_)
1143{
1144  linearForms=linearForms_;
1145}
1146
1147
1148ZMatrix ZCone::quotientLatticeBasis()const
1149{
1150//  assert(isInStateMinimum(1));// Implied equations must have been computed in order to know the span of the cone
1151  ensureStateAsMinimum(1);
1152
1153
1154  int a=equations.getHeight();
1155  int b=inequalities.getHeight();
1156
1157  // Implementation below could be moved to nonLP part of code.
1158
1159  // small vector space defined by a+b equations.... big by a equations.
1160
1161  ZMatrix M=combineLeftRight(combineLeftRight(
1162                                                  equations.transposed(),
1163                                                  inequalities.transposed()),
1164                                 ZMatrix::identity(n));
1165  M.reduce(false,true);
1166  /*
1167    [A|B|I] is reduced to [A'|B'|C'] meaning [A'|B']=C'[A|B] and A'=C'A.
1168
1169    [A'|B'] is in row echelon form, implying that the rows of C' corresponding to zero rows
1170    of [A'|B'] generate the lattice cokernel of [A|B] - that is the linealityspace intersected with Z^n.
1171
1172    [A'] is in row echelon form, implying that the rows of C' corresponding to zero rows of [A'] generate
1173    the lattice cokernel of [A] - that is the span of the cone intersected with Z^n.
1174
1175    It is clear that the second row set is a superset of the first. Their difference is a basis for the quotient.
1176   */
1177  ZMatrix ret(0,n);
1178
1179  for(int i=0;i<M.getHeight();i++)
1180    if(M[i].subvector(0,a).isZero()&&!M[i].subvector(a,a+b).isZero())
1181      {
1182        ret.appendRow(M[i].subvector(a+b,a+b+n));
1183      }
1184
1185  return ret;
1186}
1187
1188
1189ZVector ZCone::semiGroupGeneratorOfRay()const
1190{
1191  ZMatrix temp=quotientLatticeBasis();
1192  assert(temp.getHeight()==1);
1193  for(int i=0;i<inequalities.getHeight();i++)
1194    if(dot(temp[0],inequalities[i]).sign()<0)
1195      {
1196        temp[0]=-temp[0];
1197        break;
1198      }
1199  return temp[0];
1200}
1201
1202
1203ZCone ZCone::link(ZVector const &w)const
1204{
1205  /* Observe that the inequalities giving rise to facets
1206   * also give facets in the link, if they are kept as
1207   * inequalities. This means that the state cannot decrease
1208   * when taking links - that is why we specify the PCP flags.
1209   */
1210  ZMatrix inequalities2(0,n);
1211  for(int j=0;j<inequalities.getHeight();j++)
1212    if(dot(w,inequalities[j]).sign()==0)inequalities2.appendRow(inequalities[j]);
1213  ZCone C(inequalities2,equations,(areImpliedEquationsKnown()?PCP_impliedEquationsKnown:0)|(areFacetsKnown()?PCP_facetsKnown:0));
1214  C.ensureStateAsMinimum(state);
1215
1216  C.setLinearForms(getLinearForms());
1217  C.setMultiplicity(getMultiplicity());
1218
1219  return C;
1220}
1221
1222bool ZCone::hasFace(ZCone const &f)const
1223{
1224  if(!contains(f.getRelativeInteriorPoint()))return false;
1225  ZCone temp1=faceContaining(f.getRelativeInteriorPoint());
1226  temp1.canonicalize();
1227  ZCone temp2=f;
1228  temp2.canonicalize();
1229  return !(temp2!=temp1);
1230}
1231
1232ZCone ZCone::faceContaining(ZVector const &v)const
1233{
1234  assert(n==(int)v.size());
1235  assert(contains(v));
1236  ZMatrix newEquations=equations;
1237  ZMatrix newInequalities(0,n);
1238  for(int i=0;i<inequalities.getHeight();i++)
1239    if(dot(inequalities[i],v).sign()!=0)
1240      newInequalities.appendRow(inequalities[i]);
1241    else
1242      newEquations.appendRow(inequalities[i]);
1243
1244  ZCone ret(newInequalities,newEquations,(state>=1)?PCP_impliedEquationsKnown:0);
1245  ret.ensureStateAsMinimum(state);
1246  return ret;
1247}
1248
1249
1250ZMatrix ZCone::getInequalities()const
1251{
1252  return inequalities;
1253}
1254
1255
1256ZMatrix ZCone::getEquations()const
1257{
1258  return equations;
1259}
1260
1261
1262ZMatrix ZCone::generatorsOfSpan()const
1263{
1264  ensureStateAsMinimum(1);
1265  QMatrix l=ZToQMatrix(equations);
1266  return QToZMatrixPrimitive(l.reduceAndComputeKernel());
1267}
1268
1269
1270ZMatrix ZCone::generatorsOfLinealitySpace()const
1271{
1272  QMatrix l=ZToQMatrix(combineOnTop(inequalities,equations));
1273  return QToZMatrixPrimitive(l.reduceAndComputeKernel());
1274}
1275
1276};
Note: See TracBrowser for help on using the repository browser.