source: git/gfanlib/gfanlib_zcone.cpp @ 09b2c9b

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