Frobby  0.9.5
LatticeAlgs.cpp
Go to the documentation of this file.
1 /* Frobby: Software for monomial ideal computations.
2  Copyright (C) 2011 Bjarke Hammersholt Roune (www.broune.com)
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program. If not, see http://www.gnu.org/licenses/.
16 */
17 #include "stdinc.h"
18 #include "LatticeAlgs.h"
19 
20 #include <stack>
21 
22 void getThinPlanes(vector<TriPlane>& planes, const GrobLat& lat) {
23  planes.clear();
24  for (size_t a = 0; a <= lat.getNeighborCount(); ++a) {
25  Neighbor an(lat);
26  if (a < lat.getNeighborCount())
27  an = lat.getNeighbor(a);
28  for (size_t b = 0; b < lat.getNeighborCount(); ++b) {
29  for (size_t c = 0; c < lat.getNeighborCount(); ++c) {
30  TriPlane plane(an, lat.getNeighbor(b), lat.getNeighbor(c));
31  if (plane.isLine())
32  continue; // points are collinear
33  ASSERT(plane.isParallel(plane));
34  bool parallel = false;
35  for (size_t p = 0; p < planes.size(); ++p) {
36  if (plane.isParallel(planes[p])) {
37  parallel = true;
38  break;
39  }
40  }
41  if (parallel)
42  continue; // already got this plane
43 
44  bool isThin = true;
45  for (size_t n = 0; n < lat.getNeighborCount(); ++n) {
46  if (!plane.closeToPlane(lat.getNeighbor(n))) {
47  isThin = false;
48  break;
49  }
50  }
51  if (isThin)
52  planes.push_back(plane);
53  }
54  }
55  }
56 }
57 
58 /*
59 void checkParallelFaces(const vector<Mlfb>& mlfbs,
60  const vector<Plane> planes) {
61  vector<TriPlane> facePlanes;
62  for (size_t m = 0; m < mlfbs.size(); ++m) {
63  const Mlfb& mlfb = mlfbs[m];
64  cout << mlfb.getName() << facePlanes.size() << endl;
65  Neighbor a = mlfb.getPoint(0);
66  Neighbor b = mlfb.getPoint(1);
67  Neighbor c = mlfb.getPoint(2);
68  Neighbor d = mlfb.getPoint(3);
69  facePlanes.push_back(TriPlane(b, c, d));
70  facePlanes.push_back(TriPlane(a, c, d));
71  facePlanes.push_back(TriPlane(a, b, d));
72  facePlanes.push_back(TriPlane(a, b, c));
73  }
74 
75  for (size_t i = 0; i < facePlanes.size(); ++i) {
76  const TriPlane& plane = facePlanes[i];
77 
78  bool thin = false;
79  for (size_t p = 0; p < planes.size(); ++p) {
80  if (plane.isParallel(planes[p])) {
81  thin = true;
82  break;
83  }
84  }
85  if (thin)
86  continue;
87 
88  size_t parallelCount = 0;
89  for (size_t j = 0; j < facePlanes.size(); ++j)
90  if (plane.isParallel(facePlanes[j])) {cout << ' ' << j << endl;
91  ++parallelCount;}
92  cout << parallelCount << ' ' << plane.getNormal() << endl;
93  CHECK(parallelCount == 2); // not satisfied
94  }
95 }
96 */
97 
98 
99 void checkPlanes(const vector<TriPlane>& thinPlanes,
100  const vector<Plane>& dtPlanes) {
101  CHECK(thinPlanes.size() == dtPlanes.size());
102 
103  for (size_t thin = 0; thin < thinPlanes.size(); ++thin) {
104  bool parallel = false;
105  for (size_t dt = 0; dt < dtPlanes.size(); ++dt) {
106  if (thinPlanes[thin].isParallel(dtPlanes[dt])) {
107  parallel = true;
108  break;
109  }
110  }
111  CHECK(parallel);
112  }
113 
114  bool found = false;
115  for (size_t dt = 0; dt < dtPlanes.size(); ++dt) {
116  const Plane& plane = dtPlanes[dt];
117  size_t sum = plane.tri.getASideMlfbs().size() +
118  plane.tri.getBSideMlfbs().size();
119 
120  if (sum == 3)
121  found = true;
122  /*
123  if (plane.flatSeq.empty()) {
124  if (sum == 4)
125  found = true;
126  } else {
127  CHECK(sum == 3);
128  found = true;
129  }
130  */
131  }
132  CHECK(dtPlanes.size() == 6 || found);
133 }
134 
136  switch (place) {
137  case InPlane: return 'P';
138  case UnderPlane: return 'U';
139  case OverPlane: return 'O';
140  case NoPlace: return ' ';
141  default: return 'E';
142  }
143 }
144 
145 size_t pushOutFacetPositive(size_t facetPushOut,
146  const vector<mpz_class>& rhs,
147  const GrobLat& lat) {
148  size_t onFacet = numeric_limits<size_t>::max();
149  mpq_class leastEntry;
150 
151  for (size_t n = 0; n < lat.getNeighborCount(); ++n) {
152  for (size_t i = 0; i < lat.getYDim(); ++i) {
153  if (i == facetPushOut)
154  continue;
155  if (lat.getYMatrix()(n, i) >= rhs[i])
156  goto notOnFacet;
157  }
158 
159  if (onFacet == numeric_limits<size_t>::max() ||
160  leastEntry > lat.getYMatrix()(n, facetPushOut)) {
161  leastEntry = lat.getYMatrix()(n, facetPushOut);
162  onFacet = n;
163  }
164 
165  notOnFacet:;
166  }
167  return onFacet;
168 }
169 
170 size_t pushOutFacetZero(const vector<mpz_class>& rhs, const GrobLat& lat) {
171  size_t onFacet = numeric_limits<size_t>::max();
172  mpq_class leastEntry;
173 
174  for (size_t n = 0; n < lat.getNeighborCount(); ++n) {
175  for (size_t i = 1; i < lat.getYDim(); ++i)
176  if (-lat.getYMatrix()(n, i) >= rhs[i])
177  goto notOnFacet;
178 
179  if (onFacet == numeric_limits<size_t>::max() ||
180  leastEntry > -lat.getYMatrix()(n, 0)) {
181  leastEntry = -lat.getYMatrix()(n, 0);
182  onFacet = n;
183  }
184 
185  notOnFacet:;
186  }
187  return onFacet;
188 }
189 
190 void computeRhs(vector<mpz_class>& rhs, const vector<Neighbor> points) {
191  ASSERT(!points.empty());
192  const GrobLat& lat = points[0].getGrobLat();
193  rhs.resize(lat.getYDim());
194  for (size_t var = 0; var < lat.getYDim(); ++var) {
195  rhs[var] = points[0].getY(var);
196  for (size_t p = 1; p < points.size(); ++p)
197  if (rhs[var] < points[p].getY(var))
198  rhs[var] = points[p].getY(var);
199  }
200 }
201 
202 void Mlfb::reset(size_t offset, const vector<Neighbor>& points) {
203  ASSERT(!points.empty());
204  _points = points;
205  _offset = offset;
206 
207  const GrobLat& lat = points[0].getGrobLat();
208 
209  computeRhs(_rhs, points);
210 
211  // order to have maxima along diagonal if possible.
212  if (getPointCount() == lat.getYDim()) {
213  for (size_t i = 0; i < lat.getYDim(); ++i)
214  for (size_t p = 0; p < getPointCount(); ++p)
215  if (getPoint(p).getY(i) == getRhs()[i])
216  swap(_points[i], _points[p]);
217  }
218 
219  // Compute MLFB index.
220  if (getPointCount() - 1 == lat.getHDim())
221  {
222  Matrix mat(getPointCount() - 1, lat.getHDim());
223  for (size_t point = 1; point < getPointCount(); ++point)
224  for (size_t var = 0; var < lat.getHDim(); ++var)
225  mat(point - 1, var) = getPoint(point).getH(var);
226  index = determinant(mat);
227  }
228 
229  if (getPointCount() == 4) {
230  Matrix mat(4, lat.getHDim());
231  for (size_t point = 0; point < getPointCount(); ++point)
232  for (size_t var = 0; var < lat.getHDim(); ++var)
233  mat(point, var) = getPoint(point).getH(var);
235  } else
236  _isParallelogram = false;
237 }
238 
239 void computeMlfbs(vector<Mlfb>& mlfbs, const GrobLat& lat) {
240  BigIdeal initialIdeal;
241  lat.getInitialIdeal(initialIdeal);
242 
243  BigTermRecorder recorder;
244  SliceParams params;
245  SliceFacade facade(params, initialIdeal, recorder);
246  facade.computeIrreducibleDecomposition(true);
247  auto_ptr<BigIdeal> rhsesOwner = recorder.releaseIdeal();
248  BigIdeal& rhses = *rhsesOwner;
249  ASSERT(recorder.empty());
250 
251  mlfbs.clear();
252  mlfbs.resize(rhses.getGeneratorCount());
253 
254  vector<Neighbor> points;
255  for (size_t i = 0; i < mlfbs.size(); ++i) {
256  Mlfb& mlfb = mlfbs[i];
257  points.clear();
258 
259  points.push_back(Neighbor(lat));
260  for (size_t gen = 0; gen < initialIdeal.getGeneratorCount(); ++gen) {
261  for (size_t var = 0; var < initialIdeal.getVarCount(); ++var)
262  if (initialIdeal[gen][var] > rhses[i][var])
263  goto skipIt;
264  points.push_back(Neighbor(lat, gen));
265  skipIt:;
266  }
267 
268  mlfb.reset(i, points);
269  CHECK(rhses[i] == mlfb.getRhs());
270  }
271 
272  Matrix nullSpaceBasis;
273  nullSpace(nullSpaceBasis, lat.getMatrix());
274  transpose(nullSpaceBasis, nullSpaceBasis);
275  // the basis is the rows of NullSpaceBasis at this point.
276 
277  for (size_t m = 0; m < mlfbs.size(); ++m) {
278  Mlfb& mlfb = mlfbs[m];
279 
280  if (mlfb.getPointCount() != lat.getYDim())
281  continue;
282 
283  // Compute minInitialFacet.
284  mlfb.minInitialFacet = 0;
285  mpq_class minInitial = 0;
286  for (size_t i = 0; i < mlfb.getPointCount(); ++i) {
287  mpq_class initial = mlfb.getPoint(i).getY(0);
288  if (minInitial > initial) {
289  minInitial = initial;
290  mlfb.minInitialFacet = i;
291  }
292  }
293 
294  // Compute dot degree.
295  if (nullSpaceBasis.getRowCount() == 1 &&
296  lat.getYDim() == nullSpaceBasis.getColCount()) {
297  mlfb.dotDegree = 0;
298  for (size_t r = 0; r < nullSpaceBasis.getRowCount(); ++r)
299  for (size_t c = 0; c < nullSpaceBasis.getColCount(); ++c)
300  mlfb.dotDegree += nullSpaceBasis(r, c) * mlfb.getRhs()[c];
301  }
302 
303  // Compute Scarf edges.
304  mlfb.edges.resize(lat.getYDim());
305  mlfb.edgeHitsFacet.resize(lat.getYDim());
306  for (size_t facetPushIn = 0; facetPushIn < lat.getYDim(); ++facetPushIn) {
307  mpq_class secondLargest;
308  size_t facetPushOut = numeric_limits<size_t>::max();
309 
310  for (size_t neigh = 0; neigh < lat.getYDim(); ++neigh) {
311  mpq_class entry = 0; // neigh == 0 represents zero.
312  if (neigh > 0)
313  entry = mlfb.getPoint(neigh).getY(facetPushIn);
314 
315  if (neigh == facetPushIn) {
316  if (entry != mlfb.getRhs()[facetPushIn])
317  goto skipBecauseNotGeneric;
318  } else {
319  if (entry == secondLargest &&
320  facetPushOut != numeric_limits<size_t>::max())
321  goto skipBecauseNotGeneric;
322 
323  if (entry > secondLargest ||
324  facetPushOut == numeric_limits<size_t>::max()) {
325  secondLargest = entry;
326  facetPushOut = neigh;
327  }
328  }
329  }
330 
331  // ----------------------------------------------
332  // ** Case 1: facetPushIn > 0 and facetPushOut > 0
333  //
334  // We push in facetPushIn (discarding the non-zero neighbor
335  // previously on that facet) and hit a non-zero neighbor
336  // that is already on the MLFB. That neighbor now instead
337  // lies on facetPushIn and we push out facetPushOut in the
338  // straight forward way until it hits what will be the new
339  // neighbor on facetPushOut.
340  //
341  // ----------------------------------------------
342  // ** Case 2: facetPushIn > 0 and facetPushOut == 0
343  //
344  // We push in facetPushIn (discarding the non-zero neighbor
345  // previously on that facet) and hit zero. Zero now instead
346  // lies on facetPushIn and we push out facetPushOut. It will
347  // be pushing into the area on the opposite side from the
348  // half-set of neighbors that we are looking at, so to find
349  // the replacement neighbor to put on facetPushOut
350  // (i.e. facet zero) we need to consider the negative of the
351  // neighbors we have. When that neighbor -v has been found,
352  // we need to translate the whole body by +v so that zero
353  // will once again lie on facet zero.
354  //
355  // ----------------------------------------------
356  // ** case 3: facetPushIn == 0 and facetPushOut > 0
357  //
358  // We push in facetPushIn (discarding the zero previously on
359  // that facet) and hit a non-zero neighbor v on
360  // facetPushOut. Then v lies on facetPushIn (i.e. facet
361  // zero), so for the MLFB to have zero on facet 0 we need to
362  // translate it by -v. We then relax facetPushOut to find a
363  // replacement neighbor as in Case 1.
364 
365  ASSERT(facetPushIn == 0 || secondLargest >= 0);
366  // In all cases the neighbor we hit moves to facetPushIn.
367  vector<mpz_class> rhs(mlfb.getRhs());
368 
369  rhs[facetPushIn] = secondLargest;
370 
371  if (facetPushIn == 0) {
372  // Case 3: the neighbor hit moves to facet 0 so translate
373  // the body to make that neighbor zero.
374  for (size_t i = 0; i < lat.getYDim(); ++i)
375  rhs[i] -= mlfb.getPoint(facetPushOut).getY(i);
376  }
377 
378  if (facetPushOut > 0) {
379  // Case 1 or 3: push out in the usual way.
380  size_t newNeighbor = pushOutFacetPositive(facetPushOut, rhs, lat);
381  if (newNeighbor == numeric_limits<size_t>::max())
382  goto skipBecauseNotGeneric;
383  rhs[facetPushOut] = lat.getYMatrix()(newNeighbor, facetPushOut);
384  }
385 
386  if (facetPushOut == 0) {
387  // Case 2: push out into negative neighbors
388  size_t newNeighbor = pushOutFacetZero(rhs, lat);
389  if (newNeighbor == numeric_limits<size_t>::max())
390  goto skipBecauseNotGeneric;
391  for (size_t i = 0; i < lat.getYDim(); ++i)
392  rhs[i] += lat.getYMatrix()(newNeighbor, i);
393  rhs[0] = 0;
394  }
395 
396  // Find the MLFB with the right hand side that we have
397  // computed.
398  for (size_t mi = 0; mi < mlfbs.size(); ++mi) {
399  if (mlfbs[mi].getRhs() == rhs) {
400  mlfb.edges[facetPushIn] = &(mlfbs[mi]);
401  mlfb.edgeHitsFacet[facetPushIn] = facetPushOut;
402  goto foundMatch;
403  }
404  }
405  goto skipBecauseNotGeneric;
406  foundMatch:;
407  }
408  continue;
409  skipBecauseNotGeneric:
410  mlfb.edges.clear();
411  mlfb.edgeHitsFacet.clear();
412  }
413 }
414 
416  size_t pushIn;
417  for (pushIn = 0;; ++pushIn) {
418  ASSERT(pushIn < 4);
419  if (pushIn != pos.fixFacet1 &&
420  pushIn != pos.fixFacet2 &&
421  pushIn != pos.comingFromFacet)
422  break;
423  }
424 
425  size_t hits = pos.mlfb->getHitsFacet(pushIn);
426  ASSERT(hits != pushIn);
427 
428  SeqPos next = pos;
429  next.mlfb = pos.mlfb->getEdge(pushIn);
430  next.comingFromFacet = hits;
431 
432  if (pos.fixFacet1 == hits)
433  next.fixFacet1 = pushIn;
434  else if (pos.fixFacet2 == hits)
435  next.fixFacet2 = pushIn;
436 
437  next.order();
438  return next;
439 }
440 
442  return nextInSeq(pos.getReverse()).getReverse();
443 }
444 
445 size_t computeFlatIntervalCount(const vector<SeqPos>& flatSeq) {
446  if (flatSeq.empty())
447  return 0u;
448 
449  const Mlfb& leftFlat = *(flatSeq.front().mlfb);
450  size_t sumFacet = leftFlat.getMinInitialFacet();
451 
452  size_t aFacet = 4;
453  for (size_t j = 0; j < 4; ++j) {
454  if (j != 0 && j != sumFacet) {
455  aFacet = j;
456  break;
457  }
458  }
459  CHECK(aFacet != 4);
460 
461  size_t subSeqCount = 1;
462  for (size_t i = 1; i < flatSeq.size() - 1; ++i) {
463  const Mlfb& prev = *(flatSeq[i - 1].mlfb);
464  const Mlfb& flat = *(flatSeq[i].mlfb);
465  if (flat.getHitsFacet(aFacet) != prev.getHitsFacet(aFacet))
466  ++subSeqCount;
467  }
468  return subSeqCount;
469 }
470 
471 void computeFlatSeq(vector<SeqPos>& seq,
472  const vector<Mlfb>& mlfbs,
473  const Plane& plane) {
474  // ** compute left most flat
475  const Mlfb* leftFlat = 0;
476  for (size_t m = 0; m < mlfbs.size(); ++m) {
477  if (!plane.isFlat(mlfbs[m]))
478  continue;
479  const Mlfb* toLeft = mlfbs[m].getEdge(0);
480  if (!plane.isFlat(*toLeft)) {
481  CHECK(leftFlat == 0 || leftFlat == toLeft); // left flat unique
482  leftFlat = &(mlfbs[m]);
483  }
484  }
485 
486  seq.clear();
487  if (leftFlat == 0) {
488  ASSERT(!plane.hasFlat());
489  return;
490  }
491 
492  // ** go right as long as there is a flat there
493  SeqPos pos;
494  pos.mlfb = leftFlat;
495  while (plane.isFlat(*pos.mlfb)) {
496  ASSERT(seq.empty() || seq.back().mlfb != pos.mlfb);
497  seq.push_back(pos);
498  bool moved = false;
499  for (size_t facet = 1; facet < 4; ++facet) {
500  if (pos.mlfb->getEdge(facet)->getEdge(0) == pos.mlfb) {
501  pos.mlfb = pos.mlfb->getEdge(facet);
502  moved = true;
503  break;
504  }
505  }
506  if (!moved)
507  break;
508  }
509 }
510 
511 void computePlanes(vector<Plane>& planes,
512  const GrobLat& lat,
513  vector<Mlfb>& mlfbs) {
514  const size_t neighborCount = lat.getNeighborCount();
515  for (size_t gen1 = 0; gen1 < neighborCount; ++gen1) {
516  for (size_t gen2 = gen1 + 1; gen2 < neighborCount; ++gen2) {
517  Neighbor a = lat.getNeighbor(gen1);
518  Neighbor b = lat.getNeighbor(gen2);
519  Neighbor sum = lat.getSum(a, b);
520 
521  if (!sum.isValid())
522  continue;
523  if (!lat.isPointFreeBody(a, sum))
524  continue;
525  if (!lat.isPointFreeBody(b, sum))
526  continue;
527  if (lat.isPointFreeBody(a, b, sum))
528  continue; // only looking for non-flat double triangles right now
529 
530  Matrix rowAB(2, lat.getHDim());
531  copyRow(rowAB, 0, lat.getHMatrix(), gen1);
532  copyRow(rowAB, 1, lat.getHMatrix(), gen2);
533 
534  planes.push_back(Plane(a, b, sum, mlfbs, lat));
535  Plane& plane = planes.back();
536  plane.rowAB = rowAB;
537  nullSpace(plane.nullSpaceBasis, rowAB);
538 
539  Matrix prod;
540  product(prod, lat.getHMatrix(), plane.nullSpaceBasis);
541  plane.neighborPlace.resize(lat.getNeighborCount());
542  for (size_t gen = 0; gen < lat.getNeighborCount(); ++gen) {
543  mpq_class& value = prod(gen, 0);
544  NeighborPlace place = InPlane;
545  if (value < 0)
546  place = UnderPlane;
547  else if (value > 0)
548  place = OverPlane;
549  plane.neighborPlace[gen] = place;
550  }
551 
552  transpose(plane.nullSpaceBasis);
553  }
554  }
555 
556  for (size_t p = 0; p < planes.size(); ++p) {
557  Plane& plane = planes[p];
558  for (size_t i = 0; i < mlfbs.size(); ++i)
559  plane.typeCounts[plane.getType(mlfbs[i])] += 1;
560 
561  computeFlatSeq(plane.flatSeq, mlfbs, plane);
562  computePivots(plane.pivots, mlfbs, plane, plane.flatSeq);
564  }
565 }
566 
568  const vector<Mlfb>& mlfbs, const GrobLat& lat):
569  _a(a), _b(b), _sum(sum) {
570 
571  // find MLFBs containing {0,a,a+b}
572  for (size_t m = 0; m < mlfbs.size(); ++m)
573  if (mlfbs[m].hasPoint(a) && mlfbs[m].hasPoint(sum))
574  _aSideMlfbs.push_back(&(mlfbs[m]));
575 
576  // find MLFBs containing {0,b,a+b}
577  for (size_t m = 0; m < mlfbs.size(); ++m)
578  if (mlfbs[m].hasPoint(b) && mlfbs[m].hasPoint(sum))
579  _bSideMlfbs.push_back(&(mlfbs[m]));
580 
581  // find additional neighbors in the body defined by {0,a,b,a+b}
582  vector<Neighbor> points;
583  points.push_back(Neighbor(lat)); // add zero;
584  points.push_back(a);
585  points.push_back(b);
586  points.push_back(sum);
587  vector<mpz_class> rhs;
588  computeRhs(rhs, points);
589  _boundary.push_back(Neighbor(lat)); // add zero
590  for (size_t n = 0; n < lat.getNeighborCount(); ++n) {
591  Neighbor neighbor = lat.getNeighbor(n);
592  bool boundary = true;
593  bool interior = true;
594  for (size_t i = 0; i < rhs.size(); ++i) {
595  if (neighbor.getY(i) == rhs[i])
596  interior = false;
597  else if (neighbor.getY(i) > rhs[i]) {
598  interior = false;
599  boundary = false;
600  break;
601  }
602  }
603  if (interior)
604  _interior.push_back(neighbor);
605  else if (boundary)
606  _boundary.push_back(neighbor);
607  }
608 }
609 
610 
611 void check0Graph(const vector<Mlfb>& mlfbs) {
612  vector<bool> ok(mlfbs.size());
613  bool sawFlat = false;
614  for (size_t i =0 ; i < mlfbs.size(); ++i) {
615  ok[i] = (mlfbs[i].index == 0);
616  if (ok[i])
617  sawFlat = true;
618  }
619  if (!sawFlat)
620  return;
621 
622  while (true) {
623  bool done = true;
624  for (size_t i = 0; i < mlfbs.size(); ++i) {
625  if (!ok[i]) {
626  size_t to = mlfbs[i].getEdge(0)->getOffset();
627  if (ok[to]) {
628  done = false;
629  ok[i] = true;
630  }
631  }
632  }
633  if (done)
634  break;
635  }
636 
637  for (size_t i = 0; i < mlfbs.size(); ++i) {
638  CHECK(ok[i]);
639  }
640 }
641 
642 void checkMlfbs(const vector<Mlfb>& mlfbs, const GrobLat& lat) {
643  CHECK(mlfbs.size() == lat.getNeighborCount() - 1);
644  for (size_t m = 0; m < mlfbs.size(); ++m) {
645  CHECK(mlfbs[m].isParallelogram() == (mlfbs[m].index == 0));
646  }
647 }
648 
649 void checkDoubleTrianglePlanes(const vector<Plane>& planes,
650  const GrobLat& lat,
651  const vector<Mlfb>& mlfbs) {
652  // Check no two planes are parallel. Otherwise there would a plane
653  // with two non-flat double triangles in it.
654  for (size_t p1 = 0; p1 < planes.size(); ++p1) {
655  for (size_t p2 = 0; p2 < p1; ++p2) {
656  CHECK(!hasSameRowSpace(planes[p1].rowAB, planes[p2].rowAB));
657  }
658  }
659 
660  // Check that all parallelograms lie in a plane. Otherwise there
661  // would be a plane defined by a flat that does not have a double
662  // triangle in it.
663  for (size_t m = 0; m < mlfbs.size(); ++m) {
664  if (mlfbs[m].isParallelogram()) {
665  bool liesInSomePlane = false;
666  for (size_t p = 0; p < planes.size(); ++p) {
667  if (planes[p].isFlat(mlfbs[m])) {
668  liesInSomePlane = true;
669  break;
670  }
671  }
672  CHECK(liesInSomePlane);
673  }
674  }
675 
676 
677 
678 
679  bool multipleIntervals = false;
680  bool anyFlat = false;
681  bool flatWith4Pivots = false;
682  for (size_t p = 0; p < planes.size(); ++p) {
683  if (planes[p].flatIntervalCount > 1)
684  multipleIntervals = true;
685  if (planes[p].hasFlat()) {
686  anyFlat = true;
687  if (planes[p].pivots.size() == 4)
688  flatWith4Pivots = true;
689  }
690  }
691  if (multipleIntervals) {
692  ASSERT(anyFlat);
693  //CHECK(flatWith4Pivots);
694  CHECK(planes.size() == 1);
695  }
696 
697  if (planes.size() == 6) {
698  CHECK(!anyFlat);
699  CHECK(planes.size() == 6);
700  for (size_t p = 0; p < planes.size(); ++p) {
701  CHECK(planes[p].pivots.size() == 4);
702  }
703  CHECK(lat.getNeighborCount() == 7);
704  CHECK(mlfbs.size() == 6);
705  }
706 
707  if (anyFlat) {
708  //check0Graph(mlfbs);
709  //CHECK(flatWith4Pivots);
710  CHECK(planes.size() < 6);
711  }
712 }
713 
714 void checkPlane(const Plane& plane, const vector<Mlfb>& mlfbs) {
715  for (size_t i = 0; i < mlfbs.size(); ++i) {
716  if (plane.isPivot(mlfbs[i])) {
717  CHECK(mlfbs[i].index == -1 || mlfbs[i].index == 1);
718  } else if (plane.isFlat(mlfbs[i])) {
719  CHECK(mlfbs[i].index == 0);
720  }
721  }
722 }
723 
726 size_t pivotToFlatFacet(const Mlfb& pivot, const Plane& plane) {
727  size_t facet = 4;
728  for (size_t push = 0; push < 4; ++push) {
729  if (plane.isFlat(*pivot.getEdge(push))) {
730  CHECK(facet == 4); // adjacent to no more than one flat
731  facet = push;
732  }
733  }
734  CHECK(facet != 4); // adjacent to at least one flat
735  return facet;
736 }
737 
738 bool disjointSeqs(const vector<SeqPos>& a, const vector<SeqPos>& b) {
739  for (size_t i = 0; i < a.size(); ++i)
740  for (size_t j = 0; j < b.size(); ++j)
741  if (a[i].mlfb == b[j].mlfb)
742  return false;
743  return true;
744 }
745 
746 void computePivots(vector<const Mlfb*>& pivots,
747  const vector<Mlfb>& mlfbs,
748  const Plane& plane,
749  const vector<SeqPos>& flatSeq) {
750  pivots.clear();
751  for (size_t m = 0; m < mlfbs.size(); ++m)
752  if (plane.isPivot(mlfbs[m]))
753  pivots.push_back(&(mlfbs[m]));
754  if (pivots.size() != 4 || flatSeq.empty())
755  return; // no idea about proper order in this case
756 
757  pivots.clear();
758  // use flat sequence to impose correct order
759  size_t sumFacet = flatSeq.front().mlfb->getMinInitialFacet();
760  pivots.push_back(flatSeq.front().mlfb->getEdge(0));
761  pivots.push_back(flatSeq.front().mlfb->getEdge(sumFacet));
762 
763  sumFacet = flatSeq.back().mlfb->getMinInitialFacet();
764  for (size_t i = 0; i < 4; ++i)
765  if (i != 0 && i != sumFacet)
766  pivots.push_back(flatSeq.back().mlfb->getEdge(i));
767 }
768 
769 void computeSeqs(vector<vector<SeqPos> >& left,
770  vector<vector<SeqPos> >& right,
771  const vector<Mlfb>& mlfbs,
772  const Plane& plane) {
773  vector<vector<SeqPos> > seqs;
774 
775  for (size_t m = 0; m < mlfbs.size(); ++m) {
776  if (!plane.isPivot(mlfbs[m]))
777  continue;
778  const Mlfb& p = mlfbs[m];
779  for (size_t i = 0; i < 4; ++i) {
780  const Mlfb& e = *(p.getEdge(i));
781  if (plane.isPivot(e) || plane.isFlat(e))
782  continue;
783 
784  bool doneBefore = false;
785  for (size_t s = 0; s < seqs.size(); ++s) {
786  if (*(seqs[s][seqs[s].size() - 1].mlfb) == p &&
787  *(seqs[s][seqs[s].size() - 2].mlfb) == e) {
788  doneBefore = true;
789  break;
790  }
791  }
792  if (doneBefore)
793  continue;
794 
795  size_t prevFacet;
796  for (prevFacet = 0; prevFacet < 4; ++prevFacet)
797  if (*(e.getEdge(prevFacet)) == p)
798  break;
799  ASSERT(prevFacet < 4);
800 
801  NeighborPlace place = plane.getPlace(e.getPoint(prevFacet));
802  size_t nextFacet;
803  for (nextFacet = 0; nextFacet < 4; ++nextFacet) {
804  if (nextFacet != prevFacet &&
805  place == plane.getPlace(e.getPoint(nextFacet)))
806  break;
807  }
808  SeqPos pos = prevInSeq(SeqPos(&e, nextFacet, prevFacet));
809 
810  seqs.resize(seqs.size() + 1);
811  vector<SeqPos>& seq = seqs.back();
812  seq.push_back(pos);
813  do {
814  pos = nextInSeq(pos);
815  seq.push_back(pos);
816  } while (!(plane.isPivot(*pos.mlfb)));
817  }
818  }
819 
820  CHECK(!seqs.empty());
821  ASSERT(!seqs.front().empty());
822 
823  // now we've got all the sequences. Time to look at the sides.
824  stack<const Mlfb*> pending;
825 
826  // put a side pivot on the left arbitrarily and explore the
827  // connected component
828  vector<bool> leftSeen(mlfbs.size());
829  pending.push(seqs.front().front().mlfb);
830  while (!pending.empty()) {
831  const Mlfb& m = *pending.top();
832  pending.pop();
833  if (leftSeen[m.getOffset()])
834  continue;
835  leftSeen[m.getOffset()] = true;
836  for (size_t s = 0; s < seqs.size(); ++s) {
837  if (*(seqs[s].front().mlfb) == m)
838  pending.push(seqs[s].back().mlfb);
839  if (*(seqs[s].back().mlfb) == m)
840  pending.push(seqs[s].front().mlfb);
841  }
842  }
843 
844  // find a non-left side pivot
845  size_t m;
846  for (m = 0; m < mlfbs.size(); ++m)
847  if (plane.isSidePivot(mlfbs[m]) && !leftSeen[m])
848  break;
849  CHECK(m < mlfbs.size());
850 
851  // put the non-left pivot on the right and explore the connected
852  // component
853  vector<bool> rightSeen(mlfbs.size());
854  pending.push(&(mlfbs[m]));
855  while (!pending.empty()) {
856  const Mlfb& pm = *pending.top();
857  pending.pop();
858  if (rightSeen[pm.getOffset()])
859  continue;
860  rightSeen[pm.getOffset()] = true;
861  for (size_t s = 0; s < seqs.size(); ++s) {
862  if (*(seqs[s].front().mlfb) == pm)
863  pending.push(seqs[s].back().mlfb);
864  if (*(seqs[s].back().mlfb) == pm)
865  pending.push(seqs[s].front().mlfb);
866  }
867  }
868 
869  left.clear();
870  right.clear();
871  for (size_t s = 0; s < seqs.size(); ++s) {
872  const size_t offset = seqs[s].front().mlfb->getOffset();
873  if (leftSeen[offset]) {
874  CHECK(!rightSeen[offset]);
875  left.push_back(seqs[s]);
876  } else if (rightSeen[offset])
877  right.push_back(seqs[s]);
878  }
879 }
880 
881 void computePivotSeqs(vector<vector<SeqPos> >& seqs,
882  const Mlfb& pivot,
883  const Plane& plane) {
884  ASSERT(plane.pivots.size() == 4);
885  ASSERT(plane.isPivot(pivot));
886  size_t flatFacet = pivotToFlatFacet(pivot, plane);
887 
888  seqs.clear();
889  for (size_t facet = 0; facet < 4; ++facet) {
890  if (facet == flatFacet)
891  continue;
892  seqs.resize(seqs.size() + 1);
893  vector<SeqPos>& seq = seqs.back();
894 
895  SeqPos pos(&pivot, facet, flatFacet);
896  seq.push_back(pos);
897  do {
898  pos = nextInSeq(pos);
899  seq.push_back(pos);
900  } while (!(plane.isPivot(*pos.mlfb)));
901  }
902 }
903 
904 void checkSeq(vector<bool>& seenOnSide,
905  const vector<SeqPos>& seq,
906  const Plane& plane) {
907  CHECK(seq.size() >= 3); // each seq must have at least one 2-2.
908  CHECK(plane.isSidePivot(*(seq.front().mlfb))); // start is a pivot
909  CHECK(plane.isSidePivot(*(seq.back().mlfb))); // end is a pivot
910  CHECK(seq.front().mlfb != seq.back().mlfb); // no loops
911 
912  for (size_t m = 1; m < seq.size() - 1 ; ++m) {
913  const Mlfb* prev = seq[m - 1].mlfb;
914  const Mlfb* current = seq[m].mlfb;
915  const Mlfb* next = seq[m + 1].mlfb;
916  const SeqPos& pos = seq[m];
917 
918  // ** Check on 2-2 appears twice and update seenOnSide
919  CHECK(!seenOnSide[current->getOffset()]);
920  seenOnSide[current->getOffset()] = true;
921 
922  // ** middle elements are 2-2s.
923  CHECK(plane.is22(*current));
924 
925  // ** SeqPos fields agrees with sequence order
926  size_t prevFacet = pos.getBackFacet();
927  size_t nextFacet = pos.getForwardFacet();
928  CHECK(current->getEdge(prevFacet) == prev);
929  CHECK(current->getEdge(nextFacet) == next);
930 
931  // ** in-coming and out-going facets are on same plane
932  CHECK(plane.getPlace(current->getPoint(prevFacet)) ==
933  plane.getPlace(current->getPoint(nextFacet)));
934  }
935 }
936 
937 void checkSide(vector<bool>& pivotOnSide,
938  const vector<vector<SeqPos> >& side,
939  const Plane& plane,
940  const vector<Mlfb>& mlfbs) {
941  CHECK(side.size() == 2 || side.size() == 3);
942 
943  vector<bool> seenOnSide(mlfbs.size());
944  for (size_t s = 0; s < side.size(); ++s){
945  // check sequence local properties and update seen
946  checkSeq(seenOnSide, side[s], plane);
947 
948  // compute onSide
949  pivotOnSide[side[s].front().mlfb->getOffset()] = true;
950  pivotOnSide[side[s].back().mlfb->getOffset()] = true;
951  }
952 
953  /* // must have seen all 2-2s on this side.
954  for (size_t m = 0; m < mlfbs.size(); ++m)
955  if (plane.is22(mlfbs[m]))
956  CHECK(seenOnSide[m]);*/
957 
958  // 2,3 or 4 sidepivots
959  size_t sidePivots = 0;
960  for (size_t m = 0; m < mlfbs.size(); ++m)
961  if (pivotOnSide[m])
962  ++sidePivots;
963  CHECK(sidePivots == 2 || sidePivots == 3 || sidePivots == 4);
964 }
965 
966 void checkSeqs(const vector<vector<SeqPos> >& left,
967  const vector<vector<SeqPos> >& right,
968  const Plane& plane,
969  const vector<Mlfb>& mlfbs) {
970  vector<bool> isLeftPivot(mlfbs.size());
971  checkSide(isLeftPivot, left, plane, mlfbs);
972 
973  vector<bool> isRightPivot(mlfbs.size());
974  checkSide(isRightPivot, right, plane, mlfbs);
975 
976  // all side pivots are on one and only one side
977  for (size_t m = 0; m < mlfbs.size(); ++m) {
978  if (plane.isSidePivot(mlfbs[m]))
979  CHECK((isLeftPivot[m] + isRightPivot[m]) == 1);
980  else
981  CHECK((isLeftPivot[m] + isRightPivot[m]) == 0);
982  }
983 }
984 
985 void checkMiddle(const Plane& plane,
986  const vector<Mlfb>& mlfbs) {
987  // ** check that the subgraph of pivots and flat is connected.
988  vector<bool> seen(mlfbs.size());
989  stack<const Mlfb*> pending;
990 
991  // find a pivot or flat
992  size_t m;
993  for (m = 0; m < mlfbs.size(); ++m)
994  if (plane.isFlat(mlfbs[m]) || plane.isPivot(mlfbs[m]))
995  break;
996  ASSERT(m < mlfbs.size());
997 
998  // explore the graph of pivots and flats that is connected to the
999  // one we found.
1000  pending.push(&(mlfbs[m]));
1001  while (!pending.empty()) {
1002  const Mlfb& mlfb = *(pending.top());
1003  pending.pop();
1004  if (seen[mlfb.getOffset()])
1005  continue;
1006  seen[mlfb.getOffset()] = true;
1007  for (size_t i = 0; i < 4; ++i)
1008  pending.push(mlfb.getEdge(i));
1009  }
1010 
1011  // check that we have reached all pivots and flats
1012  for (m = 0; m < mlfbs.size(); ++m)
1013  if (plane.isFlat(mlfbs[m]) || plane.isPivot(mlfbs[m]))
1014  CHECK(seen[m]);
1015 }
1016 
1017 void checkGraphOnPlane(const Plane& plane,
1018  const vector<Mlfb>& mlfbs) {
1019  // no flat is adjacent to a 2-2
1020  for (size_t m = 0; m < mlfbs.size(); ++m) {
1021  const Mlfb& mlfb = mlfbs[m];
1022  if (plane.isFlat(mlfb))
1023  for (size_t i = 0; i < 4; ++i)
1024  CHECK(!plane.is22(*(mlfb.getEdge(i))));
1025  }
1026 
1027  // parallelograms can't be flats and non-flat parallelograms are not
1028  // adjacent to a flat
1029  for (size_t m = 0; m < mlfbs.size(); ++m) {
1030  const Mlfb& mlfb = mlfbs[m];
1031  if (mlfb.isParallelogram()) {
1032  CHECK(!plane.isPivot(mlfb));
1033  if (!plane.isFlat(mlfb)) {
1034  for (size_t i = 0; i < 4; ++i) {
1035  const Mlfb& adj = *(mlfb.getEdge(i));
1036  CHECK(!plane.isFlat(adj));
1037  }
1038  }
1039  }
1040  }
1041 }
1042 
1043 void checkDoubleTriangle(const Plane& plane,
1044  const vector<Mlfb>& mlfbs) {
1045  size_t aSideCount = plane.tri.getASideMlfbs().size();
1046  size_t bSideCount = plane.tri.getBSideMlfbs().size();
1047  CHECK(aSideCount == 1 || aSideCount == 2);
1048  CHECK(bSideCount == 1 || bSideCount == 2);
1049 
1050  for (size_t m = 0; m < aSideCount; ++m) {
1051  const Mlfb& mlfb = *plane.tri.getASideMlfbs()[m];
1052  CHECK(plane.isFlat(mlfb) || plane.isPivot(mlfb));
1053  }
1054  for (size_t m = 0; m < bSideCount; ++m) {
1055  const Mlfb& mlfb = *plane.tri.getBSideMlfbs()[m];
1056  CHECK(plane.isFlat(mlfb) || plane.isPivot(mlfb));
1057  }
1058 }
1059 
1060 void checkGraph(const vector<Mlfb>& mlfbs) {
1061  // All non-parallelograms have out-degree 2. Parallelograms have
1062  // out-degree equal to 4 minus the number of other adjacent
1063  // parallelograms.
1064  for (size_t m = 0; m < mlfbs.size(); ++m) {
1065  const Mlfb& mlfb = mlfbs[m];
1066  set<size_t> adjParas;
1067  set<size_t> adjNodes;
1068  for (size_t i = 0; i < 4; ++i) {
1069  const Mlfb& adj = *(mlfb.getEdge(i));
1070  adjNodes.insert(adj.getOffset());
1071  if (adj.isParallelogram())
1072  adjParas.insert(adj.getOffset());
1073  }
1074  const size_t outDegree = adjNodes.size();
1075  if (!mlfb.isParallelogram())
1076  CHECK(outDegree == 4);
1077  else
1078  CHECK(outDegree == 4 - adjParas.size());
1079  }
1080 
1081  // if there is an edge (a,b) then there is also an edge (b,a).
1082  for (size_t m = 0; m < mlfbs.size(); ++m) {
1083  const Mlfb& mlfb = mlfbs[m];
1084  for (size_t i = 0; i < 4; ++i) {
1085  size_t hitsFacet = mlfb.getHitsFacet(i);
1086  const Mlfb& adj = *(mlfb.getEdge(i));
1087  CHECK(mlfb == *(adj.getEdge(hitsFacet)));
1088  }
1089  }
1090 }
1091 
1092 void checkPivotSeqs(vector<vector<SeqPos> >& pivotSeqs,
1093  const Plane& plane,
1094  const vector<Mlfb>& mlfbs,
1095  const vector<SeqPos>& flatSeq) {
1096  CHECK(pivotSeqs.size() == 3);
1097  CHECK(pivotSeqs[0].size() >= 2);
1098  const Mlfb* pivot1 = pivotSeqs[0].front().mlfb;
1099  const Mlfb* pivot2 = pivotSeqs[0].back().mlfb;
1100 
1101  CHECK(plane.isPivot(*pivot1));
1102  CHECK(plane.isPivot(*pivot2));
1103 
1104 
1105  bool foundPlace = false;
1106  NeighborPlace place;
1107  for (size_t i = 0; i < 3; ++i) {
1108  CHECK(pivotSeqs[i].size() >= 2);
1109  // ** all sequences on same side between same pivots
1110  CHECK((pivotSeqs[i].front().mlfb == pivot1 &&
1111  pivotSeqs[i].back().mlfb == pivot2) ||
1112  (pivotSeqs[i].front().mlfb == pivot2 &&
1113  pivotSeqs[i].back().mlfb == pivot1));
1114 
1115  for (size_t j = 1; j < pivotSeqs[i].size() - 1; ++j) {
1116  const Mlfb* prev = pivotSeqs[i][j - 1].mlfb;
1117  const Mlfb* current = pivotSeqs[i][j].mlfb;
1118  const Mlfb* next = pivotSeqs[i][j + 1].mlfb;
1119 
1120  // ** middle mlfbs are 2-2's
1121  CHECK(plane.getType(*current) == 2);
1122 
1123  // ** SeqPos agrees with sequence order
1124  const SeqPos& pos = pivotSeqs[i][j];
1125  size_t prevFacet = pos.getBackFacet();
1126  size_t nextFacet = pos.getForwardFacet();
1127  CHECK(current->getEdge(prevFacet) == prev);
1128  CHECK(current->getEdge(nextFacet) == next);
1129 
1130  // ** in-coming and out-going facets are on same plane
1131  CHECK(plane.getPlace(current->getPoint(prevFacet)) ==
1132  plane.getPlace(current->getPoint(nextFacet)));
1133 
1134  // ** active facets are the same for all sequences on same side
1135  if (!foundPlace) {
1136  place = plane.getPlace(current->getPoint(prevFacet));
1137  }
1138  CHECK(place == plane.getPlace(current->getPoint(prevFacet)));
1139  }
1140  }
1141 
1142  // ** Check that the sequences are a partition of the set of 2-2 mlfbs
1143  vector<bool> seen(mlfbs.size());
1144  for (size_t i = 0; i < 3; ++i) {
1145  for (size_t j = 1; j < pivotSeqs[i].size() - 1; ++j) {
1146  CHECK(!seen[pivotSeqs[i][j].mlfb->getOffset()]); // sequences must be disjoint
1147  seen[pivotSeqs[i][j].mlfb->getOffset()] = true;
1148  }
1149  }
1150  /* for (size_t i = 0; i < mlfbs.size(); ++i) {
1151  if (plane.isPivot(mlfbs[i]) || plane.isFlat(mlfbs[i]))
1152  continue;
1153  CHECK(seen[i]); // all 2-2s in some sequence
1154  }*/
1155 }
1156 
1157 void checkNonSums(const GrobLat& lat) {
1158  const vector<Neighbor>& nonSums = lat.getNonSums();
1159  CHECK(nonSums.size() == 3 || nonSums.size() == 4);
1160  if (nonSums.size() == 3) {
1161  Matrix mat(3, 3);
1162  for (size_t ns = 0; ns < 3; ++ns)
1163  for (size_t var = 0; var < 3; ++var)
1164  mat(ns, var) = nonSums[ns].getH(var);
1165  mpq_class det = determinant(mat);
1166  CHECK(det == 1 || det == -1);
1167  } else {
1168  Matrix mat(4, 3);
1169  for (size_t ns = 0; ns < 4; ++ns)
1170  for (size_t var = 0; var < 3; ++var)
1171  mat(ns, var) = nonSums[ns].getY(var);
1172  CHECK(isParallelogram(mat));
1173 
1174  return; // not checking this as it seems to not be true
1175  mpq_class areaSq = getParallelogramAreaSq(mat);
1176  CHECK(areaSq == 1);
1177  }
1178 }
1179 
1180 void checkFlatSeq(const vector<SeqPos>& flatSeq,
1181  const GrobLat& lat,
1182  const Plane& plane) {
1183  if (flatSeq.empty())
1184  return;
1185  size_t sumf = flatSeq.front().mlfb->getMinInitialFacet();
1186  CHECK(sumf != 0);
1187 
1188  size_t af = 4;
1189  for (size_t j = 0; j < 4; ++j) {
1190  if (j != 0 && j != sumf) {
1191  af = j;
1192  break;
1193  }
1194  }
1195 
1196  size_t bf = 4;
1197  for (size_t j = 0; j < 4; ++j) {
1198  if (j != 0 && j != sumf && j != af) {
1199  bf = j;
1200  break;
1201  }
1202  }
1203 
1204  for (size_t i = 0; i < flatSeq.size(); ++i) {
1205  const Mlfb& flat = *(flatSeq[i].mlfb);
1206  Neighbor sum = flat.getPoint(sumf);
1207  Neighbor a = flat.getPoint(af);
1208  Neighbor b = flat.getPoint(bf);
1209 
1210  CHECK(sumf == flat.getMinInitialFacet());
1211  CHECK(lat.getSum(a, b) == sum);
1212 
1213  // right-going edges
1214  if (i < flatSeq.size() - 1) {
1215  // not at right end
1216  CHECK(flat.getEdge(af) == flat.getEdge(bf));
1217  const Mlfb& next = *(flatSeq[i + 1].mlfb);
1218  CHECK(flat.getEdge(af) == &next);
1219  if (flat.getHitsFacet(af) == sumf) {
1220  CHECK(flat.getHitsFacet(bf) == 0);
1221  CHECK(next.hasPoint(b));
1222  CHECK(next.hasPoint(sum));
1223  CHECK(next.hasPoint(lat.getSum(sum, b)));
1224  } else {
1225  CHECK(flat.getHitsFacet(af) == 0);
1226  CHECK(flat.getHitsFacet(bf) == sumf);
1227  CHECK(next.hasPoint(a));
1228  CHECK(next.hasPoint(sum));
1229  CHECK(next.hasPoint(lat.getSum(sum, a)));
1230  }
1231  } else {
1232  // at right end
1233  CHECK(plane.isPivot(*flat.getEdge(af)));
1234  CHECK(plane.isPivot(*flat.getEdge(bf)));
1235  CHECK(flat.getEdge(af) != flat.getEdge(bf));
1236  }
1237 
1238  // left-going edges
1239  if (i > 0) {
1240  // not at left end
1241  CHECK(flat.getEdge(0) == flat.getEdge(sumf));
1242  const Mlfb& prev = *(flatSeq[i - 1].mlfb);
1243  CHECK(flat.getEdge(0) == &prev);
1244  if (flat.getHitsFacet(0) == af) {
1245  CHECK(flat.getHitsFacet(sumf) == bf);
1246  } else {
1247  CHECK(flat.getHitsFacet(0) == bf);
1248  CHECK(flat.getHitsFacet(sumf) == af);
1249  }
1250  } else {
1251  // at left end
1252  CHECK(plane.isPivot(*flat.getEdge(0)));
1253  CHECK(plane.isPivot(*flat.getEdge(sumf)));
1254  CHECK(flat.getEdge(0) != flat.getEdge(sumf));
1255  }
1256  }
1257 }
1258 
1259 void checkPlaneTri(const GrobLat& lat,
1260  const vector<Mlfb>& mlfbs,
1261  const vector<const Mlfb*>& pivots,
1262  const Plane& plane) {
1263  const Tri& tri = plane.tri;
1264  Neighbor a = tri.getA();
1265  Neighbor b = tri.getB();
1266  Neighbor sum = tri.getSum();
1267 
1268  // ** tri is not a flat
1269  for (size_t i = 0; i < mlfbs.size(); ++i) {
1270  if (plane.isFlat(mlfbs[i])) {
1271  CHECK(!mlfbs[i].hasPoint(a) ||
1272  !mlfbs[i].hasPoint(b) ||
1273  !mlfbs[i].hasPoint(sum));
1274  }
1275  }
1276 
1277  // ** find unique non-flat MLFB with {0,a,a+b}
1278  const Mlfb* mlfbA = 0;
1279  for (size_t i = 0; i < mlfbs.size(); ++i) {
1280  if (!plane.isFlat(mlfbs[i]) &&
1281  mlfbs[i].hasPoint(a) &&
1282  mlfbs[i].hasPoint(sum)) {
1283  CHECK(mlfbA == 0);
1284  mlfbA = &(mlfbs[i]);
1285  }
1286  }
1287  CHECK(mlfbA != 0);
1288 
1289  // ** find unique non-flat MLFB with {0,b,a+b}
1290  const Mlfb* mlfbB = 0;
1291  for (size_t i = 0; i < mlfbs.size(); ++i) {
1292  if (!plane.isFlat(mlfbs[i]) &&
1293  mlfbs[i].hasPoint(b) &&
1294  mlfbs[i].hasPoint(sum)) {
1295  CHECK(mlfbB == 0);
1296  mlfbB = &(mlfbs[i]);
1297  }
1298  }
1299  CHECK(mlfbB != 0);
1300 
1301  // ** both parts must be pivots
1302  CHECK(plane.isPivot(*mlfbA));
1303  CHECK(plane.isPivot(*mlfbB));
1304 
1305  // ** the two pivots must be on the left
1306  CHECK((mlfbA == pivots[0] && mlfbB == pivots[1]) ||
1307  (mlfbA == pivots[1] && mlfbB == pivots[0]));
1308 }
1309 
1310 const char* getEdgePos(size_t index) {
1311  switch (index) {
1312  case 0: return "sw";
1313  case 1: return "se";
1314  case 2: return "ne";
1315  case 3: return "nw";
1316  default: ASSERT(false);
1317  return "ERROR";
1318  }
1319 }
1320 
1321 mpq_class getIndexSum(const vector<Mlfb>& mlfbs) {
1322  mpq_class sum;
1323  for (size_t m = 0; m < mlfbs.size(); ++m)
1324  sum += mlfbs[m].index;
1325  return sum;
1326 }
1327 
1329 SeqPos::SeqPos(const Mlfb* mlfbParam, size_t nextFacet, size_t previousFacet) {
1330  ASSERT(mlfbParam != 0);
1331  ASSERT(nextFacet != previousFacet);
1332  ASSERT(nextFacet < 4);
1333  ASSERT(previousFacet < 4);
1334  mlfb = mlfbParam;
1335 
1336  comingFromFacet = previousFacet;
1337  for (size_t f = 0; f < 4; ++f)
1338  if (f != previousFacet && f != nextFacet)
1339  fixFacet1 = f;
1340  for (size_t f = 0; f < 4; ++f)
1341  if (f != previousFacet && f != nextFacet && f != fixFacet1)
1342  fixFacet2 = f;
1343 }
1344 
1345 size_t SeqPos::getForwardFacet() const {
1346  for (size_t i = 0; ; ++i) {
1347  ASSERT(i < 4);
1348  if (i != fixFacet1 && i != fixFacet2 && i != comingFromFacet)
1349  return i;
1350  }
1351 }
1352 
1353 size_t SeqPos::getBackFacet() const {
1354  return comingFromFacet;
1355 }
1356 
1358  size_t to;
1359  for (to = 0; to < 4; ++to) {
1360  if (to != fixFacet1 && to != fixFacet2 && to != comingFromFacet)
1361  break;
1362  }
1363  ASSERT(to != 4);
1364  SeqPos reverse = *this;
1365  reverse.comingFromFacet = to;
1366  return reverse;
1367 }
1368 
1370  if (fixFacet1 > fixFacet2)
1372 }
1373 
1374 bool SeqPos::operator<(const SeqPos& pos) const {
1375  if (mlfb->getOffset() < pos.mlfb->getOffset())
1376  return true;
1377  if (mlfb->getOffset() > pos.mlfb->getOffset())
1378  return false;
1379 
1380  if (fixFacet1 < pos.fixFacet1)
1381  return true;
1382  if (fixFacet1 > pos.fixFacet1)
1383  return false;
1384 
1385  if (fixFacet2 < pos.fixFacet2)
1386  return true;
1387  if (fixFacet2 > pos.fixFacet2)
1388  return false;
1389 
1390  if (comingFromFacet < pos.comingFromFacet)
1391  return true;
1392  if (comingFromFacet > pos.comingFromFacet)
1393  return false;
1394 
1395  return false;
1396 }
1397 
1399  _lat(0), _row(0) {
1400 }
1401 
1403  _lat(&lat), _row(lat.getNeighborCount() + 1) {
1404 }
1405 
1406 Neighbor::Neighbor(const GrobLat& lat, const size_t row):
1407  _lat(&lat), _row(row) {
1408 }
1409 
1410 const mpq_class& Neighbor::getH(size_t i) const {
1411  ASSERT(isValid());
1412  ASSERT(i < getHDim());
1413  if (isZero())
1414  return _lat->getZero();
1415  else
1416  return _lat->getHMatrix()(_row, i);
1417 }
1418 
1419 size_t Neighbor::getHDim() const {
1420  ASSERT(isValid());
1421  return _lat->getHDim();
1422 }
1423 
1424 const mpq_class& Neighbor::getY(size_t i) const {
1425  ASSERT(isValid());
1426  ASSERT(i < getYDim());
1427  if (isZero())
1428  return _lat->getZero();
1429  else
1430  return _lat->getYMatrix()(_row, i);
1431 }
1432 
1433 size_t Neighbor::getYDim() const {
1434  ASSERT(isValid());
1435  return _lat->getYDim();
1436 }
1437 
1438 bool Neighbor::isZero() const {
1439  ASSERT(isValid());
1440  return _row == _lat->getNeighborCount() + 1;
1441 }
1442 
1443 bool Neighbor::isValid() const {
1444  return _lat != 0;
1445 }
1446 
1447 size_t Plane::getTypeCount(size_t type) const {
1448  map<size_t, size_t>::const_iterator it = typeCounts.find(type);
1449  if (it == typeCounts.end())
1450  return 0u;
1451  else
1452  return it->second;
1453 }
1454 
1455 size_t Plane::getMaxType() const {
1456  if (typeCounts.empty())
1457  return 0u;
1458  else
1459  return typeCounts.rbegin()->first;
1460 }
1461 
1463  if (neighbor.isZero())
1464  return InPlane;
1465  ASSERT(neighbor.getRow() < neighborPlace.size());
1466  return neighborPlace[neighbor.getRow()];
1467 }
1468 
1469 bool Plane::inPlane(Neighbor neighbor) const {
1470  return getPlace(neighbor) == InPlane;
1471 }
1472 
1473 bool Plane::isPivot(const Mlfb& mlfb) const {
1474  const size_t type = getType(mlfb);
1475  return type == 1 || type == 3;
1476 }
1477 
1478 bool Plane::isSidePivot(const Mlfb& mlfb) const {
1479  if (!isPivot(mlfb))
1480  return false;
1481  for (size_t i = 0; i < 4; ++i)
1482  if (is22(*(mlfb.getEdge(i))))
1483  return true;
1484  return false;
1485 }
1486 
1487 bool Plane::is22(const Mlfb& mlfb) const {
1488  const size_t type = getType(mlfb);
1489  return type == 2;
1490 }
1491 
1492 bool Plane::isFlat(const Mlfb& mlfb) const {
1493  return getType(mlfb) == 4;
1494 }
1495 
1496 bool Neighbor::isSpecial() const {
1497  ASSERT(isValid());
1498  for (size_t i = 1; i < _lat->getYDim(); ++i)
1499  if (getY(i) <= 0)
1500  return false;
1501  return true;
1502 }
1503 
1505  if (isZero())
1506  return false;
1507  else
1508  return !_lat->isSum(*this);
1509 }
1510 
1511 size_t Plane::getType(const Mlfb& mlfb) const {
1512  size_t type = 0;
1513  for (size_t i = 0; i < mlfb.getPointCount(); ++i)
1514  if (inPlane(mlfb.getPoint(i)))
1515  ++type;
1516  return type;
1517 }
1518 
1519 string Neighbor::getName() const {
1520  if (isZero())
1521  return "zero";
1522  if (!isValid())
1523  return "none";
1524  ostringstream name;
1525  name << 'n' << (getRow() + 1);
1526  if (isSpecial())
1527  name << 's';
1528  if (isGenerator())
1529  name << 'g';
1530  return name.str();
1531 }
1532 
1533 GrobLat::GrobLat(const Matrix& matrix, const SatBinomIdeal& ideal) {
1534  _ideal = ideal;
1535  _ideal.getMatrix(_y);
1536 
1537  // transpose in preparation for solve
1538  transpose(_y);
1539  transpose(_mat, matrix);
1540 
1541  solve(_h, _mat, _y);
1542 
1543  // un-transpose
1544  transpose(_mat);
1545  transpose(_y);
1546  transpose(_h);
1547 
1548  _isSumRow.resize(getNeighborCount());
1549  for (size_t i = 0; i < getNeighborCount(); ++i) {
1550  for (size_t j = 0; j < i; ++j) {
1551  Neighbor sum = getSum(getNeighbor(i), getNeighbor(j));
1552  if (sum.isValid())
1553  _isSumRow[sum.getRow()] = true;
1554  }
1555  }
1556 
1557  _nonSums.clear();
1558  for (size_t i = 0; i < _isSumRow.size(); ++i)
1559  if (!_isSumRow[i])
1560  _nonSums.push_back(getNeighbor(i));
1561 }
void checkFlatSeq(const vector< SeqPos > &flatSeq, const GrobLat &lat, const Plane &plane)
void checkGraphOnPlane(const Plane &plane, const vector< Mlfb > &mlfbs)
void checkPlanes(const vector< TriPlane > &thinPlanes, const vector< Plane > &dtPlanes)
Definition: LatticeAlgs.cpp:99
void checkMlfbs(const vector< Mlfb > &mlfbs, const GrobLat &lat)
const char * getEdgePos(size_t index)
bool disjointSeqs(const vector< SeqPos > &a, const vector< SeqPos > &b)
void computePivotSeqs(vector< vector< SeqPos > > &seqs, const Mlfb &pivot, const Plane &plane)
Starting at pivot (which must be a pivot), follow the three non-flat sequences starting at pivot.
SeqPos prevInSeq(SeqPos pos)
void checkSeqs(const vector< vector< SeqPos > > &left, const vector< vector< SeqPos > > &right, const Plane &plane, const vector< Mlfb > &mlfbs)
void checkSeq(vector< bool > &seenOnSide, const vector< SeqPos > &seq, const Plane &plane)
void computeSeqs(vector< vector< SeqPos > > &left, vector< vector< SeqPos > > &right, const vector< Mlfb > &mlfbs, const Plane &plane)
size_t pivotToFlatFacet(const Mlfb &pivot, const Plane &plane)
Returns the facet to push in of pivot to get to a flat.
size_t pushOutFacetZero(const vector< mpz_class > &rhs, const GrobLat &lat)
char getPlaceCode(NeighborPlace place)
void computeMlfbs(vector< Mlfb > &mlfbs, const GrobLat &lat)
void computePivots(vector< const Mlfb * > &pivots, const vector< Mlfb > &mlfbs, const Plane &plane, const vector< SeqPos > &flatSeq)
Put all pivots into pivots.
void checkGraph(const vector< Mlfb > &mlfbs)
void checkMiddle(const Plane &plane, const vector< Mlfb > &mlfbs)
mpq_class getIndexSum(const vector< Mlfb > &mlfbs)
void checkDoubleTriangle(const Plane &plane, const vector< Mlfb > &mlfbs)
void computePlanes(vector< Plane > &planes, const GrobLat &lat, vector< Mlfb > &mlfbs)
void checkDoubleTrianglePlanes(const vector< Plane > &planes, const GrobLat &lat, const vector< Mlfb > &mlfbs)
void checkSide(vector< bool > &pivotOnSide, const vector< vector< SeqPos > > &side, const Plane &plane, const vector< Mlfb > &mlfbs)
void computeFlatSeq(vector< SeqPos > &seq, const vector< Mlfb > &mlfbs, const Plane &plane)
void check0Graph(const vector< Mlfb > &mlfbs)
SeqPos nextInSeq(SeqPos pos)
size_t pushOutFacetPositive(size_t facetPushOut, const vector< mpz_class > &rhs, const GrobLat &lat)
void getThinPlanes(vector< TriPlane > &planes, const GrobLat &lat)
Definition: LatticeAlgs.cpp:22
void checkNonSums(const GrobLat &lat)
void computeRhs(vector< mpz_class > &rhs, const vector< Neighbor > points)
void checkPlane(const Plane &plane, const vector< Mlfb > &mlfbs)
void checkPlaneTri(const GrobLat &lat, const vector< Mlfb > &mlfbs, const vector< const Mlfb * > &pivots, const Plane &plane)
void checkPivotSeqs(vector< vector< SeqPos > > &pivotSeqs, const Plane &plane, const vector< Mlfb > &mlfbs, const vector< SeqPos > &flatSeq)
Perform checks where pivotSeqs are the 3 non-flat sequences on one side.
size_t computeFlatIntervalCount(const vector< SeqPos > &flatSeq)
NeighborPlace
Definition: LatticeAlgs.h:58
@ InPlane
Definition: LatticeAlgs.h:59
@ OverPlane
Definition: LatticeAlgs.h:61
@ UnderPlane
Definition: LatticeAlgs.h:60
@ NoPlace
Definition: LatticeAlgs.h:62
#define CHECK(X)
Definition: LatticeAlgs.h:48
bool solve(Matrix &sol, const Matrix &lhs, const Matrix &rhs)
Sets sol to some matrix such that lhs*sol=rhs and returns true if such a matrix exists.
Definition: Matrix.cpp:348
mpq_class getParallelogramAreaSq(const Matrix &mat)
Returns the square of the area of the parallelogram whose vertices are the 4 rows of mat.
Definition: Matrix.cpp:456
void product(Matrix &prod, const Matrix &a, const Matrix &b)
Sets prod to a * b.
Definition: Matrix.cpp:116
bool isParallelogram(const Matrix &mat)
Returns true if the rows of mat are the (4) vertices of a parallelogram.
Definition: Matrix.cpp:452
void nullSpace(Matrix &basis, const Matrix &matParam)
Sets the columns of basis to a basis of the null space of mat.
Definition: Matrix.cpp:296
mpq_class determinant(const Matrix &mat)
Returns the determinant of mat.
Definition: Matrix.cpp:410
void copyRow(Matrix &target, size_t targetRow, const Matrix &source, size_t sourceRow)
Copies row sourceRow from source to row targetRow of target.
Definition: Matrix.cpp:246
bool hasSameRowSpace(const Matrix &a, const Matrix &b)
Returns true if a and b have the same row space.
Definition: Matrix.cpp:390
void transpose(Matrix &trans, const Matrix &mat)
Sets trans to the transpose of mat.
Definition: Matrix.cpp:129
size_t getVarCount() const
Definition: BigIdeal.h:148
size_t getGeneratorCount() const
Definition: BigIdeal.h:144
BigTermRecorder records all the terms it consumes into an ideal.
bool empty() const
auto_ptr< BigIdeal > releaseIdeal()
A lattice with associated Grobner basis/neighbors.
Definition: LatticeAlgs.h:124
Matrix _h
Definition: LatticeAlgs.h:229
Neighbor getNeighbor(size_t row) const
Definition: LatticeAlgs.h:128
const mpq_class & getZero() const
Definition: LatticeAlgs.h:198
size_t getYDim() const
Definition: LatticeAlgs.h:174
size_t getHDim() const
Definition: LatticeAlgs.h:179
SatBinomIdeal _ideal
Definition: LatticeAlgs.h:231
const vector< Neighbor > & getNonSums() const
Definition: LatticeAlgs.h:197
vector< bool > _isSumRow
Definition: LatticeAlgs.h:225
Matrix _y
Definition: LatticeAlgs.h:228
const Matrix & getYMatrix() const
Definition: LatticeAlgs.h:138
GrobLat(const Matrix &matrix, const SatBinomIdeal &ideal)
Neighbor getSum(Neighbor a, Neighbor b) const
Definition: LatticeAlgs.h:144
size_t getNeighborCount() const
Definition: LatticeAlgs.h:133
const Matrix & getHMatrix() const
Definition: LatticeAlgs.h:139
void getInitialIdeal(BigIdeal &ideal) const
Definition: LatticeAlgs.h:187
Matrix _mat
Definition: LatticeAlgs.h:230
bool isSum(Neighbor n) const
Definition: LatticeAlgs.h:191
vector< Neighbor > _nonSums
Definition: LatticeAlgs.h:226
bool isPointFreeBody(Neighbor a, Neighbor b) const
Returns true if the smallest body containing zero, a and b has no neighbor in its interior.
Definition: LatticeAlgs.h:202
const Matrix & getMatrix() const
Definition: LatticeAlgs.h:140
Definition: Matrix.h:26
size_t getColCount() const
Definition: Matrix.h:31
size_t getRowCount() const
Definition: Matrix.h:30
const vector< mpz_class > & getRhs() const
Definition: LatticeAlgs.h:319
Neighbor getPoint(size_t offset) const
Definition: LatticeAlgs.h:302
vector< mpz_class > _rhs
Definition: LatticeAlgs.h:377
vector< Neighbor > _points
Definition: LatticeAlgs.h:378
vector< Mlfb * > edges
Definition: LatticeAlgs.h:370
mpq_class index
Definition: LatticeAlgs.h:368
vector< size_t > edgeHitsFacet
Definition: LatticeAlgs.h:371
const Mlfb * getEdge(size_t indexParam) const
Definition: LatticeAlgs.h:347
bool hasPoint(Neighbor n) const
Definition: LatticeAlgs.h:295
size_t _offset
Definition: LatticeAlgs.h:379
void reset(size_t offset, const vector< Neighbor > &points)
mpz_class dotDegree
Definition: LatticeAlgs.h:369
size_t minInitialFacet
Definition: LatticeAlgs.h:372
size_t getOffset() const
Definition: LatticeAlgs.h:315
size_t getPointCount() const
Definition: LatticeAlgs.h:307
bool isParallelogram() const
Definition: LatticeAlgs.h:364
size_t getMinInitialFacet() const
Definition: LatticeAlgs.h:291
size_t getHitsFacet(size_t indexParam) const
Definition: LatticeAlgs.h:342
bool _isParallelogram
Definition: LatticeAlgs.h:380
const GrobLat * _lat
Definition: LatticeAlgs.h:119
bool isSpecial() const
size_t _row
Definition: LatticeAlgs.h:120
bool isGenerator() const
const mpq_class & getH(size_t i) const
string getName() const
size_t getRow() const
Definition: LatticeAlgs.h:108
size_t getYDim() const
const mpq_class & getY(size_t i) const
size_t getHDim() const
bool isZero() const
bool isValid() const
bool isFlat(const Mlfb &mlfb) const
vector< NeighborPlace > neighborPlace
Definition: LatticeAlgs.h:284
vector< SeqPos > flatSeq
Definition: LatticeAlgs.h:285
Tri tri
Definition: LatticeAlgs.h:279
bool isPivot(const Mlfb &mlfb) const
size_t flatIntervalCount
Definition: LatticeAlgs.h:281
Matrix nullSpaceBasis
Definition: LatticeAlgs.h:278
bool is22(const Mlfb &mlfb) const
NeighborPlace getPlace(Neighbor neighbor) const
bool hasFlat() const
Definition: LatticeAlgs.h:274
map< size_t, size_t > typeCounts
Definition: LatticeAlgs.h:283
vector< const Mlfb * > pivots
Definition: LatticeAlgs.h:286
size_t getTypeCount(size_t type) const
bool isSidePivot(const Mlfb &mlfb) const
Matrix rowAB
Definition: LatticeAlgs.h:280
size_t getMaxType() const
bool inPlane(Neighbor neighbor) const
size_t getType(const Mlfb &mlfb) const
Represents a saturated binomial ideal.
Definition: SatBinomIdeal.h:28
void getMatrix(Matrix &matrix) const
A facade for operations on monomial ideals using the Slice Algorithm.
Definition: SliceFacade.h:44
void computeIrreducibleDecomposition(bool encode)
Compute the unique irredundant set of irreducible ideals whose intersection equals ideal.
bool closeToPlane(Neighbor a)
Definition: LatticeAlgs.h:403
bool isParallel(const TriPlane &plane) const
Definition: LatticeAlgs.h:420
bool isLine() const
Definition: LatticeAlgs.h:399
vector< const Mlfb * > _bSideMlfbs
Definition: LatticeAlgs.h:253
const vector< const Mlfb * > & getBSideMlfbs() const
Definition: LatticeAlgs.h:244
Tri(Neighbor a, Neighbor b, Neighbor sum, const vector< Mlfb > &mlfbs, const GrobLat &lat)
Neighbor getB() const
Definition: LatticeAlgs.h:241
vector< Neighbor > _interior
Definition: LatticeAlgs.h:254
const vector< const Mlfb * > & getASideMlfbs() const
Definition: LatticeAlgs.h:243
Neighbor getA() const
Definition: LatticeAlgs.h:240
Neighbor getSum() const
Definition: LatticeAlgs.h:242
vector< Neighbor > _boundary
Definition: LatticeAlgs.h:255
vector< const Mlfb * > _aSideMlfbs
Definition: LatticeAlgs.h:252
void swap(hashtable< _Val, _Key, _HF, _Extract, _EqKey, _All > &__ht1, hashtable< _Val, _Key, _HF, _Extract, _EqKey, _All > &__ht2)
Definition: hashtable.h:740
#define ASSERT(X)
Definition: stdinc.h:86
void order()
SeqPos getReverse() const
const Mlfb * mlfb
Definition: LatticeAlgs.h:78
size_t comingFromFacet
Definition: LatticeAlgs.h:81
size_t fixFacet1
Definition: LatticeAlgs.h:79
bool operator<(const SeqPos &pos) const
size_t fixFacet2
Definition: LatticeAlgs.h:80
size_t getForwardFacet() const
size_t getBackFacet() const