source: git/gfanlib/gfanlib_zcone.cpp @ a3a6a0

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