source: git/gfanlib/gfanlib_zcone.cpp @ ee3e7cd

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