MLIR  20.0.0git
IntegerRelation.cpp
Go to the documentation of this file.
1 //===- IntegerRelation.cpp - MLIR IntegerRelation Class ---------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // A class to represent an relation over integer tuples. A relation is
10 // represented as a constraint system over a space of tuples of integer valued
11 // variables supporting symbolic variables and existential quantification.
12 //
13 //===----------------------------------------------------------------------===//
14 
23 #include "llvm/ADT/DenseMap.h"
24 #include "llvm/ADT/DenseSet.h"
25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/Sequence.h"
27 #include "llvm/ADT/SmallBitVector.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/LogicalResult.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include <algorithm>
32 #include <cassert>
33 #include <functional>
34 #include <memory>
35 #include <numeric>
36 #include <optional>
37 #include <sstream>
38 #include <string>
39 #include <utility>
40 #include <vector>
41 
42 #define DEBUG_TYPE "presburger"
43 
44 using namespace mlir;
45 using namespace presburger;
46 
47 using llvm::SmallDenseMap;
48 using llvm::SmallDenseSet;
49 
50 std::unique_ptr<IntegerRelation> IntegerRelation::clone() const {
51  return std::make_unique<IntegerRelation>(*this);
52 }
53 
54 std::unique_ptr<IntegerPolyhedron> IntegerPolyhedron::clone() const {
55  return std::make_unique<IntegerPolyhedron>(*this);
56 }
57 
59  assert(space.getNumVars() == oSpace.getNumVars() && "invalid space!");
60  space = oSpace;
61 }
62 
64  assert(oSpace.getNumLocalVars() == 0 && "no locals should be present!");
65  assert(oSpace.getNumVars() <= getNumVars() && "invalid space!");
66  unsigned newNumLocals = getNumVars() - oSpace.getNumVars();
67  space = oSpace;
68  space.insertVar(VarKind::Local, 0, newNumLocals);
69 }
70 
71 void IntegerRelation::setId(VarKind kind, unsigned i, Identifier id) {
72  assert(space.isUsingIds() &&
73  "space must be using identifiers to set an identifier");
74  assert(kind != VarKind::Local && "local variables cannot have identifiers");
75  assert(i < space.getNumVarKind(kind) && "invalid variable index");
76  space.setId(kind, i, id);
77 }
78 
80  if (!space.isUsingIds())
81  space.resetIds();
82  return space.getIds(kind);
83 }
84 
86  assert(space.isEqual(other.getSpace()) && "Spaces must be equal.");
87 
89  other.getNumInequalities());
91 
92  for (unsigned r = 0, e = other.getNumInequalities(); r < e; r++) {
93  addInequality(other.getInequality(r));
94  }
95  for (unsigned r = 0, e = other.getNumEqualities(); r < e; r++) {
96  addEquality(other.getEquality(r));
97  }
98 }
99 
101  IntegerRelation result = *this;
102  result.mergeLocalVars(other);
103  result.append(other);
104  return result;
105 }
106 
107 bool IntegerRelation::isEqual(const IntegerRelation &other) const {
108  assert(space.isCompatible(other.getSpace()) && "Spaces must be compatible.");
109  return PresburgerRelation(*this).isEqual(PresburgerRelation(other));
110 }
111 
113  if (!space.isEqual(other.getSpace()))
114  return false;
115  if (getNumEqualities() != other.getNumEqualities())
116  return false;
117  if (getNumInequalities() != other.getNumInequalities())
118  return false;
119 
120  unsigned cols = getNumCols();
121  for (unsigned i = 0, eqs = getNumEqualities(); i < eqs; ++i) {
122  for (unsigned j = 0; j < cols; ++j) {
123  if (atEq(i, j) != other.atEq(i, j))
124  return false;
125  }
126  }
127  for (unsigned i = 0, ineqs = getNumInequalities(); i < ineqs; ++i) {
128  for (unsigned j = 0; j < cols; ++j) {
129  if (atIneq(i, j) != other.atIneq(i, j))
130  return false;
131  }
132  }
133  return true;
134 }
135 
137  assert(space.isCompatible(other.getSpace()) && "Spaces must be compatible.");
138  return PresburgerRelation(*this).isSubsetOf(PresburgerRelation(other));
139 }
140 
143  assert(getNumSymbolVars() == 0 && "Symbols are not supported!");
146 
147  if (!maybeLexMin.isBounded())
148  return maybeLexMin;
149 
150  // The Simplex returns the lexmin over all the variables including locals. But
151  // locals are not actually part of the space and should not be returned in the
152  // result. Since the locals are placed last in the list of variables, they
153  // will be minimized last in the lexmin. So simply truncating out the locals
154  // from the end of the answer gives the desired lexmin over the dimensions.
155  assert(maybeLexMin->size() == getNumVars() &&
156  "Incorrect number of vars in lexMin!");
157  maybeLexMin->resize(getNumDimAndSymbolVars());
158  return maybeLexMin;
159 }
160 
163  assert(getNumSymbolVars() == 0 && "Symbols are not supported!");
165  LexSimplex(*this).findIntegerLexMin();
166 
167  if (!maybeLexMin.isBounded())
168  return maybeLexMin.getKind();
169 
170  // The Simplex returns the lexmin over all the variables including locals. But
171  // locals are not actually part of the space and should not be returned in the
172  // result. Since the locals are placed last in the list of variables, they
173  // will be minimized last in the lexmin. So simply truncating out the locals
174  // from the end of the answer gives the desired lexmin over the dimensions.
175  assert(maybeLexMin->size() == getNumVars() &&
176  "Incorrect number of vars in lexMin!");
177  maybeLexMin->resize(getNumDimAndSymbolVars());
178  return maybeLexMin;
179 }
180 
182  return llvm::all_of(range, [](const DynamicAPInt &x) { return x == 0; });
183 }
184 
186  unsigned begin, unsigned count) {
187  // We loop until i > 0 and index into i - 1 to avoid sign issues.
188  //
189  // We iterate backwards so that whether we remove constraint i - 1 or not, the
190  // next constraint to be tested is always i - 2.
191  for (unsigned i = poly.getNumEqualities(); i > 0; i--)
192  if (!rangeIsZero(poly.getEquality(i - 1).slice(begin, count)))
193  poly.removeEquality(i - 1);
194  for (unsigned i = poly.getNumInequalities(); i > 0; i--)
195  if (!rangeIsZero(poly.getInequality(i - 1).slice(begin, count)))
196  poly.removeInequality(i - 1);
197 }
198 
201 }
202 
203 void IntegerRelation::truncateVarKind(VarKind kind, unsigned num) {
204  unsigned curNum = getNumVarKind(kind);
205  assert(num <= curNum && "Can't truncate to more vars!");
206  removeVarRange(kind, num, curNum);
207 }
208 
210  const CountsSnapshot &counts) {
211  truncateVarKind(kind, counts.getSpace().getNumVarKind(kind));
212 }
213 
221 }
222 
224  // If there are no locals, we're done.
225  if (getNumLocalVars() == 0)
226  return PresburgerRelation(*this);
227 
228  // Move all the non-div locals to the end, as the current API to
229  // SymbolicLexOpt requires these to form a contiguous range.
230  //
231  // Take a copy so we can perform mutations.
232  IntegerRelation copy = *this;
233  std::vector<MaybeLocalRepr> reprs(getNumLocalVars());
234  copy.getLocalReprs(&reprs);
235 
236  // Iterate through all the locals. The last `numNonDivLocals` are the locals
237  // that have been scanned already and do not have division representations.
238  unsigned numNonDivLocals = 0;
239  unsigned offset = copy.getVarKindOffset(VarKind::Local);
240  for (unsigned i = 0, e = copy.getNumLocalVars(); i < e - numNonDivLocals;) {
241  if (!reprs[i]) {
242  // Whenever we come across a local that does not have a division
243  // representation, we swap it to the `numNonDivLocals`-th last position
244  // and increment `numNonDivLocal`s. `reprs` also needs to be swapped.
245  copy.swapVar(offset + i, offset + e - numNonDivLocals - 1);
246  std::swap(reprs[i], reprs[e - numNonDivLocals - 1]);
247  ++numNonDivLocals;
248  continue;
249  }
250  ++i;
251  }
252 
253  // If there are no non-div locals, we're done.
254  if (numNonDivLocals == 0)
255  return PresburgerRelation(*this);
256 
257  // We computeSymbolicIntegerLexMin by considering the non-div locals as
258  // "non-symbols" and considering everything else as "symbols". This will
259  // compute a function mapping assignments to "symbols" to the
260  // lexicographically minimal valid assignment of "non-symbols", when a
261  // satisfying assignment exists. It separately returns the set of assignments
262  // to the "symbols" such that a satisfying assignment to the "non-symbols"
263  // exists but the lexmin is unbounded. We basically want to find the set of
264  // values of the "symbols" such that an assignment to the "non-symbols"
265  // exists, which is the union of the domain of the returned lexmin function
266  // and the returned set of assignments to the "symbols" that makes the lexmin
267  // unbounded.
268  SymbolicLexOpt lexminResult =
269  SymbolicLexSimplex(copy, /*symbolOffset*/ 0,
271  /*numDims=*/copy.getNumVars() - numNonDivLocals)))
273  PresburgerRelation result =
274  lexminResult.lexopt.getDomain().unionSet(lexminResult.unboundedDomain);
275 
276  // The result set might lie in the wrong space -- all its ids are dims.
277  // Set it to the desired space and return.
280  result.setSpace(space);
281  return result;
282 }
283 
285  // Symbol and Domain vars will be used as symbols for symbolic lexmin.
286  // In other words, for every value of the symbols and domain, return the
287  // lexmin value of the (range, locals).
288  llvm::SmallBitVector isSymbol(getNumVars(), false);
289  isSymbol.set(getVarKindOffset(VarKind::Symbol),
291  isSymbol.set(getVarKindOffset(VarKind::Domain),
293  // Compute the symbolic lexmin of the dims and locals, with the symbols being
294  // the actual symbols of this set.
295  // The resultant space of lexmin is the space of the relation itself.
296  SymbolicLexOpt result =
297  SymbolicLexSimplex(*this,
299  /*numDims=*/getNumDomainVars(),
300  /*numSymbols=*/getNumSymbolVars())),
301  isSymbol)
303 
304  // We want to return only the lexmin over the dims, so strip the locals from
305  // the computed lexmin.
307  result.lexopt.getNumOutputs());
308  return result;
309 }
310 
311 /// findSymbolicIntegerLexMax is implemented using findSymbolicIntegerLexMin as
312 /// follows:
313 /// 1. A new relation is created which is `this` relation with the sign of
314 /// each dimension variable in range flipped;
315 /// 2. findSymbolicIntegerLexMin is called on the range negated relation to
316 /// compute the negated lexmax of `this` relation;
317 /// 3. The sign of the negated lexmax is flipped and returned.
319  IntegerRelation flippedRel = *this;
320  // Flip range sign by flipping the sign of range variables in all constraints.
321  for (unsigned j = getNumDomainVars(),
323  j < b; j++) {
324  for (unsigned i = 0, a = getNumEqualities(); i < a; i++)
325  flippedRel.atEq(i, j) = -1 * atEq(i, j);
326  for (unsigned i = 0, a = getNumInequalities(); i < a; i++)
327  flippedRel.atIneq(i, j) = -1 * atIneq(i, j);
328  }
329  // Compute negated lexmax by computing lexmin.
330  SymbolicLexOpt flippedSymbolicIntegerLexMax =
331  flippedRel.findSymbolicIntegerLexMin(),
332  symbolicIntegerLexMax(
333  flippedSymbolicIntegerLexMax.lexopt.getSpace());
334  // Get lexmax by flipping range sign in the PWMA constraints.
335  for (auto &flippedPiece :
336  flippedSymbolicIntegerLexMax.lexopt.getAllPieces()) {
337  IntMatrix mat = flippedPiece.output.getOutputMatrix();
338  for (unsigned i = 0, e = mat.getNumRows(); i < e; i++)
339  mat.negateRow(i);
340  MultiAffineFunction maf(flippedPiece.output.getSpace(), mat);
341  PWMAFunction::Piece piece = {flippedPiece.domain, maf};
342  symbolicIntegerLexMax.lexopt.addPiece(piece);
343  }
344  symbolicIntegerLexMax.unboundedDomain =
345  flippedSymbolicIntegerLexMax.unboundedDomain;
346  return symbolicIntegerLexMax;
347 }
348 
351  return PresburgerRelation(*this).subtract(set);
352 }
353 
354 unsigned IntegerRelation::insertVar(VarKind kind, unsigned pos, unsigned num) {
355  assert(pos <= getNumVarKind(kind));
356 
357  unsigned insertPos = space.insertVar(kind, pos, num);
358  inequalities.insertColumns(insertPos, num);
359  equalities.insertColumns(insertPos, num);
360  return insertPos;
361 }
362 
363 unsigned IntegerRelation::appendVar(VarKind kind, unsigned num) {
364  unsigned pos = getNumVarKind(kind);
365  return insertVar(kind, pos, num);
366 }
367 
369  assert(eq.size() == getNumCols());
370  unsigned row = equalities.appendExtraRow();
371  for (unsigned i = 0, e = eq.size(); i < e; ++i)
372  equalities(row, i) = eq[i];
373 }
374 
376  assert(inEq.size() == getNumCols());
377  unsigned row = inequalities.appendExtraRow();
378  for (unsigned i = 0, e = inEq.size(); i < e; ++i)
379  inequalities(row, i) = inEq[i];
380 }
381 
382 void IntegerRelation::removeVar(VarKind kind, unsigned pos) {
383  removeVarRange(kind, pos, pos + 1);
384 }
385 
386 void IntegerRelation::removeVar(unsigned pos) { removeVarRange(pos, pos + 1); }
387 
388 void IntegerRelation::removeVarRange(VarKind kind, unsigned varStart,
389  unsigned varLimit) {
390  assert(varLimit <= getNumVarKind(kind));
391 
392  if (varStart >= varLimit)
393  return;
394 
395  // Remove eliminated variables from the constraints.
396  unsigned offset = getVarKindOffset(kind);
397  equalities.removeColumns(offset + varStart, varLimit - varStart);
398  inequalities.removeColumns(offset + varStart, varLimit - varStart);
399 
400  // Remove eliminated variables from the space.
401  space.removeVarRange(kind, varStart, varLimit);
402 }
403 
404 void IntegerRelation::removeVarRange(unsigned varStart, unsigned varLimit) {
405  assert(varLimit <= getNumVars());
406 
407  if (varStart >= varLimit)
408  return;
409 
410  // Helper function to remove vars of the specified kind in the given range
411  // [start, limit), The range is absolute (i.e. it is not relative to the kind
412  // of variable). Also updates `limit` to reflect the deleted variables.
413  auto removeVarKindInRange = [this](VarKind kind, unsigned &start,
414  unsigned &limit) {
415  if (start >= limit)
416  return;
417 
418  unsigned offset = getVarKindOffset(kind);
419  unsigned num = getNumVarKind(kind);
420 
421  // Get `start`, `limit` relative to the specified kind.
422  unsigned relativeStart =
423  start <= offset ? 0 : std::min(num, start - offset);
424  unsigned relativeLimit =
425  limit <= offset ? 0 : std::min(num, limit - offset);
426 
427  // Remove vars of the specified kind in the relative range.
428  removeVarRange(kind, relativeStart, relativeLimit);
429 
430  // Update `limit` to reflect deleted variables.
431  // `start` does not need to be updated because any variables that are
432  // deleted are after position `start`.
433  limit -= relativeLimit - relativeStart;
434  };
435 
436  removeVarKindInRange(VarKind::Domain, varStart, varLimit);
437  removeVarKindInRange(VarKind::Range, varStart, varLimit);
438  removeVarKindInRange(VarKind::Symbol, varStart, varLimit);
439  removeVarKindInRange(VarKind::Local, varStart, varLimit);
440 }
441 
443  equalities.removeRow(pos);
444 }
445 
447  inequalities.removeRow(pos);
448 }
449 
450 void IntegerRelation::removeEqualityRange(unsigned start, unsigned end) {
451  if (start >= end)
452  return;
453  equalities.removeRows(start, end - start);
454 }
455 
456 void IntegerRelation::removeInequalityRange(unsigned start, unsigned end) {
457  if (start >= end)
458  return;
459  inequalities.removeRows(start, end - start);
460 }
461 
462 void IntegerRelation::swapVar(unsigned posA, unsigned posB) {
463  assert(posA < getNumVars() && "invalid position A");
464  assert(posB < getNumVars() && "invalid position B");
465 
466  if (posA == posB)
467  return;
468 
469  VarKind kindA = space.getVarKindAt(posA);
470  VarKind kindB = space.getVarKindAt(posB);
471  unsigned relativePosA = posA - getVarKindOffset(kindA);
472  unsigned relativePosB = posB - getVarKindOffset(kindB);
473  space.swapVar(kindA, kindB, relativePosA, relativePosB);
474 
475  inequalities.swapColumns(posA, posB);
476  equalities.swapColumns(posA, posB);
477 }
478 
482 }
483 
484 /// Gather all lower and upper bounds of the variable at `pos`, and
485 /// optionally any equalities on it. In addition, the bounds are to be
486 /// independent of variables in position range [`offset`, `offset` + `num`).
488  unsigned pos, SmallVectorImpl<unsigned> *lbIndices,
490  unsigned offset, unsigned num) const {
491  assert(pos < getNumVars() && "invalid position");
492  assert(offset + num < getNumCols() && "invalid range");
493 
494  // Checks for a constraint that has a non-zero coeff for the variables in
495  // the position range [offset, offset + num) while ignoring `pos`.
496  auto containsConstraintDependentOnRange = [&](unsigned r, bool isEq) {
497  unsigned c, f;
498  auto cst = isEq ? getEquality(r) : getInequality(r);
499  for (c = offset, f = offset + num; c < f; ++c) {
500  if (c == pos)
501  continue;
502  if (cst[c] != 0)
503  break;
504  }
505  return c < f;
506  };
507 
508  // Gather all lower bounds and upper bounds of the variable. Since the
509  // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower
510  // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1.
511  for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
512  // The bounds are to be independent of [offset, offset + num) columns.
513  if (containsConstraintDependentOnRange(r, /*isEq=*/false))
514  continue;
515  if (atIneq(r, pos) >= 1) {
516  // Lower bound.
517  lbIndices->emplace_back(r);
518  } else if (atIneq(r, pos) <= -1) {
519  // Upper bound.
520  ubIndices->emplace_back(r);
521  }
522  }
523 
524  // An equality is both a lower and upper bound. Record any equalities
525  // involving the pos^th variable.
526  if (!eqIndices)
527  return;
528 
529  for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
530  if (atEq(r, pos) == 0)
531  continue;
532  if (containsConstraintDependentOnRange(r, /*isEq=*/true))
533  continue;
534  eqIndices->emplace_back(r);
535  }
536 }
537 
540  return false;
542  return false;
543  return true;
544 }
545 
547  ArrayRef<DynamicAPInt> values) {
548  if (values.empty())
549  return;
550  assert(pos + values.size() <= getNumVars() &&
551  "invalid position or too many values");
552  // Setting x_j = p in sum_i a_i x_i + c is equivalent to adding p*a_j to the
553  // constant term and removing the var x_j. We do this for all the vars
554  // pos, pos + 1, ... pos + values.size() - 1.
555  unsigned constantColPos = getNumCols() - 1;
556  for (unsigned i = 0, numVals = values.size(); i < numVals; ++i)
557  inequalities.addToColumn(i + pos, constantColPos, values[i]);
558  for (unsigned i = 0, numVals = values.size(); i < numVals; ++i)
559  equalities.addToColumn(i + pos, constantColPos, values[i]);
560  removeVarRange(pos, pos + values.size());
561 }
562 
564  *this = other;
565 }
566 
567 // Searches for a constraint with a non-zero coefficient at `colIdx` in
568 // equality (isEq=true) or inequality (isEq=false) constraints.
569 // Returns true and sets row found in search in `rowIdx`, false otherwise.
570 bool IntegerRelation::findConstraintWithNonZeroAt(unsigned colIdx, bool isEq,
571  unsigned *rowIdx) const {
572  assert(colIdx < getNumCols() && "position out of bounds");
573  auto at = [&](unsigned rowIdx) -> DynamicAPInt {
574  return isEq ? atEq(rowIdx, colIdx) : atIneq(rowIdx, colIdx);
575  };
576  unsigned e = isEq ? getNumEqualities() : getNumInequalities();
577  for (*rowIdx = 0; *rowIdx < e; ++(*rowIdx)) {
578  if (at(*rowIdx) != 0) {
579  return true;
580  }
581  }
582  return false;
583 }
584 
586  for (unsigned i = 0, e = getNumEqualities(); i < e; ++i)
588  for (unsigned i = 0, e = getNumInequalities(); i < e; ++i)
590 }
591 
593  assert(hasConsistentState());
594  auto check = [&](bool isEq) -> bool {
595  unsigned numCols = getNumCols();
596  unsigned numRows = isEq ? getNumEqualities() : getNumInequalities();
597  for (unsigned i = 0, e = numRows; i < e; ++i) {
598  unsigned j;
599  for (j = 0; j < numCols - 1; ++j) {
600  DynamicAPInt v = isEq ? atEq(i, j) : atIneq(i, j);
601  // Skip rows with non-zero variable coefficients.
602  if (v != 0)
603  break;
604  }
605  if (j < numCols - 1) {
606  continue;
607  }
608  // Check validity of constant term at 'numCols - 1' w.r.t 'isEq'.
609  // Example invalid constraints include: '1 == 0' or '-1 >= 0'
610  DynamicAPInt v = isEq ? atEq(i, numCols - 1) : atIneq(i, numCols - 1);
611  if ((isEq && v != 0) || (!isEq && v < 0)) {
612  return true;
613  }
614  }
615  return false;
616  };
617  if (check(/*isEq=*/true))
618  return true;
619  return check(/*isEq=*/false);
620 }
621 
622 /// Eliminate variable from constraint at `rowIdx` based on coefficient at
623 /// pivotRow, pivotCol. Columns in range [elimColStart, pivotCol) will not be
624 /// updated as they have already been eliminated.
625 static void eliminateFromConstraint(IntegerRelation *constraints,
626  unsigned rowIdx, unsigned pivotRow,
627  unsigned pivotCol, unsigned elimColStart,
628  bool isEq) {
629  // Skip if equality 'rowIdx' if same as 'pivotRow'.
630  if (isEq && rowIdx == pivotRow)
631  return;
632  auto at = [&](unsigned i, unsigned j) -> DynamicAPInt {
633  return isEq ? constraints->atEq(i, j) : constraints->atIneq(i, j);
634  };
635  DynamicAPInt leadCoeff = at(rowIdx, pivotCol);
636  // Skip if leading coefficient at 'rowIdx' is already zero.
637  if (leadCoeff == 0)
638  return;
639  DynamicAPInt pivotCoeff = constraints->atEq(pivotRow, pivotCol);
640  int sign = (leadCoeff * pivotCoeff > 0) ? -1 : 1;
641  DynamicAPInt lcm = llvm::lcm(pivotCoeff, leadCoeff);
642  DynamicAPInt pivotMultiplier = sign * (lcm / abs(pivotCoeff));
643  DynamicAPInt rowMultiplier = lcm / abs(leadCoeff);
644 
645  unsigned numCols = constraints->getNumCols();
646  for (unsigned j = 0; j < numCols; ++j) {
647  // Skip updating column 'j' if it was just eliminated.
648  if (j >= elimColStart && j < pivotCol)
649  continue;
650  DynamicAPInt v = pivotMultiplier * constraints->atEq(pivotRow, j) +
651  rowMultiplier * at(rowIdx, j);
652  isEq ? constraints->atEq(rowIdx, j) = v
653  : constraints->atIneq(rowIdx, j) = v;
654  }
655 }
656 
657 /// Returns the position of the variable that has the minimum <number of lower
658 /// bounds> times <number of upper bounds> from the specified range of
659 /// variables [start, end). It is often best to eliminate in the increasing
660 /// order of these counts when doing Fourier-Motzkin elimination since FM adds
661 /// that many new constraints.
662 static unsigned getBestVarToEliminate(const IntegerRelation &cst,
663  unsigned start, unsigned end) {
664  assert(start < cst.getNumVars() && end < cst.getNumVars() + 1);
665 
666  auto getProductOfNumLowerUpperBounds = [&](unsigned pos) {
667  unsigned numLb = 0;
668  unsigned numUb = 0;
669  for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) {
670  if (cst.atIneq(r, pos) > 0) {
671  ++numLb;
672  } else if (cst.atIneq(r, pos) < 0) {
673  ++numUb;
674  }
675  }
676  return numLb * numUb;
677  };
678 
679  unsigned minLoc = start;
680  unsigned min = getProductOfNumLowerUpperBounds(start);
681  for (unsigned c = start + 1; c < end; c++) {
682  unsigned numLbUbProduct = getProductOfNumLowerUpperBounds(c);
683  if (numLbUbProduct < min) {
684  min = numLbUbProduct;
685  minLoc = c;
686  }
687  }
688  return minLoc;
689 }
690 
691 // Checks for emptiness of the set by eliminating variables successively and
692 // using the GCD test (on all equality constraints) and checking for trivially
693 // invalid constraints. Returns 'true' if the constraint system is found to be
694 // empty; false otherwise.
697  return true;
698 
699  IntegerRelation tmpCst(*this);
700 
701  // First, eliminate as many local variables as possible using equalities.
702  tmpCst.removeRedundantLocalVars();
703  if (tmpCst.isEmptyByGCDTest() || tmpCst.hasInvalidConstraint())
704  return true;
705 
706  // Eliminate as many variables as possible using Gaussian elimination.
707  unsigned currentPos = 0;
708  while (currentPos < tmpCst.getNumVars()) {
709  tmpCst.gaussianEliminateVars(currentPos, tmpCst.getNumVars());
710  ++currentPos;
711  // We check emptiness through trivial checks after eliminating each ID to
712  // detect emptiness early. Since the checks isEmptyByGCDTest() and
713  // hasInvalidConstraint() are linear time and single sweep on the constraint
714  // buffer, this appears reasonable - but can optimize in the future.
715  if (tmpCst.hasInvalidConstraint() || tmpCst.isEmptyByGCDTest())
716  return true;
717  }
718 
719  // Eliminate the remaining using FM.
720  for (unsigned i = 0, e = tmpCst.getNumVars(); i < e; i++) {
722  getBestVarToEliminate(tmpCst, 0, tmpCst.getNumVars()));
723  // Check for a constraint explosion. This rarely happens in practice, but
724  // this check exists as a safeguard against improperly constructed
725  // constraint systems or artificially created arbitrarily complex systems
726  // that aren't the intended use case for IntegerRelation. This is
727  // needed since FM has a worst case exponential complexity in theory.
728  if (tmpCst.getNumConstraints() >= kExplosionFactor * getNumVars()) {
729  LLVM_DEBUG(llvm::dbgs() << "FM constraint explosion detected\n");
730  return false;
731  }
732 
733  // FM wouldn't have modified the equalities in any way. So no need to again
734  // run GCD test. Check for trivial invalid constraints.
735  if (tmpCst.hasInvalidConstraint())
736  return true;
737  }
738  return false;
739 }
740 
743 }
744 
745 // Runs the GCD test on all equality constraints. Returns 'true' if this test
746 // fails on any equality. Returns 'false' otherwise.
747 // This test can be used to disprove the existence of a solution. If it returns
748 // true, no integer solution to the equality constraints can exist.
749 //
750 // GCD test definition:
751 //
752 // The equality constraint:
753 //
754 // c_1*x_1 + c_2*x_2 + ... + c_n*x_n = c_0
755 //
756 // has an integer solution iff:
757 //
758 // GCD of c_1, c_2, ..., c_n divides c_0.
760  assert(hasConsistentState());
761  unsigned numCols = getNumCols();
762  for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
763  DynamicAPInt gcd = abs(atEq(i, 0));
764  for (unsigned j = 1; j < numCols - 1; ++j) {
765  gcd = llvm::gcd(gcd, abs(atEq(i, j)));
766  }
767  DynamicAPInt v = abs(atEq(i, numCols - 1));
768  if (gcd > 0 && (v % gcd != 0)) {
769  return true;
770  }
771  }
772  return false;
773 }
774 
775 // Returns a matrix where each row is a vector along which the polytope is
776 // bounded. The span of the returned vectors is guaranteed to contain all
777 // such vectors. The returned vectors are NOT guaranteed to be linearly
778 // independent. This function should not be called on empty sets.
779 //
780 // It is sufficient to check the perpendiculars of the constraints, as the set
781 // of perpendiculars which are bounded must span all bounded directions.
783  // Note that it is necessary to add the equalities too (which the constructor
784  // does) even though we don't need to check if they are bounded; whether an
785  // inequality is bounded or not depends on what other constraints, including
786  // equalities, are present.
787  Simplex simplex(*this);
788 
789  assert(!simplex.isEmpty() && "It is not meaningful to ask whether a "
790  "direction is bounded in an empty set.");
791 
792  SmallVector<unsigned, 8> boundedIneqs;
793  // The constructor adds the inequalities to the simplex first, so this
794  // processes all the inequalities.
795  for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
796  if (simplex.isBoundedAlongConstraint(i))
797  boundedIneqs.emplace_back(i);
798  }
799 
800  // The direction vector is given by the coefficients and does not include the
801  // constant term, so the matrix has one fewer column.
802  unsigned dirsNumCols = getNumCols() - 1;
803  IntMatrix dirs(boundedIneqs.size() + getNumEqualities(), dirsNumCols);
804 
805  // Copy the bounded inequalities.
806  unsigned row = 0;
807  for (unsigned i : boundedIneqs) {
808  for (unsigned col = 0; col < dirsNumCols; ++col)
809  dirs(row, col) = atIneq(i, col);
810  ++row;
811  }
812 
813  // Copy the equalities. All the equalities' perpendiculars are bounded.
814  for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
815  for (unsigned col = 0; col < dirsNumCols; ++col)
816  dirs(row, col) = atEq(i, col);
817  ++row;
818  }
819 
820  return dirs;
821 }
822 
824 
825 /// Let this set be S. If S is bounded then we directly call into the GBR
826 /// sampling algorithm. Otherwise, there are some unbounded directions, i.e.,
827 /// vectors v such that S extends to infinity along v or -v. In this case we
828 /// use an algorithm described in the integer set library (isl) manual and used
829 /// by the isl_set_sample function in that library. The algorithm is:
830 ///
831 /// 1) Apply a unimodular transform T to S to obtain S*T, such that all
832 /// dimensions in which S*T is bounded lie in the linear span of a prefix of the
833 /// dimensions.
834 ///
835 /// 2) Construct a set B by removing all constraints that involve
836 /// the unbounded dimensions and then deleting the unbounded dimensions. Note
837 /// that B is a Bounded set.
838 ///
839 /// 3) Try to obtain a sample from B using the GBR sampling
840 /// algorithm. If no sample is found, return that S is empty.
841 ///
842 /// 4) Otherwise, substitute the obtained sample into S*T to obtain a set
843 /// C. C is a full-dimensional Cone and always contains a sample.
844 ///
845 /// 5) Obtain an integer sample from C.
846 ///
847 /// 6) Return T*v, where v is the concatenation of the samples from B and C.
848 ///
849 /// The following is a sketch of a proof that
850 /// a) If the algorithm returns empty, then S is empty.
851 /// b) If the algorithm returns a sample, it is a valid sample in S.
852 ///
853 /// The algorithm returns empty only if B is empty, in which case S*T is
854 /// certainly empty since B was obtained by removing constraints and then
855 /// deleting unconstrained dimensions from S*T. Since T is unimodular, a vector
856 /// v is in S*T iff T*v is in S. So in this case, since
857 /// S*T is empty, S is empty too.
858 ///
859 /// Otherwise, the algorithm substitutes the sample from B into S*T. All the
860 /// constraints of S*T that did not involve unbounded dimensions are satisfied
861 /// by this substitution. All dimensions in the linear span of the dimensions
862 /// outside the prefix are unbounded in S*T (step 1). Substituting values for
863 /// the bounded dimensions cannot make these dimensions bounded, and these are
864 /// the only remaining dimensions in C, so C is unbounded along every vector (in
865 /// the positive or negative direction, or both). C is hence a full-dimensional
866 /// cone and therefore always contains an integer point.
867 ///
868 /// Concatenating the samples from B and C gives a sample v in S*T, so the
869 /// returned sample T*v is a sample in S.
870 std::optional<SmallVector<DynamicAPInt, 8>>
872  // First, try the GCD test heuristic.
873  if (isEmptyByGCDTest())
874  return {};
875 
876  Simplex simplex(*this);
877  if (simplex.isEmpty())
878  return {};
879 
880  // For a bounded set, we directly call into the GBR sampling algorithm.
881  if (!simplex.isUnbounded())
882  return simplex.findIntegerSample();
883 
884  // The set is unbounded. We cannot directly use the GBR algorithm.
885  //
886  // m is a matrix containing, in each row, a vector in which S is
887  // bounded, such that the linear span of all these dimensions contains all
888  // bounded dimensions in S.
890  // In column echelon form, each row of m occupies only the first rank(m)
891  // columns and has zeros on the other columns. The transform T that brings S
892  // to column echelon form is unimodular as well, so this is a suitable
893  // transform to use in step 1 of the algorithm.
894  std::pair<unsigned, LinearTransform> result =
896  const LinearTransform &transform = result.second;
897  // 1) Apply T to S to obtain S*T.
898  IntegerRelation transformedSet = transform.applyTo(*this);
899 
900  // 2) Remove the unbounded dimensions and constraints involving them to
901  // obtain a bounded set.
902  IntegerRelation boundedSet(transformedSet);
903  unsigned numBoundedDims = result.first;
904  unsigned numUnboundedDims = getNumVars() - numBoundedDims;
905  removeConstraintsInvolvingVarRange(boundedSet, numBoundedDims,
906  numUnboundedDims);
907  boundedSet.removeVarRange(numBoundedDims, boundedSet.getNumVars());
908 
909  // 3) Try to obtain a sample from the bounded set.
910  std::optional<SmallVector<DynamicAPInt, 8>> boundedSample =
911  Simplex(boundedSet).findIntegerSample();
912  if (!boundedSample)
913  return {};
914  assert(boundedSet.containsPoint(*boundedSample) &&
915  "Simplex returned an invalid sample!");
916 
917  // 4) Substitute the values of the bounded dimensions into S*T to obtain a
918  // full-dimensional cone, which necessarily contains an integer sample.
919  transformedSet.setAndEliminate(0, *boundedSample);
920  IntegerRelation &cone = transformedSet;
921 
922  // 5) Obtain an integer sample from the cone.
923  //
924  // We shrink the cone such that for any rational point in the shrunken cone,
925  // rounding up each of the point's coordinates produces a point that still
926  // lies in the original cone.
927  //
928  // Rounding up a point x adds a number e_i in [0, 1) to each coordinate x_i.
929  // For each inequality sum_i a_i x_i + c >= 0 in the original cone, the
930  // shrunken cone will have the inequality tightened by some amount s, such
931  // that if x satisfies the shrunken cone's tightened inequality, then x + e
932  // satisfies the original inequality, i.e.,
933  //
934  // sum_i a_i x_i + c + s >= 0 implies sum_i a_i (x_i + e_i) + c >= 0
935  //
936  // for any e_i values in [0, 1). In fact, we will handle the slightly more
937  // general case where e_i can be in [0, 1]. For example, consider the
938  // inequality 2x_1 - 3x_2 - 7x_3 - 6 >= 0, and let x = (3, 0, 0). How low
939  // could the LHS go if we added a number in [0, 1] to each coordinate? The LHS
940  // is minimized when we add 1 to the x_i with negative coefficient a_i and
941  // keep the other x_i the same. In the example, we would get x = (3, 1, 1),
942  // changing the value of the LHS by -3 + -7 = -10.
943  //
944  // In general, the value of the LHS can change by at most the sum of the
945  // negative a_i, so we accomodate this by shifting the inequality by this
946  // amount for the shrunken cone.
947  for (unsigned i = 0, e = cone.getNumInequalities(); i < e; ++i) {
948  for (unsigned j = 0; j < cone.getNumVars(); ++j) {
949  DynamicAPInt coeff = cone.atIneq(i, j);
950  if (coeff < 0)
951  cone.atIneq(i, cone.getNumVars()) += coeff;
952  }
953  }
954 
955  // Obtain an integer sample in the cone by rounding up a rational point from
956  // the shrunken cone. Shrinking the cone amounts to shifting its apex
957  // "inwards" without changing its "shape"; the shrunken cone is still a
958  // full-dimensional cone and is hence non-empty.
959  Simplex shrunkenConeSimplex(cone);
960  assert(!shrunkenConeSimplex.isEmpty() && "Shrunken cone cannot be empty!");
961 
962  // The sample will always exist since the shrunken cone is non-empty.
963  SmallVector<Fraction, 8> shrunkenConeSample =
964  *shrunkenConeSimplex.getRationalSample();
965 
966  SmallVector<DynamicAPInt, 8> coneSample(
967  llvm::map_range(shrunkenConeSample, ceil));
968 
969  // 6) Return transform * concat(boundedSample, coneSample).
970  SmallVector<DynamicAPInt, 8> &sample = *boundedSample;
971  sample.append(coneSample.begin(), coneSample.end());
972  return transform.postMultiplyWithColumn(sample);
973 }
974 
975 /// Helper to evaluate an affine expression at a point.
976 /// The expression is a list of coefficients for the dimensions followed by the
977 /// constant term.
978 static DynamicAPInt valueAt(ArrayRef<DynamicAPInt> expr,
979  ArrayRef<DynamicAPInt> point) {
980  assert(expr.size() == 1 + point.size() &&
981  "Dimensionalities of point and expression don't match!");
982  DynamicAPInt value = expr.back();
983  for (unsigned i = 0; i < point.size(); ++i)
984  value += expr[i] * point[i];
985  return value;
986 }
987 
988 /// A point satisfies an equality iff the value of the equality at the
989 /// expression is zero, and it satisfies an inequality iff the value of the
990 /// inequality at that point is non-negative.
992  for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
993  if (valueAt(getEquality(i), point) != 0)
994  return false;
995  }
996  for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
997  if (valueAt(getInequality(i), point) < 0)
998  return false;
999  }
1000  return true;
1001 }
1002 
1003 /// Just substitute the values given and check if an integer sample exists for
1004 /// the local vars.
1005 ///
1006 /// TODO: this could be made more efficient by handling divisions separately.
1007 /// Instead of finding an integer sample over all the locals, we can first
1008 /// compute the values of the locals that have division representations and
1009 /// only use the integer emptiness check for the locals that don't have this.
1010 /// Handling this correctly requires ordering the divs, though.
1011 std::optional<SmallVector<DynamicAPInt, 8>>
1013  assert(point.size() == getNumVars() - getNumLocalVars() &&
1014  "Point should contain all vars except locals!");
1016  "This function depends on locals being stored last!");
1017  IntegerRelation copy = *this;
1018  copy.setAndEliminate(0, point);
1019  return copy.findIntegerSample();
1020 }
1021 
1023 IntegerRelation::getLocalReprs(std::vector<MaybeLocalRepr> *repr) const {
1024  SmallVector<bool, 8> foundRepr(getNumVars(), false);
1025  for (unsigned i = 0, e = getNumDimAndSymbolVars(); i < e; ++i)
1026  foundRepr[i] = true;
1027 
1028  unsigned localOffset = getVarKindOffset(VarKind::Local);
1030  bool changed;
1031  do {
1032  // Each time changed is true, at end of this iteration, one or more local
1033  // vars have been detected as floor divs.
1034  changed = false;
1035  for (unsigned i = 0, e = getNumLocalVars(); i < e; ++i) {
1036  if (!foundRepr[i + localOffset]) {
1037  MaybeLocalRepr res =
1038  computeSingleVarRepr(*this, foundRepr, localOffset + i,
1039  divs.getDividend(i), divs.getDenom(i));
1040  if (!res) {
1041  // No representation was found, so clear the representation and
1042  // continue.
1043  divs.clearRepr(i);
1044  continue;
1045  }
1046  foundRepr[localOffset + i] = true;
1047  if (repr)
1048  (*repr)[i] = res;
1049  changed = true;
1050  }
1051  }
1052  } while (changed);
1053 
1054  return divs;
1055 }
1056 
1057 /// Tightens inequalities given that we are dealing with integer spaces. This is
1058 /// analogous to the GCD test but applied to inequalities. The constant term can
1059 /// be reduced to the preceding multiple of the GCD of the coefficients, i.e.,
1060 /// 64*i - 100 >= 0 => 64*i - 128 >= 0 (since 'i' is an integer). This is a
1061 /// fast method - linear in the number of coefficients.
1062 // Example on how this affects practical cases: consider the scenario:
1063 // 64*i >= 100, j = 64*i; without a tightening, elimination of i would yield
1064 // j >= 100 instead of the tighter (exact) j >= 128.
1066  unsigned numCols = getNumCols();
1067  for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
1068  // Normalize the constraint and tighten the constant term by the GCD.
1069  DynamicAPInt gcd = inequalities.normalizeRow(i, getNumCols() - 1);
1070  if (gcd > 1)
1071  atIneq(i, numCols - 1) = floorDiv(atIneq(i, numCols - 1), gcd);
1072  }
1073 }
1074 
1075 // Eliminates all variable variables in column range [posStart, posLimit).
1076 // Returns the number of variables eliminated.
1077 unsigned IntegerRelation::gaussianEliminateVars(unsigned posStart,
1078  unsigned posLimit) {
1079  // Return if variable positions to eliminate are out of range.
1080  assert(posLimit <= getNumVars());
1081  assert(hasConsistentState());
1082 
1083  if (posStart >= posLimit)
1084  return 0;
1085 
1087 
1088  unsigned pivotCol = 0;
1089  for (pivotCol = posStart; pivotCol < posLimit; ++pivotCol) {
1090  // Find a row which has a non-zero coefficient in column 'j'.
1091  unsigned pivotRow;
1092  if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/true, &pivotRow)) {
1093  // No pivot row in equalities with non-zero at 'pivotCol'.
1094  if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/false, &pivotRow)) {
1095  // If inequalities are also non-zero in 'pivotCol', it can be
1096  // eliminated.
1097  continue;
1098  }
1099  break;
1100  }
1101 
1102  // Eliminate variable at 'pivotCol' from each equality row.
1103  for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
1104  eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart,
1105  /*isEq=*/true);
1107  }
1108 
1109  // Eliminate variable at 'pivotCol' from each inequality row.
1110  for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
1111  eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart,
1112  /*isEq=*/false);
1114  }
1115  removeEquality(pivotRow);
1117  }
1118  // Update position limit based on number eliminated.
1119  posLimit = pivotCol;
1120  // Remove eliminated columns from all constraints.
1121  removeVarRange(posStart, posLimit);
1122  return posLimit - posStart;
1123 }
1124 
1127  unsigned firstVar = 0, vars = getNumVars();
1128  unsigned nowDone, eqs, pivotRow;
1129  for (nowDone = 0, eqs = getNumEqualities(); nowDone < eqs; ++nowDone) {
1130  // Finds the first non-empty column.
1131  for (; firstVar < vars; ++firstVar) {
1132  if (!findConstraintWithNonZeroAt(firstVar, true, &pivotRow))
1133  continue;
1134  break;
1135  }
1136  // The matrix has been normalized to row echelon form.
1137  if (firstVar >= vars)
1138  break;
1139 
1140  // The first pivot row found is below where it should currently be placed.
1141  if (pivotRow > nowDone) {
1142  equalities.swapRows(pivotRow, nowDone);
1143  pivotRow = nowDone;
1144  }
1145 
1146  // Normalize all lower equations and all inequalities.
1147  for (unsigned i = nowDone + 1; i < eqs; ++i) {
1148  eliminateFromConstraint(this, i, pivotRow, firstVar, 0, true);
1150  }
1151  for (unsigned i = 0, ineqs = getNumInequalities(); i < ineqs; ++i) {
1152  eliminateFromConstraint(this, i, pivotRow, firstVar, 0, false);
1154  }
1156  }
1157 
1158  // No redundant rows.
1159  if (nowDone == eqs)
1160  return false;
1161 
1162  // Check to see if the redundant rows constant is zero, a non-zero value means
1163  // the set is empty.
1164  for (unsigned i = nowDone; i < eqs; ++i) {
1165  if (atEq(i, vars) == 0)
1166  continue;
1167 
1168  *this = getEmpty(getSpace());
1169  return true;
1170  }
1171  // Eliminate rows that are confined to be all zeros.
1172  removeEqualityRange(nowDone, eqs);
1173  return true;
1174 }
1175 
1176 // A more complex check to eliminate redundant inequalities. Uses FourierMotzkin
1177 // to check if a constraint is redundant.
1179  SmallVector<bool, 32> redun(getNumInequalities(), false);
1180  // To check if an inequality is redundant, we replace the inequality by its
1181  // complement (for eg., i - 1 >= 0 by i <= 0), and check if the resulting
1182  // system is empty. If it is, the inequality is redundant.
1183  IntegerRelation tmpCst(*this);
1184  for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
1185  // Change the inequality to its complement.
1186  tmpCst.inequalities.negateRow(r);
1187  --tmpCst.atIneq(r, tmpCst.getNumCols() - 1);
1188  if (tmpCst.isEmpty()) {
1189  redun[r] = true;
1190  // Zero fill the redundant inequality.
1191  inequalities.fillRow(r, /*value=*/0);
1192  tmpCst.inequalities.fillRow(r, /*value=*/0);
1193  } else {
1194  // Reverse the change (to avoid recreating tmpCst each time).
1195  ++tmpCst.atIneq(r, tmpCst.getNumCols() - 1);
1196  tmpCst.inequalities.negateRow(r);
1197  }
1198  }
1199 
1200  unsigned pos = 0;
1201  for (unsigned r = 0, e = getNumInequalities(); r < e; ++r) {
1202  if (!redun[r])
1203  inequalities.copyRow(r, pos++);
1204  }
1206 }
1207 
1208 // A more complex check to eliminate redundant inequalities and equalities. Uses
1209 // Simplex to check if a constraint is redundant.
1211  // First, we run gcdTightenInequalities. This allows us to catch some
1212  // constraints which are not redundant when considering rational solutions
1213  // but are redundant in terms of integer solutions.
1215  Simplex simplex(*this);
1216  simplex.detectRedundant();
1217 
1218  unsigned pos = 0;
1219  unsigned numIneqs = getNumInequalities();
1220  // Scan to get rid of all inequalities marked redundant, in-place. In Simplex,
1221  // the first constraints added are the inequalities.
1222  for (unsigned r = 0; r < numIneqs; r++) {
1223  if (!simplex.isMarkedRedundant(r))
1224  inequalities.copyRow(r, pos++);
1225  }
1227 
1228  // Scan to get rid of all equalities marked redundant, in-place. In Simplex,
1229  // after the inequalities, a pair of constraints for each equality is added.
1230  // An equality is redundant if both the inequalities in its pair are
1231  // redundant.
1232  pos = 0;
1233  for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
1234  if (!(simplex.isMarkedRedundant(numIneqs + 2 * r) &&
1235  simplex.isMarkedRedundant(numIneqs + 2 * r + 1)))
1236  equalities.copyRow(r, pos++);
1237  }
1239 }
1240 
1241 std::optional<DynamicAPInt> IntegerRelation::computeVolume() const {
1242  assert(getNumSymbolVars() == 0 && "Symbols are not yet supported!");
1243 
1244  Simplex simplex(*this);
1245  // If the polytope is rationally empty, there are certainly no integer
1246  // points.
1247  if (simplex.isEmpty())
1248  return DynamicAPInt(0);
1249 
1250  // Just find the maximum and minimum integer value of each non-local var
1251  // separately, thus finding the number of integer values each such var can
1252  // take. Multiplying these together gives a valid overapproximation of the
1253  // number of integer points in the relation. The result this gives is
1254  // equivalent to projecting (rationally) the relation onto its non-local vars
1255  // and returning the number of integer points in a minimal axis-parallel
1256  // hyperrectangular overapproximation of that.
1257  //
1258  // We also handle the special case where one dimension is unbounded and
1259  // another dimension can take no integer values. In this case, the volume is
1260  // zero.
1261  //
1262  // If there is no such empty dimension, if any dimension is unbounded we
1263  // just return the result as unbounded.
1264  DynamicAPInt count(1);
1266  bool hasUnboundedVar = false;
1267  for (unsigned i = 0, e = getNumDimAndSymbolVars(); i < e; ++i) {
1268  dim[i] = 1;
1269  auto [min, max] = simplex.computeIntegerBounds(dim);
1270  dim[i] = 0;
1271 
1272  assert((!min.isEmpty() && !max.isEmpty()) &&
1273  "Polytope should be rationally non-empty!");
1274 
1275  // One of the dimensions is unbounded. Note this fact. We will return
1276  // unbounded if none of the other dimensions makes the volume zero.
1277  if (min.isUnbounded() || max.isUnbounded()) {
1278  hasUnboundedVar = true;
1279  continue;
1280  }
1281 
1282  // In this case there are no valid integer points and the volume is
1283  // definitely zero.
1284  if (min.getBoundedOptimum() > max.getBoundedOptimum())
1285  return DynamicAPInt(0);
1286 
1287  count *= (*max - *min + 1);
1288  }
1289 
1290  if (count == 0)
1291  return DynamicAPInt(0);
1292  if (hasUnboundedVar)
1293  return {};
1294  return count;
1295 }
1296 
1297 void IntegerRelation::eliminateRedundantLocalVar(unsigned posA, unsigned posB) {
1298  assert(posA < getNumLocalVars() && "Invalid local var position");
1299  assert(posB < getNumLocalVars() && "Invalid local var position");
1300 
1301  unsigned localOffset = getVarKindOffset(VarKind::Local);
1302  posA += localOffset;
1303  posB += localOffset;
1304  inequalities.addToColumn(posB, posA, 1);
1305  equalities.addToColumn(posB, posA, 1);
1306  removeVar(posB);
1307 }
1308 
1309 /// mergeAndAlignSymbols's implementation can be broken down into two steps:
1310 /// 1. Merge and align identifiers into `other` from `this. If an identifier
1311 /// from `this` exists in `other` then we align it. Otherwise, we assume it is a
1312 /// new identifier and insert it into `other` in the same position as `this`.
1313 /// 2. Add identifiers that are in `other` but not `this to `this`.
1315  assert(space.isUsingIds() && other.space.isUsingIds() &&
1316  "both relations need to have identifers to merge and align");
1317 
1318  unsigned i = 0;
1319  for (const Identifier identifier : space.getIds(VarKind::Symbol)) {
1320  // Search in `other` starting at position `i` since the left of `i` is
1321  // aligned.
1322  const Identifier *findBegin =
1323  other.space.getIds(VarKind::Symbol).begin() + i;
1324  const Identifier *findEnd = other.space.getIds(VarKind::Symbol).end();
1325  const Identifier *itr = std::find(findBegin, findEnd, identifier);
1326  if (itr != findEnd) {
1327  other.swapVar(other.getVarKindOffset(VarKind::Symbol) + i,
1328  other.getVarKindOffset(VarKind::Symbol) + i +
1329  std::distance(findBegin, itr));
1330  } else {
1331  other.insertVar(VarKind::Symbol, i);
1332  other.space.setId(VarKind::Symbol, i, identifier);
1333  }
1334  ++i;
1335  }
1336 
1337  for (unsigned e = other.getNumVarKind(VarKind::Symbol); i < e; ++i) {
1340  }
1341 }
1342 
1343 /// Adds additional local ids to the sets such that they both have the union
1344 /// of the local ids in each set, without changing the set of points that
1345 /// lie in `this` and `other`.
1346 ///
1347 /// To detect local ids that always take the same value, each local id is
1348 /// represented as a floordiv with constant denominator in terms of other ids.
1349 /// After extracting these divisions, local ids in `other` with the same
1350 /// division representation as some other local id in any set are considered
1351 /// duplicate and are merged.
1352 ///
1353 /// It is possible that division representation for some local id cannot be
1354 /// obtained, and thus these local ids are not considered for detecting
1355 /// duplicates.
1357  IntegerRelation &relA = *this;
1358  IntegerRelation &relB = other;
1359 
1360  unsigned oldALocals = relA.getNumLocalVars();
1361 
1362  // Merge function that merges the local variables in both sets by treating
1363  // them as the same variable.
1364  auto merge = [&relA, &relB, oldALocals](unsigned i, unsigned j) -> bool {
1365  // We only merge from local at pos j to local at pos i, where j > i.
1366  if (i >= j)
1367  return false;
1368 
1369  // If i < oldALocals, we are trying to merge duplicate divs. Since we do not
1370  // want to merge duplicates in A, we ignore this call.
1371  if (j < oldALocals)
1372  return false;
1373 
1374  // Merge local at pos j into local at position i.
1375  relA.eliminateRedundantLocalVar(i, j);
1376  relB.eliminateRedundantLocalVar(i, j);
1377  return true;
1378  };
1379 
1380  presburger::mergeLocalVars(*this, other, merge);
1381 
1382  // Since we do not remove duplicate divisions in relA, this is guranteed to be
1383  // non-negative.
1384  return relA.getNumLocalVars() - oldALocals;
1385 }
1386 
1388  return getLocalReprs().hasAllReprs();
1389 }
1390 
1392  DivisionRepr divs = getLocalReprs();
1393  auto merge = [this](unsigned i, unsigned j) -> bool {
1395  return true;
1396  };
1397  divs.removeDuplicateDivs(merge);
1398 }
1399 
1401  bool changed = true;
1402  // Repeat until we reach a fixed point.
1403  while (changed) {
1404  if (isObviouslyEmpty())
1405  return;
1406  changed = false;
1408  changed |= gaussianEliminate();
1409  changed |= removeDuplicateConstraints();
1410  }
1411  // Current set is not empty.
1412 }
1413 
1414 /// Removes local variables using equalities. Each equality is checked if it
1415 /// can be reduced to the form: `e = affine-expr`, where `e` is a local
1416 /// variable and `affine-expr` is an affine expression not containing `e`.
1417 /// If an equality satisfies this form, the local variable is replaced in
1418 /// each constraint and then removed. The equality used to replace this local
1419 /// variable is also removed.
1421  // Normalize the equality constraints to reduce coefficients of local
1422  // variables to 1 wherever possible.
1423  for (unsigned i = 0, e = getNumEqualities(); i < e; ++i)
1425 
1426  while (true) {
1427  unsigned i, e, j, f;
1428  for (i = 0, e = getNumEqualities(); i < e; ++i) {
1429  // Find a local variable to eliminate using ith equality.
1430  for (j = getNumDimAndSymbolVars(), f = getNumVars(); j < f; ++j)
1431  if (abs(atEq(i, j)) == 1)
1432  break;
1433 
1434  // Local variable can be eliminated using ith equality.
1435  if (j < f)
1436  break;
1437  }
1438 
1439  // No equality can be used to eliminate a local variable.
1440  if (i == e)
1441  break;
1442 
1443  // Use the ith equality to simplify other equalities. If any changes
1444  // are made to an equality constraint, it is normalized by GCD.
1445  for (unsigned k = 0, t = getNumEqualities(); k < t; ++k) {
1446  if (atEq(k, j) != 0) {
1447  eliminateFromConstraint(this, k, i, j, j, /*isEq=*/true);
1449  }
1450  }
1451 
1452  // Use the ith equality to simplify inequalities.
1453  for (unsigned k = 0, t = getNumInequalities(); k < t; ++k)
1454  eliminateFromConstraint(this, k, i, j, j, /*isEq=*/false);
1455 
1456  // Remove the ith equality and the found local variable.
1457  removeVar(j);
1458  removeEquality(i);
1459  }
1460 }
1461 
1462 void IntegerRelation::convertVarKind(VarKind srcKind, unsigned varStart,
1463  unsigned varLimit, VarKind dstKind,
1464  unsigned pos) {
1465  assert(varLimit <= getNumVarKind(srcKind) && "invalid id range");
1466 
1467  if (varStart >= varLimit)
1468  return;
1469 
1470  unsigned srcOffset = getVarKindOffset(srcKind);
1471  unsigned dstOffset = getVarKindOffset(dstKind);
1472  unsigned convertCount = varLimit - varStart;
1473  int forwardMoveOffset = dstOffset > srcOffset ? -convertCount : 0;
1474 
1475  equalities.moveColumns(srcOffset + varStart, convertCount,
1476  dstOffset + pos + forwardMoveOffset);
1477  inequalities.moveColumns(srcOffset + varStart, convertCount,
1478  dstOffset + pos + forwardMoveOffset);
1479 
1480  space.convertVarKind(srcKind, varStart, varLimit - varStart, dstKind, pos);
1481 }
1482 
1483 void IntegerRelation::addBound(BoundType type, unsigned pos,
1484  const DynamicAPInt &value) {
1485  assert(pos < getNumCols());
1486  if (type == BoundType::EQ) {
1487  unsigned row = equalities.appendExtraRow();
1488  equalities(row, pos) = 1;
1489  equalities(row, getNumCols() - 1) = -value;
1490  } else {
1491  unsigned row = inequalities.appendExtraRow();
1492  inequalities(row, pos) = type == BoundType::LB ? 1 : -1;
1493  inequalities(row, getNumCols() - 1) =
1494  type == BoundType::LB ? -value : value;
1495  }
1496 }
1497 
1499  const DynamicAPInt &value) {
1500  assert(type != BoundType::EQ && "EQ not implemented");
1501  assert(expr.size() == getNumCols());
1502  unsigned row = inequalities.appendExtraRow();
1503  for (unsigned i = 0, e = expr.size(); i < e; ++i)
1504  inequalities(row, i) = type == BoundType::LB ? expr[i] : -expr[i];
1506  type == BoundType::LB ? -value : value;
1507 }
1508 
1509 /// Adds a new local variable as the floordiv of an affine function of other
1510 /// variables, the coefficients of which are provided in 'dividend' and with
1511 /// respect to a positive constant 'divisor'. Two constraints are added to the
1512 /// system to capture equivalence with the floordiv.
1513 /// q = expr floordiv c <=> c*q <= expr <= c*q + c - 1.
1515  const DynamicAPInt &divisor) {
1516  assert(dividend.size() == getNumCols() && "incorrect dividend size");
1517  assert(divisor > 0 && "positive divisor expected");
1518 
1520 
1521  SmallVector<DynamicAPInt, 8> dividendCopy(dividend);
1522  dividendCopy.insert(dividendCopy.end() - 1, DynamicAPInt(0));
1523  addInequality(
1524  getDivLowerBound(dividendCopy, divisor, dividendCopy.size() - 2));
1525  addInequality(
1526  getDivUpperBound(dividendCopy, divisor, dividendCopy.size() - 2));
1527 }
1528 
1529 /// Finds an equality that equates the specified variable to a constant.
1530 /// Returns the position of the equality row. If 'symbolic' is set to true,
1531 /// symbols are also treated like a constant, i.e., an affine function of the
1532 /// symbols is also treated like a constant. Returns -1 if such an equality
1533 /// could not be found.
1534 static int findEqualityToConstant(const IntegerRelation &cst, unsigned pos,
1535  bool symbolic = false) {
1536  assert(pos < cst.getNumVars() && "invalid position");
1537  for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) {
1538  DynamicAPInt v = cst.atEq(r, pos);
1539  if (v * v != 1)
1540  continue;
1541  unsigned c;
1542  unsigned f = symbolic ? cst.getNumDimVars() : cst.getNumVars();
1543  // This checks for zeros in all positions other than 'pos' in [0, f)
1544  for (c = 0; c < f; c++) {
1545  if (c == pos)
1546  continue;
1547  if (cst.atEq(r, c) != 0) {
1548  // Dependent on another variable.
1549  break;
1550  }
1551  }
1552  if (c == f)
1553  // Equality is free of other variables.
1554  return r;
1555  }
1556  return -1;
1557 }
1558 
1559 LogicalResult IntegerRelation::constantFoldVar(unsigned pos) {
1560  assert(pos < getNumVars() && "invalid position");
1561  int rowIdx;
1562  if ((rowIdx = findEqualityToConstant(*this, pos)) == -1)
1563  return failure();
1564 
1565  // atEq(rowIdx, pos) is either -1 or 1.
1566  assert(atEq(rowIdx, pos) * atEq(rowIdx, pos) == 1);
1567  DynamicAPInt constVal = -atEq(rowIdx, getNumCols() - 1) / atEq(rowIdx, pos);
1568  setAndEliminate(pos, constVal);
1569  return success();
1570 }
1571 
1572 void IntegerRelation::constantFoldVarRange(unsigned pos, unsigned num) {
1573  for (unsigned s = pos, t = pos, e = pos + num; s < e; s++) {
1574  if (constantFoldVar(t).failed())
1575  t++;
1576  }
1577 }
1578 
1579 /// Returns a non-negative constant bound on the extent (upper bound - lower
1580 /// bound) of the specified variable if it is found to be a constant; returns
1581 /// std::nullopt if it's not a constant. This methods treats symbolic variables
1582 /// specially, i.e., it looks for constant differences between affine
1583 /// expressions involving only the symbolic variables. See comments at function
1584 /// definition for example. 'lb', if provided, is set to the lower bound
1585 /// associated with the constant difference. Note that 'lb' is purely symbolic
1586 /// and thus will contain the coefficients of the symbolic variables and the
1587 /// constant coefficient.
1588 // Egs: 0 <= i <= 15, return 16.
1589 // s0 + 2 <= i <= s0 + 17, returns 16. (s0 has to be a symbol)
1590 // s0 + s1 + 16 <= d0 <= s0 + s1 + 31, returns 16.
1591 // s0 - 7 <= 8*j <= s0 returns 1 with lb = s0, lbDivisor = 8 (since lb =
1592 // ceil(s0 - 7 / 8) = floor(s0 / 8)).
1594  unsigned pos, SmallVectorImpl<DynamicAPInt> *lb,
1595  DynamicAPInt *boundFloorDivisor, SmallVectorImpl<DynamicAPInt> *ub,
1596  unsigned *minLbPos, unsigned *minUbPos) const {
1597  assert(pos < getNumDimVars() && "Invalid variable position");
1598 
1599  // Find an equality for 'pos'^th variable that equates it to some function
1600  // of the symbolic variables (+ constant).
1601  int eqPos = findEqualityToConstant(*this, pos, /*symbolic=*/true);
1602  if (eqPos != -1) {
1603  auto eq = getEquality(eqPos);
1604  // If the equality involves a local var, punt for now.
1605  // TODO: this can be handled in the future by using the explicit
1606  // representation of the local vars.
1607  if (!std::all_of(eq.begin() + getNumDimAndSymbolVars(), eq.end() - 1,
1608  [](const DynamicAPInt &coeff) { return coeff == 0; }))
1609  return std::nullopt;
1610 
1611  // This variable can only take a single value.
1612  if (lb) {
1613  // Set lb to that symbolic value.
1614  lb->resize(getNumSymbolVars() + 1);
1615  if (ub)
1616  ub->resize(getNumSymbolVars() + 1);
1617  for (unsigned c = 0, f = getNumSymbolVars() + 1; c < f; c++) {
1618  DynamicAPInt v = atEq(eqPos, pos);
1619  // atEq(eqRow, pos) is either -1 or 1.
1620  assert(v * v == 1);
1621  (*lb)[c] = v < 0 ? atEq(eqPos, getNumDimVars() + c) / -v
1622  : -atEq(eqPos, getNumDimVars() + c) / v;
1623  // Since this is an equality, ub = lb.
1624  if (ub)
1625  (*ub)[c] = (*lb)[c];
1626  }
1627  assert(boundFloorDivisor &&
1628  "both lb and divisor or none should be provided");
1629  *boundFloorDivisor = 1;
1630  }
1631  if (minLbPos)
1632  *minLbPos = eqPos;
1633  if (minUbPos)
1634  *minUbPos = eqPos;
1635  return DynamicAPInt(1);
1636  }
1637 
1638  // Check if the variable appears at all in any of the inequalities.
1639  unsigned r, e;
1640  for (r = 0, e = getNumInequalities(); r < e; r++) {
1641  if (atIneq(r, pos) != 0)
1642  break;
1643  }
1644  if (r == e)
1645  // If it doesn't, there isn't a bound on it.
1646  return std::nullopt;
1647 
1648  // Positions of constraints that are lower/upper bounds on the variable.
1649  SmallVector<unsigned, 4> lbIndices, ubIndices;
1650 
1651  // Gather all symbolic lower bounds and upper bounds of the variable, i.e.,
1652  // the bounds can only involve symbolic (and local) variables. Since the
1653  // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower
1654  // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1.
1655  getLowerAndUpperBoundIndices(pos, &lbIndices, &ubIndices,
1656  /*eqIndices=*/nullptr, /*offset=*/0,
1657  /*num=*/getNumDimVars());
1658 
1659  std::optional<DynamicAPInt> minDiff;
1660  unsigned minLbPosition = 0, minUbPosition = 0;
1661  for (auto ubPos : ubIndices) {
1662  for (auto lbPos : lbIndices) {
1663  // Look for a lower bound and an upper bound that only differ by a
1664  // constant, i.e., pairs of the form 0 <= c_pos - f(c_i's) <= diffConst.
1665  // For example, if ii is the pos^th variable, we are looking for
1666  // constraints like ii >= i, ii <= ii + 50, 50 being the difference. The
1667  // minimum among all such constant differences is kept since that's the
1668  // constant bounding the extent of the pos^th variable.
1669  unsigned j, e;
1670  for (j = 0, e = getNumCols() - 1; j < e; j++)
1671  if (atIneq(ubPos, j) != -atIneq(lbPos, j)) {
1672  break;
1673  }
1674  if (j < getNumCols() - 1)
1675  continue;
1676  DynamicAPInt diff = ceilDiv(atIneq(ubPos, getNumCols() - 1) +
1677  atIneq(lbPos, getNumCols() - 1) + 1,
1678  atIneq(lbPos, pos));
1679  // This bound is non-negative by definition.
1680  diff = std::max<DynamicAPInt>(diff, DynamicAPInt(0));
1681  if (minDiff == std::nullopt || diff < minDiff) {
1682  minDiff = diff;
1683  minLbPosition = lbPos;
1684  minUbPosition = ubPos;
1685  }
1686  }
1687  }
1688  if (lb && minDiff) {
1689  // Set lb to the symbolic lower bound.
1690  lb->resize(getNumSymbolVars() + 1);
1691  if (ub)
1692  ub->resize(getNumSymbolVars() + 1);
1693  // The lower bound is the ceildiv of the lb constraint over the coefficient
1694  // of the variable at 'pos'. We express the ceildiv equivalently as a floor
1695  // for uniformity. For eg., if the lower bound constraint was: 32*d0 - N +
1696  // 31 >= 0, the lower bound for d0 is ceil(N - 31, 32), i.e., floor(N, 32).
1697  *boundFloorDivisor = atIneq(minLbPosition, pos);
1698  assert(*boundFloorDivisor == -atIneq(minUbPosition, pos));
1699  for (unsigned c = 0, e = getNumSymbolVars() + 1; c < e; c++) {
1700  (*lb)[c] = -atIneq(minLbPosition, getNumDimVars() + c);
1701  }
1702  if (ub) {
1703  for (unsigned c = 0, e = getNumSymbolVars() + 1; c < e; c++)
1704  (*ub)[c] = atIneq(minUbPosition, getNumDimVars() + c);
1705  }
1706  // The lower bound leads to a ceildiv while the upper bound is a floordiv
1707  // whenever the coefficient at pos != 1. ceildiv (val / d) = floordiv (val +
1708  // d - 1 / d); hence, the addition of 'atIneq(minLbPosition, pos) - 1' to
1709  // the constant term for the lower bound.
1710  (*lb)[getNumSymbolVars()] += atIneq(minLbPosition, pos) - 1;
1711  }
1712  if (minLbPos)
1713  *minLbPos = minLbPosition;
1714  if (minUbPos)
1715  *minUbPos = minUbPosition;
1716  return minDiff;
1717 }
1718 
1719 template <bool isLower>
1720 std::optional<DynamicAPInt>
1722  assert(pos < getNumVars() && "invalid position");
1723  // Project to 'pos'.
1724  projectOut(0, pos);
1725  projectOut(1, getNumVars() - 1);
1726  // Check if there's an equality equating the '0'^th variable to a constant.
1727  int eqRowIdx = findEqualityToConstant(*this, 0, /*symbolic=*/false);
1728  if (eqRowIdx != -1)
1729  // atEq(rowIdx, 0) is either -1 or 1.
1730  return -atEq(eqRowIdx, getNumCols() - 1) / atEq(eqRowIdx, 0);
1731 
1732  // Check if the variable appears at all in any of the inequalities.
1733  unsigned r, e;
1734  for (r = 0, e = getNumInequalities(); r < e; r++) {
1735  if (atIneq(r, 0) != 0)
1736  break;
1737  }
1738  if (r == e)
1739  // If it doesn't, there isn't a bound on it.
1740  return std::nullopt;
1741 
1742  std::optional<DynamicAPInt> minOrMaxConst;
1743 
1744  // Take the max across all const lower bounds (or min across all constant
1745  // upper bounds).
1746  for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
1747  if (isLower) {
1748  if (atIneq(r, 0) <= 0)
1749  // Not a lower bound.
1750  continue;
1751  } else if (atIneq(r, 0) >= 0) {
1752  // Not an upper bound.
1753  continue;
1754  }
1755  unsigned c, f;
1756  for (c = 0, f = getNumCols() - 1; c < f; c++)
1757  if (c != 0 && atIneq(r, c) != 0)
1758  break;
1759  if (c < getNumCols() - 1)
1760  // Not a constant bound.
1761  continue;
1762 
1763  DynamicAPInt boundConst =
1764  isLower ? ceilDiv(-atIneq(r, getNumCols() - 1), atIneq(r, 0))
1765  : floorDiv(atIneq(r, getNumCols() - 1), -atIneq(r, 0));
1766  if (isLower) {
1767  if (minOrMaxConst == std::nullopt || boundConst > minOrMaxConst)
1768  minOrMaxConst = boundConst;
1769  } else {
1770  if (minOrMaxConst == std::nullopt || boundConst < minOrMaxConst)
1771  minOrMaxConst = boundConst;
1772  }
1773  }
1774  return minOrMaxConst;
1775 }
1776 
1777 std::optional<DynamicAPInt>
1779  if (type == BoundType::LB)
1780  return IntegerRelation(*this)
1781  .computeConstantLowerOrUpperBound</*isLower=*/true>(pos);
1782  if (type == BoundType::UB)
1783  return IntegerRelation(*this)
1784  .computeConstantLowerOrUpperBound</*isLower=*/false>(pos);
1785 
1786  assert(type == BoundType::EQ && "expected EQ");
1787  std::optional<DynamicAPInt> lb =
1788  IntegerRelation(*this).computeConstantLowerOrUpperBound</*isLower=*/true>(
1789  pos);
1790  std::optional<DynamicAPInt> ub =
1791  IntegerRelation(*this)
1792  .computeConstantLowerOrUpperBound</*isLower=*/false>(pos);
1793  return (lb && ub && *lb == *ub) ? std::optional<DynamicAPInt>(*ub)
1794  : std::nullopt;
1795 }
1796 
1797 // A simple (naive and conservative) check for hyper-rectangularity.
1798 bool IntegerRelation::isHyperRectangular(unsigned pos, unsigned num) const {
1799  assert(pos < getNumCols() - 1);
1800  // Check for two non-zero coefficients in the range [pos, pos + sum).
1801  for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
1802  unsigned sum = 0;
1803  for (unsigned c = pos; c < pos + num; c++) {
1804  if (atIneq(r, c) != 0)
1805  sum++;
1806  }
1807  if (sum > 1)
1808  return false;
1809  }
1810  for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
1811  unsigned sum = 0;
1812  for (unsigned c = pos; c < pos + num; c++) {
1813  if (atEq(r, c) != 0)
1814  sum++;
1815  }
1816  if (sum > 1)
1817  return false;
1818  }
1819  return true;
1820 }
1821 
1822 /// Removes duplicate constraints, trivially true constraints, and constraints
1823 /// that can be detected as redundant as a result of differing only in their
1824 /// constant term part. A constraint of the form <non-negative constant> >= 0 is
1825 /// considered trivially true.
1826 // Uses a DenseSet to hash and detect duplicates followed by a linear scan to
1827 // remove duplicates in place.
1831 
1832  // A map used to detect redundancy stemming from constraints that only differ
1833  // in their constant term. The value stored is <row position, const term>
1834  // for a given row.
1835  SmallDenseMap<ArrayRef<DynamicAPInt>, std::pair<unsigned, DynamicAPInt>>
1836  rowsWithoutConstTerm;
1837  // To unique rows.
1838  SmallDenseSet<ArrayRef<DynamicAPInt>, 8> rowSet;
1839 
1840  // Check if constraint is of the form <non-negative-constant> >= 0.
1841  auto isTriviallyValid = [&](unsigned r) -> bool {
1842  for (unsigned c = 0, e = getNumCols() - 1; c < e; c++) {
1843  if (atIneq(r, c) != 0)
1844  return false;
1845  }
1846  return atIneq(r, getNumCols() - 1) >= 0;
1847  };
1848 
1849  // Detect and mark redundant constraints.
1850  SmallVector<bool, 256> redunIneq(getNumInequalities(), false);
1851  for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
1852  DynamicAPInt *rowStart = &inequalities(r, 0);
1853  auto row = ArrayRef<DynamicAPInt>(rowStart, getNumCols());
1854  if (isTriviallyValid(r) || !rowSet.insert(row).second) {
1855  redunIneq[r] = true;
1856  continue;
1857  }
1858 
1859  // Among constraints that only differ in the constant term part, mark
1860  // everything other than the one with the smallest constant term redundant.
1861  // (eg: among i - 16j - 5 >= 0, i - 16j - 1 >=0, i - 16j - 7 >= 0, the
1862  // former two are redundant).
1863  DynamicAPInt constTerm = atIneq(r, getNumCols() - 1);
1864  auto rowWithoutConstTerm =
1865  ArrayRef<DynamicAPInt>(rowStart, getNumCols() - 1);
1866  const auto &ret =
1867  rowsWithoutConstTerm.insert({rowWithoutConstTerm, {r, constTerm}});
1868  if (!ret.second) {
1869  // Check if the other constraint has a higher constant term.
1870  auto &val = ret.first->second;
1871  if (val.second > constTerm) {
1872  // The stored row is redundant. Mark it so, and update with this one.
1873  redunIneq[val.first] = true;
1874  val = {r, constTerm};
1875  } else {
1876  // The one stored makes this one redundant.
1877  redunIneq[r] = true;
1878  }
1879  }
1880  }
1881 
1882  // Scan to get rid of all rows marked redundant, in-place.
1883  unsigned pos = 0;
1884  for (unsigned r = 0, e = getNumInequalities(); r < e; r++)
1885  if (!redunIneq[r])
1886  inequalities.copyRow(r, pos++);
1887 
1889 
1890  // TODO: consider doing this for equalities as well, but probably not worth
1891  // the savings.
1892 }
1893 
1894 #undef DEBUG_TYPE
1895 #define DEBUG_TYPE "fm"
1896 
1897 /// Eliminates variable at the specified position using Fourier-Motzkin
1898 /// variable elimination. This technique is exact for rational spaces but
1899 /// conservative (in "rare" cases) for integer spaces. The operation corresponds
1900 /// to a projection operation yielding the (convex) set of integer points
1901 /// contained in the rational shadow of the set. An emptiness test that relies
1902 /// on this method will guarantee emptiness, i.e., it disproves the existence of
1903 /// a solution if it says it's empty.
1904 /// If a non-null isResultIntegerExact is passed, it is set to true if the
1905 /// result is also integer exact. If it's set to false, the obtained solution
1906 /// *may* not be exact, i.e., it may contain integer points that do not have an
1907 /// integer pre-image in the original set.
1908 ///
1909 /// Eg:
1910 /// j >= 0, j <= i + 1
1911 /// i >= 0, i <= N + 1
1912 /// Eliminating i yields,
1913 /// j >= 0, 0 <= N + 1, j - 1 <= N + 1
1914 ///
1915 /// If darkShadow = true, this method computes the dark shadow on elimination;
1916 /// the dark shadow is a convex integer subset of the exact integer shadow. A
1917 /// non-empty dark shadow proves the existence of an integer solution. The
1918 /// elimination in such a case could however be an under-approximation, and thus
1919 /// should not be used for scanning sets or used by itself for dependence
1920 /// checking.
1921 ///
1922 /// Eg: 2-d set, * represents grid points, 'o' represents a point in the set.
1923 /// ^
1924 /// |
1925 /// | * * * * o o
1926 /// i | * * o o o o
1927 /// | o * * * * *
1928 /// --------------->
1929 /// j ->
1930 ///
1931 /// Eliminating i from this system (projecting on the j dimension):
1932 /// rational shadow / integer light shadow: 1 <= j <= 6
1933 /// dark shadow: 3 <= j <= 6
1934 /// exact integer shadow: j = 1 \union 3 <= j <= 6
1935 /// holes/splinters: j = 2
1936 ///
1937 /// darkShadow = false, isResultIntegerExact = nullptr are default values.
1938 // TODO: a slight modification to yield dark shadow version of FM (tightened),
1939 // which can prove the existence of a solution if there is one.
1940 void IntegerRelation::fourierMotzkinEliminate(unsigned pos, bool darkShadow,
1941  bool *isResultIntegerExact) {
1942  LLVM_DEBUG(llvm::dbgs() << "FM input (eliminate pos " << pos << "):\n");
1943  LLVM_DEBUG(dump());
1944  assert(pos < getNumVars() && "invalid position");
1945  assert(hasConsistentState());
1946 
1947  // Check if this variable can be eliminated through a substitution.
1948  for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
1949  if (atEq(r, pos) != 0) {
1950  // Use Gaussian elimination here (since we have an equality).
1951  LogicalResult ret = gaussianEliminateVar(pos);
1952  (void)ret;
1953  assert(ret.succeeded() && "Gaussian elimination guaranteed to succeed");
1954  LLVM_DEBUG(llvm::dbgs() << "FM output (through Gaussian elimination):\n");
1955  LLVM_DEBUG(dump());
1956  return;
1957  }
1958  }
1959 
1960  // A fast linear time tightening.
1962 
1963  // Check if the variable appears at all in any of the inequalities.
1964  if (isColZero(pos)) {
1965  // If it doesn't appear, just remove the column and return.
1966  // TODO: refactor removeColumns to use it from here.
1967  removeVar(pos);
1968  LLVM_DEBUG(llvm::dbgs() << "FM output:\n");
1969  LLVM_DEBUG(dump());
1970  return;
1971  }
1972 
1973  // Positions of constraints that are lower bounds on the variable.
1974  SmallVector<unsigned, 4> lbIndices;
1975  // Positions of constraints that are lower bounds on the variable.
1976  SmallVector<unsigned, 4> ubIndices;
1977  // Positions of constraints that do not involve the variable.
1978  std::vector<unsigned> nbIndices;
1979  nbIndices.reserve(getNumInequalities());
1980 
1981  // Gather all lower bounds and upper bounds of the variable. Since the
1982  // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower
1983  // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1.
1984  for (unsigned r = 0, e = getNumInequalities(); r < e; r++) {
1985  if (atIneq(r, pos) == 0) {
1986  // Var does not appear in bound.
1987  nbIndices.emplace_back(r);
1988  } else if (atIneq(r, pos) >= 1) {
1989  // Lower bound.
1990  lbIndices.emplace_back(r);
1991  } else {
1992  // Upper bound.
1993  ubIndices.emplace_back(r);
1994  }
1995  }
1996 
1997  PresburgerSpace newSpace = getSpace();
1998  VarKind idKindRemove = newSpace.getVarKindAt(pos);
1999  unsigned relativePos = pos - newSpace.getVarKindOffset(idKindRemove);
2000  newSpace.removeVarRange(idKindRemove, relativePos, relativePos + 1);
2001 
2002  /// Create the new system which has one variable less.
2003  IntegerRelation newRel(lbIndices.size() * ubIndices.size() + nbIndices.size(),
2004  getNumEqualities(), getNumCols() - 1, newSpace);
2005 
2006  // This will be used to check if the elimination was integer exact.
2007  bool allLCMsAreOne = true;
2008 
2009  // Let x be the variable we are eliminating.
2010  // For each lower bound, lb <= c_l*x, and each upper bound c_u*x <= ub, (note
2011  // that c_l, c_u >= 1) we have:
2012  // lb*lcm(c_l, c_u)/c_l <= lcm(c_l, c_u)*x <= ub*lcm(c_l, c_u)/c_u
2013  // We thus generate a constraint:
2014  // lcm(c_l, c_u)/c_l*lb <= lcm(c_l, c_u)/c_u*ub.
2015  // Note if c_l = c_u = 1, all integer points captured by the resulting
2016  // constraint correspond to integer points in the original system (i.e., they
2017  // have integer pre-images). Hence, if the lcm's are all 1, the elimination is
2018  // integer exact.
2019  for (auto ubPos : ubIndices) {
2020  for (auto lbPos : lbIndices) {
2022  ineq.reserve(newRel.getNumCols());
2023  DynamicAPInt lbCoeff = atIneq(lbPos, pos);
2024  // Note that in the comments above, ubCoeff is the negation of the
2025  // coefficient in the canonical form as the view taken here is that of the
2026  // term being moved to the other size of '>='.
2027  DynamicAPInt ubCoeff = -atIneq(ubPos, pos);
2028  // TODO: refactor this loop to avoid all branches inside.
2029  for (unsigned l = 0, e = getNumCols(); l < e; l++) {
2030  if (l == pos)
2031  continue;
2032  assert(lbCoeff >= 1 && ubCoeff >= 1 && "bounds wrongly identified");
2033  DynamicAPInt lcm = llvm::lcm(lbCoeff, ubCoeff);
2034  ineq.emplace_back(atIneq(ubPos, l) * (lcm / ubCoeff) +
2035  atIneq(lbPos, l) * (lcm / lbCoeff));
2036  assert(lcm > 0 && "lcm should be positive!");
2037  if (lcm != 1)
2038  allLCMsAreOne = false;
2039  }
2040  if (darkShadow) {
2041  // The dark shadow is a convex subset of the exact integer shadow. If
2042  // there is a point here, it proves the existence of a solution.
2043  ineq[ineq.size() - 1] += lbCoeff * ubCoeff - lbCoeff - ubCoeff + 1;
2044  }
2045  // TODO: we need to have a way to add inequalities in-place in
2046  // IntegerRelation instead of creating and copying over.
2047  newRel.addInequality(ineq);
2048  }
2049  }
2050 
2051  LLVM_DEBUG(llvm::dbgs() << "FM isResultIntegerExact: " << allLCMsAreOne
2052  << "\n");
2053  if (allLCMsAreOne && isResultIntegerExact)
2054  *isResultIntegerExact = true;
2055 
2056  // Copy over the constraints not involving this variable.
2057  for (auto nbPos : nbIndices) {
2059  ineq.reserve(getNumCols() - 1);
2060  for (unsigned l = 0, e = getNumCols(); l < e; l++) {
2061  if (l == pos)
2062  continue;
2063  ineq.emplace_back(atIneq(nbPos, l));
2064  }
2065  newRel.addInequality(ineq);
2066  }
2067 
2068  assert(newRel.getNumConstraints() ==
2069  lbIndices.size() * ubIndices.size() + nbIndices.size());
2070 
2071  // Copy over the equalities.
2072  for (unsigned r = 0, e = getNumEqualities(); r < e; r++) {
2074  eq.reserve(newRel.getNumCols());
2075  for (unsigned l = 0, e = getNumCols(); l < e; l++) {
2076  if (l == pos)
2077  continue;
2078  eq.emplace_back(atEq(r, l));
2079  }
2080  newRel.addEquality(eq);
2081  }
2082 
2083  // GCD tightening and normalization allows detection of more trivially
2084  // redundant constraints.
2085  newRel.gcdTightenInequalities();
2086  newRel.normalizeConstraintsByGCD();
2087  newRel.removeTrivialRedundancy();
2088  clearAndCopyFrom(newRel);
2089  LLVM_DEBUG(llvm::dbgs() << "FM output:\n");
2090  LLVM_DEBUG(dump());
2091 }
2092 
2093 #undef DEBUG_TYPE
2094 #define DEBUG_TYPE "presburger"
2095 
2096 void IntegerRelation::projectOut(unsigned pos, unsigned num) {
2097  if (num == 0)
2098  return;
2099 
2100  // 'pos' can be at most getNumCols() - 2 if num > 0.
2101  assert((getNumCols() < 2 || pos <= getNumCols() - 2) && "invalid position");
2102  assert(pos + num < getNumCols() && "invalid range");
2103 
2104  // Eliminate as many variables as possible using Gaussian elimination.
2105  unsigned currentPos = pos;
2106  unsigned numToEliminate = num;
2107  unsigned numGaussianEliminated = 0;
2108 
2109  while (currentPos < getNumVars()) {
2110  unsigned curNumEliminated =
2111  gaussianEliminateVars(currentPos, currentPos + numToEliminate);
2112  ++currentPos;
2113  numToEliminate -= curNumEliminated + 1;
2114  numGaussianEliminated += curNumEliminated;
2115  }
2116 
2117  // Eliminate the remaining using Fourier-Motzkin.
2118  for (unsigned i = 0; i < num - numGaussianEliminated; i++) {
2119  unsigned numToEliminate = num - numGaussianEliminated - i;
2121  getBestVarToEliminate(*this, pos, pos + numToEliminate));
2122  }
2123 
2124  // Fast/trivial simplifications.
2126  // Normalize constraints after tightening since the latter impacts this, but
2127  // not the other way round.
2129 }
2130 
2131 namespace {
2132 
2133 enum BoundCmpResult { Greater, Less, Equal, Unknown };
2134 
2135 /// Compares two affine bounds whose coefficients are provided in 'first' and
2136 /// 'second'. The last coefficient is the constant term.
2137 static BoundCmpResult compareBounds(ArrayRef<DynamicAPInt> a,
2139  assert(a.size() == b.size());
2140 
2141  // For the bounds to be comparable, their corresponding variable
2142  // coefficients should be equal; the constant terms are then compared to
2143  // determine less/greater/equal.
2144 
2145  if (!std::equal(a.begin(), a.end() - 1, b.begin()))
2146  return Unknown;
2147 
2148  if (a.back() == b.back())
2149  return Equal;
2150 
2151  return a.back() < b.back() ? Less : Greater;
2152 }
2153 } // namespace
2154 
2155 // Returns constraints that are common to both A & B.
2157  const IntegerRelation &b, IntegerRelation &c) {
2158  c = IntegerRelation(a.getSpace());
2159  // a naive O(n^2) check should be enough here given the input sizes.
2160  for (unsigned r = 0, e = a.getNumInequalities(); r < e; ++r) {
2161  for (unsigned s = 0, f = b.getNumInequalities(); s < f; ++s) {
2162  if (a.getInequality(r) == b.getInequality(s)) {
2163  c.addInequality(a.getInequality(r));
2164  break;
2165  }
2166  }
2167  }
2168  for (unsigned r = 0, e = a.getNumEqualities(); r < e; ++r) {
2169  for (unsigned s = 0, f = b.getNumEqualities(); s < f; ++s) {
2170  if (a.getEquality(r) == b.getEquality(s)) {
2171  c.addEquality(a.getEquality(r));
2172  break;
2173  }
2174  }
2175  }
2176 }
2177 
2178 // Computes the bounding box with respect to 'other' by finding the min of the
2179 // lower bounds and the max of the upper bounds along each of the dimensions.
2180 LogicalResult
2182  assert(space.isEqual(otherCst.getSpace()) && "Spaces should match.");
2183  assert(getNumLocalVars() == 0 && "local ids not supported yet here");
2184 
2185  // Get the constraints common to both systems; these will be added as is to
2186  // the union.
2188  getCommonConstraints(*this, otherCst, commonCst);
2189 
2190  std::vector<SmallVector<DynamicAPInt, 8>> boundingLbs;
2191  std::vector<SmallVector<DynamicAPInt, 8>> boundingUbs;
2192  boundingLbs.reserve(2 * getNumDimVars());
2193  boundingUbs.reserve(2 * getNumDimVars());
2194 
2195  // To hold lower and upper bounds for each dimension.
2196  SmallVector<DynamicAPInt, 4> lb, otherLb, ub, otherUb;
2197  // To compute min of lower bounds and max of upper bounds for each dimension.
2200  // To compute final new lower and upper bounds for the union.
2202 
2203  DynamicAPInt lbFloorDivisor, otherLbFloorDivisor;
2204  for (unsigned d = 0, e = getNumDimVars(); d < e; ++d) {
2205  auto extent = getConstantBoundOnDimSize(d, &lb, &lbFloorDivisor, &ub);
2206  if (!extent.has_value())
2207  // TODO: symbolic extents when necessary.
2208  // TODO: handle union if a dimension is unbounded.
2209  return failure();
2210 
2211  auto otherExtent = otherCst.getConstantBoundOnDimSize(
2212  d, &otherLb, &otherLbFloorDivisor, &otherUb);
2213  if (!otherExtent.has_value() || lbFloorDivisor != otherLbFloorDivisor)
2214  // TODO: symbolic extents when necessary.
2215  return failure();
2216 
2217  assert(lbFloorDivisor > 0 && "divisor always expected to be positive");
2218 
2219  auto res = compareBounds(lb, otherLb);
2220  // Identify min.
2221  if (res == BoundCmpResult::Less || res == BoundCmpResult::Equal) {
2222  minLb = lb;
2223  // Since the divisor is for a floordiv, we need to convert to ceildiv,
2224  // i.e., i >= expr floordiv div <=> i >= (expr - div + 1) ceildiv div <=>
2225  // div * i >= expr - div + 1.
2226  minLb.back() -= lbFloorDivisor - 1;
2227  } else if (res == BoundCmpResult::Greater) {
2228  minLb = otherLb;
2229  minLb.back() -= otherLbFloorDivisor - 1;
2230  } else {
2231  // Uncomparable - check for constant lower/upper bounds.
2232  auto constLb = getConstantBound(BoundType::LB, d);
2233  auto constOtherLb = otherCst.getConstantBound(BoundType::LB, d);
2234  if (!constLb.has_value() || !constOtherLb.has_value())
2235  return failure();
2236  std::fill(minLb.begin(), minLb.end(), 0);
2237  minLb.back() = std::min(*constLb, *constOtherLb);
2238  }
2239 
2240  // Do the same for ub's but max of upper bounds. Identify max.
2241  auto uRes = compareBounds(ub, otherUb);
2242  if (uRes == BoundCmpResult::Greater || uRes == BoundCmpResult::Equal) {
2243  maxUb = ub;
2244  } else if (uRes == BoundCmpResult::Less) {
2245  maxUb = otherUb;
2246  } else {
2247  // Uncomparable - check for constant lower/upper bounds.
2248  auto constUb = getConstantBound(BoundType::UB, d);
2249  auto constOtherUb = otherCst.getConstantBound(BoundType::UB, d);
2250  if (!constUb.has_value() || !constOtherUb.has_value())
2251  return failure();
2252  std::fill(maxUb.begin(), maxUb.end(), 0);
2253  maxUb.back() = std::max(*constUb, *constOtherUb);
2254  }
2255 
2256  std::fill(newLb.begin(), newLb.end(), 0);
2257  std::fill(newUb.begin(), newUb.end(), 0);
2258 
2259  // The divisor for lb, ub, otherLb, otherUb at this point is lbDivisor,
2260  // and so it's the divisor for newLb and newUb as well.
2261  newLb[d] = lbFloorDivisor;
2262  newUb[d] = -lbFloorDivisor;
2263  // Copy over the symbolic part + constant term.
2264  std::copy(minLb.begin(), minLb.end(), newLb.begin() + getNumDimVars());
2265  std::transform(newLb.begin() + getNumDimVars(), newLb.end(),
2266  newLb.begin() + getNumDimVars(),
2267  std::negate<DynamicAPInt>());
2268  std::copy(maxUb.begin(), maxUb.end(), newUb.begin() + getNumDimVars());
2269 
2270  boundingLbs.emplace_back(newLb);
2271  boundingUbs.emplace_back(newUb);
2272  }
2273 
2274  // Clear all constraints and add the lower/upper bounds for the bounding box.
2275  clearConstraints();
2276  for (unsigned d = 0, e = getNumDimVars(); d < e; ++d) {
2277  addInequality(boundingLbs[d]);
2278  addInequality(boundingUbs[d]);
2279  }
2280 
2281  // Add the constraints that were common to both systems.
2282  append(commonCst);
2284 
2285  // TODO: copy over pure symbolic constraints from this and 'other' over to the
2286  // union (since the above are just the union along dimensions); we shouldn't
2287  // be discarding any other constraints on the symbols.
2288 
2289  return success();
2290 }
2291 
2292 bool IntegerRelation::isColZero(unsigned pos) const {
2293  unsigned rowPos;
2294  return !findConstraintWithNonZeroAt(pos, /*isEq=*/false, &rowPos) &&
2295  !findConstraintWithNonZeroAt(pos, /*isEq=*/true, &rowPos);
2296 }
2297 
2298 /// Find positions of inequalities and equalities that do not have a coefficient
2299 /// for [pos, pos + num) variables.
2300 static void getIndependentConstraints(const IntegerRelation &cst, unsigned pos,
2301  unsigned num,
2302  SmallVectorImpl<unsigned> &nbIneqIndices,
2303  SmallVectorImpl<unsigned> &nbEqIndices) {
2304  assert(pos < cst.getNumVars() && "invalid start position");
2305  assert(pos + num <= cst.getNumVars() && "invalid limit");
2306 
2307  for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) {
2308  // The bounds are to be independent of [offset, offset + num) columns.
2309  unsigned c;
2310  for (c = pos; c < pos + num; ++c) {
2311  if (cst.atIneq(r, c) != 0)
2312  break;
2313  }
2314  if (c == pos + num)
2315  nbIneqIndices.emplace_back(r);
2316  }
2317 
2318  for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) {
2319  // The bounds are to be independent of [offset, offset + num) columns.
2320  unsigned c;
2321  for (c = pos; c < pos + num; ++c) {
2322  if (cst.atEq(r, c) != 0)
2323  break;
2324  }
2325  if (c == pos + num)
2326  nbEqIndices.emplace_back(r);
2327  }
2328 }
2329 
2330 void IntegerRelation::removeIndependentConstraints(unsigned pos, unsigned num) {
2331  assert(pos + num <= getNumVars() && "invalid range");
2332 
2333  // Remove constraints that are independent of these variables.
2334  SmallVector<unsigned, 4> nbIneqIndices, nbEqIndices;
2335  getIndependentConstraints(*this, /*pos=*/0, num, nbIneqIndices, nbEqIndices);
2336 
2337  // Iterate in reverse so that indices don't have to be updated.
2338  // TODO: This method can be made more efficient (because removal of each
2339  // inequality leads to much shifting/copying in the underlying buffer).
2340  for (auto nbIndex : llvm::reverse(nbIneqIndices))
2341  removeInequality(nbIndex);
2342  for (auto nbIndex : llvm::reverse(nbEqIndices))
2343  removeEquality(nbIndex);
2344 }
2345 
2347  IntegerRelation copyRel = *this;
2348 
2349  // Convert Range variables to Local variables.
2351  VarKind::Local);
2352 
2353  // Convert Domain variables to SetDim(Range) variables.
2355  VarKind::SetDim);
2356 
2357  return IntegerPolyhedron(std::move(copyRel));
2358 }
2359 
2361  bool changed = false;
2362  SmallDenseMap<ArrayRef<DynamicAPInt>, unsigned> hashTable;
2363  unsigned ineqs = getNumInequalities(), cols = getNumCols();
2364 
2365  if (ineqs <= 1)
2366  return changed;
2367 
2368  // Check if the non-constant part of the constraint is the same.
2369  ArrayRef<DynamicAPInt> row = getInequality(0).drop_back();
2370  hashTable.insert({row, 0});
2371  for (unsigned k = 1; k < ineqs; ++k) {
2372  row = getInequality(k).drop_back();
2373  if (hashTable.try_emplace(row, k).second)
2374  continue;
2375 
2376  // For identical cases, keep only the smaller part of the constant term.
2377  unsigned l = hashTable[row];
2378  changed = true;
2379  if (atIneq(k, cols - 1) <= atIneq(l, cols - 1))
2380  inequalities.swapRows(k, l);
2381  removeInequality(k);
2382  --k;
2383  --ineqs;
2384  }
2385 
2386  // Check the neg form of each inequality, need an extra vector to store it.
2387  SmallVector<DynamicAPInt> negIneq(cols - 1);
2388  for (unsigned k = 0; k < ineqs; ++k) {
2389  row = getInequality(k).drop_back();
2390  negIneq.assign(row.begin(), row.end());
2391  for (DynamicAPInt &ele : negIneq)
2392  ele = -ele;
2393  if (!hashTable.contains(negIneq))
2394  continue;
2395 
2396  // For cases where the neg is the same as other inequalities, check that the
2397  // sum of their constant terms is positive.
2398  unsigned l = hashTable[row];
2399  auto sum = atIneq(l, cols - 1) + atIneq(k, cols - 1);
2400  if (sum > 0 || l == k)
2401  continue;
2402 
2403  // A sum of constant terms equal to zero combines two inequalities into one
2404  // equation, less than zero means the set is empty.
2405  changed = true;
2406  if (k < l)
2407  std::swap(l, k);
2408  if (sum == 0) {
2410  removeInequality(k);
2411  removeInequality(l);
2412  } else
2413  *this = getEmpty(getSpace());
2414  break;
2415  }
2416 
2417  return changed;
2418 }
2419 
2421  IntegerRelation copyRel = *this;
2422 
2423  // Convert Domain variables to Local variables.
2425  VarKind::Local);
2426 
2427  // We do not need to do anything to Range variables since they are already in
2428  // SetDim position.
2429 
2430  return IntegerPolyhedron(std::move(copyRel));
2431 }
2432 
2434  assert(getDomainSet().getSpace().isCompatible(poly.getSpace()) &&
2435  "Domain set is not compatible with poly");
2436 
2437  // Treating the poly as a relation, convert it from `0 -> R` to `R -> 0`.
2438  IntegerRelation rel = poly;
2439  rel.inverse();
2440 
2441  // Append dummy range variables to make the spaces compatible.
2443 
2444  // Intersect in place.
2445  mergeLocalVars(rel);
2446  append(rel);
2447 }
2448 
2450  assert(getRangeSet().getSpace().isCompatible(poly.getSpace()) &&
2451  "Range set is not compatible with poly");
2452 
2453  IntegerRelation rel = poly;
2454 
2455  // Append dummy domain variables to make the spaces compatible.
2457 
2458  mergeLocalVars(rel);
2459  append(rel);
2460 }
2461 
2463  unsigned numRangeVars = getNumVarKind(VarKind::Range);
2465  VarKind::Range);
2466  convertVarKind(VarKind::Range, 0, numRangeVars, VarKind::Domain);
2467 }
2468 
2470  assert(getRangeSet().getSpace().isCompatible(rel.getDomainSet().getSpace()) &&
2471  "Range of `this` should be compatible with Domain of `rel`");
2472 
2473  IntegerRelation copyRel = rel;
2474 
2475  // Let relation `this` be R1: A -> B, and `rel` be R2: B -> C.
2476  // We convert R1 to A -> (B X C), and R2 to B X C then intersect the range of
2477  // R1 with R2. After this, we get R1: A -> C, by projecting out B.
2478  // TODO: Using nested spaces here would help, since we could directly
2479  // intersect the range with another relation.
2480  unsigned numBVars = getNumRangeVars();
2481 
2482  // Convert R1 from A -> B to A -> (B X C).
2484 
2485  // Convert R2 to B X C.
2486  copyRel.convertVarKind(VarKind::Domain, 0, numBVars, VarKind::Range, 0);
2487 
2488  // Intersect R2 to range of R1.
2490 
2491  // Project out B in R1.
2493 }
2494 
2496  inverse();
2497  compose(rel);
2498  inverse();
2499 }
2500 
2502 
2503 void IntegerRelation::printSpace(raw_ostream &os) const {
2504  space.print(os);
2505  os << getNumConstraints() << " constraints\n";
2506 }
2507 
2509  for (int i = getNumEqualities() - 1; i >= 0; --i)
2510  if (rangeIsZero(getEquality(i)))
2511  removeEquality(i);
2512 }
2513 
2515  if (getNumVars() == 0)
2516  return true;
2517  if (isEmpty())
2518  return false;
2519 
2520  // If there is a non-trivial equality, the space cannot be full-dimensional.
2522  if (getNumEqualities() > 0)
2523  return false;
2524 
2525  // The polytope is full-dimensional iff it is not flat along any of the
2526  // inequality directions.
2527  Simplex simplex(*this);
2528  return llvm::none_of(llvm::seq<int>(getNumInequalities()), [&](int i) {
2529  return simplex.isFlatAlong(getInequality(i));
2530  });
2531 }
2532 
2534  assert(getNumDomainVars() == other.getNumRangeVars() &&
2535  "Domain of this and range of other do not match");
2536  // assert(std::equal(values.begin(), values.begin() +
2537  // other.getNumDomainVars(),
2538  // otherValues.begin() + other.getNumDomainVars()) &&
2539  // "Domain of this and range of other do not match");
2540 
2541  IntegerRelation result = other;
2542 
2543  const unsigned thisDomain = getNumDomainVars();
2544  const unsigned thisRange = getNumRangeVars();
2545  const unsigned otherDomain = other.getNumDomainVars();
2546  const unsigned otherRange = other.getNumRangeVars();
2547 
2548  // Add dimension variables temporarily to merge symbol and local vars.
2549  // Convert `this` from
2550  // [thisDomain] -> [thisRange]
2551  // to
2552  // [otherDomain thisDomain] -> [otherRange thisRange].
2553  // and `result` from
2554  // [otherDomain] -> [otherRange]
2555  // to
2556  // [otherDomain thisDomain] -> [otherRange thisRange]
2557  insertVar(VarKind::Domain, 0, otherDomain);
2558  insertVar(VarKind::Range, 0, otherRange);
2559  result.insertVar(VarKind::Domain, otherDomain, thisDomain);
2560  result.insertVar(VarKind::Range, otherRange, thisRange);
2561 
2562  // Merge symbol and local variables.
2563  mergeAndAlignSymbols(result);
2564  mergeLocalVars(result);
2565 
2566  // Convert `result` from [otherDomain thisDomain] -> [otherRange thisRange] to
2567  // [otherDomain] -> [thisRange]
2568  result.removeVarRange(VarKind::Domain, otherDomain, otherDomain + thisDomain);
2569  result.convertToLocal(VarKind::Range, 0, otherRange);
2570  // Convert `this` from [otherDomain thisDomain] -> [otherRange thisRange] to
2571  // [otherDomain] -> [thisRange]
2572  convertToLocal(VarKind::Domain, otherDomain, otherDomain + thisDomain);
2573  removeVarRange(VarKind::Range, 0, otherRange);
2574 
2575  // Add and match domain of `result` to domain of `this`.
2576  for (unsigned i = 0, e = result.getNumDomainVars(); i < e; ++i)
2577  if (result.getSpace().getId(VarKind::Domain, i).hasValue())
2579  result.getSpace().getId(VarKind::Domain, i));
2580  // Add and match range of `this` to range of `result`.
2581  for (unsigned i = 0, e = getNumRangeVars(); i < e; ++i)
2582  if (space.getId(VarKind::Range, i).hasValue())
2584 
2585  // Append `this` to `result` and simplify constraints.
2586  result.append(*this);
2587  result.removeRedundantLocalVars();
2588 
2589  *this = result;
2590 }
2591 
2592 void IntegerRelation::print(raw_ostream &os) const {
2593  assert(hasConsistentState());
2594  printSpace(os);
2595  PrintTableMetrics ptm = {0, 0, "-"};
2596  for (unsigned i = 0, e = getNumEqualities(); i < e; ++i)
2597  for (unsigned j = 0, f = getNumCols(); j < f; ++j)
2598  updatePrintMetrics<DynamicAPInt>(atEq(i, j), ptm);
2599  for (unsigned i = 0, e = getNumInequalities(); i < e; ++i)
2600  for (unsigned j = 0, f = getNumCols(); j < f; ++j)
2601  updatePrintMetrics<DynamicAPInt>(atIneq(i, j), ptm);
2602  // Print using PrintMetrics.
2603  unsigned MIN_SPACING = 1;
2604  for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) {
2605  for (unsigned j = 0, f = getNumCols(); j < f; ++j) {
2606  printWithPrintMetrics<DynamicAPInt>(os, atEq(i, j), MIN_SPACING, ptm);
2607  }
2608  os << " = 0\n";
2609  }
2610  for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) {
2611  for (unsigned j = 0, f = getNumCols(); j < f; ++j) {
2612  printWithPrintMetrics<DynamicAPInt>(os, atIneq(i, j), MIN_SPACING, ptm);
2613  }
2614  os << " >= 0\n";
2615  }
2616  os << '\n';
2617 }
2618 
2619 void IntegerRelation::dump() const { print(llvm::errs()); }
2620 
2621 unsigned IntegerPolyhedron::insertVar(VarKind kind, unsigned pos,
2622  unsigned num) {
2623  assert((kind != VarKind::Domain || num == 0) &&
2624  "Domain has to be zero in a set");
2625  return IntegerRelation::insertVar(kind, pos, num);
2626 }
2630 }
2631 
2634 }
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
static bool rangeIsZero(ArrayRef< DynamicAPInt > range)
static void getIndependentConstraints(const IntegerRelation &cst, unsigned pos, unsigned num, SmallVectorImpl< unsigned > &nbIneqIndices, SmallVectorImpl< unsigned > &nbEqIndices)
Find positions of inequalities and equalities that do not have a coefficient for [pos,...
static void removeConstraintsInvolvingVarRange(IntegerRelation &poly, unsigned begin, unsigned count)
static int findEqualityToConstant(const IntegerRelation &cst, unsigned pos, bool symbolic=false)
Finds an equality that equates the specified variable to a constant.
static unsigned getBestVarToEliminate(const IntegerRelation &cst, unsigned start, unsigned end)
Returns the position of the variable that has the minimum <number of lower bounds> times <number of u...
static void getCommonConstraints(const IntegerRelation &a, const IntegerRelation &b, IntegerRelation &c)
static void eliminateFromConstraint(IntegerRelation *constraints, unsigned rowIdx, unsigned pivotRow, unsigned pivotCol, unsigned elimColStart, bool isEq)
Eliminate variable from constraint at rowIdx based on coefficient at pivotRow, pivotCol.
static DynamicAPInt valueAt(ArrayRef< DynamicAPInt > expr, ArrayRef< DynamicAPInt > point)
Helper to evaluate an affine expression at a point.
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
int64_t cols
Class storing division representation of local variables of a constraint system.
Definition: Utils.h:117
void removeDuplicateDivs(llvm::function_ref< bool(unsigned i, unsigned j)> merge)
Removes duplicate divisions.
Definition: Utils.cpp:441
bool hasAllReprs() const
Definition: Utils.h:133
void clearRepr(unsigned i)
Definition: Utils.h:136
DynamicAPInt & getDenom(unsigned i)
Definition: Utils.h:153
MutableArrayRef< DynamicAPInt > getDividend(unsigned i)
Definition: Utils.h:139
An Identifier stores a pointer to an object, such as a Value or an Operation.
DynamicAPInt normalizeRow(unsigned row, unsigned nCols)
Divide the first nCols of the specified row by their GCD.
Definition: Matrix.cpp:549
An IntegerPolyhedron represents the set of points from a PresburgerSpace that satisfy a list of affin...
IntegerPolyhedron intersect(const IntegerPolyhedron &other) const
Return the intersection of the two relations.
unsigned insertVar(VarKind kind, unsigned pos, unsigned num=1) override
Insert num variables of the specified kind at position pos.
PresburgerSet subtract(const PresburgerSet &other) const
Return the set difference of this set and the given set, i.e., return this \ set.
IntegerPolyhedron(unsigned numReservedInequalities, unsigned numReservedEqualities, unsigned numReservedCols, const PresburgerSpace &space)
Constructs a set reserving memory for the specified number of constraints and variables.
std::unique_ptr< IntegerPolyhedron > clone() const
An IntegerRelation represents the set of points from a PresburgerSpace that satisfy a list of affine ...
std::optional< DynamicAPInt > getConstantBoundOnDimSize(unsigned pos, SmallVectorImpl< DynamicAPInt > *lb=nullptr, DynamicAPInt *boundFloorDivisor=nullptr, SmallVectorImpl< DynamicAPInt > *ub=nullptr, unsigned *minLbPos=nullptr, unsigned *minUbPos=nullptr) const
Returns the smallest known constant bound for the extent of the specified variable (pos^th),...
void setId(VarKind kind, unsigned i, Identifier id)
Set the identifier for the ith variable of the specified kind of the IntegerRelation's PresburgerSpac...
virtual void swapVar(unsigned posA, unsigned posB)
Swap the posA^th variable with the posB^th variable.
void removeIndependentConstraints(unsigned pos, unsigned num)
Removes constraints that are independent of (i.e., do not have a coefficient) variables in the range ...
void compose(const IntegerRelation &rel)
Let the relation this be R1, and the relation rel be R2.
void applyRange(const IntegerRelation &rel)
Given a relation rel, apply the relation to the range of this relation.
unsigned getVarKindEnd(VarKind kind) const
Return the index at Which the specified kind of vars ends.
ArrayRef< Identifier > getIds(VarKind kind)
Get the identifiers for the variables of specified varKind.
void removeTrivialRedundancy()
Removes duplicate constraints, trivially true constraints, and constraints that can be detected as re...
static IntegerRelation getEmpty(const PresburgerSpace &space)
Return an empty system containing an invalid equation 0 = 1.
void removeInequalityRange(unsigned start, unsigned end)
void normalizeConstraintsByGCD()
Normalized each constraints by the GCD of its coefficients.
void truncate(const CountsSnapshot &counts)
virtual void eliminateRedundantLocalVar(unsigned posA, unsigned posB)
Eliminate the posB^th local variable, replacing every instance of it with the posA^th local variable.
std::optional< DynamicAPInt > computeConstantLowerOrUpperBound(unsigned pos)
Returns the constant lower bound if isLower is true, and the upper bound if isLower is false.
void removeEqualityRange(unsigned start, unsigned end)
Remove the (in)equalities at positions [start, end).
LogicalResult constantFoldVar(unsigned pos)
Tries to fold the specified variable to a constant using a trivial equality detection; if successful,...
bool isObviouslyEqual(const IntegerRelation &other) const
Perform a quick equality check on this and other.
IntegerPolyhedron getRangeSet() const
Return a set corresponding to all points in the range of the relation.
std::optional< SmallVector< DynamicAPInt, 8 > > containsPointNoLocal(ArrayRef< DynamicAPInt > point) const
Given the values of non-local vars, return a satisfying assignment to the local if one exists,...
ArrayRef< DynamicAPInt > getInequality(unsigned idx) const
unsigned getNumVarKind(VarKind kind) const
Get the number of vars of the specified kind.
bool isEmptyByGCDTest() const
Runs the GCD test on all equality constraints.
void simplify()
Simplify the constraint system by removing canonicalizing constraints and removing redundant constrai...
void convertVarKind(VarKind srcKind, unsigned varStart, unsigned varLimit, VarKind dstKind, unsigned pos)
Converts variables of kind srcKind in the range [varStart, varLimit) to variables of kind dstKind.
void addBound(BoundType type, unsigned pos, const DynamicAPInt &value)
Adds a constant bound for the specified variable.
unsigned appendVar(VarKind kind, unsigned num=1)
Append num variables of the specified kind after the last variable of that kind.
void intersectRange(const IntegerPolyhedron &poly)
Intersect the given poly with the range in-place.
void addLocalFloorDiv(ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor)
Adds a new local variable as the floordiv of an affine function of other variables,...
void print(raw_ostream &os) const
bool isIntegerEmpty() const
Returns true if the set of constraints is found to have no solution, false if a solution exists.
DynamicAPInt atIneq(unsigned i, unsigned j) const
Returns the value at the specified inequality row and column.
virtual unsigned insertVar(VarKind kind, unsigned pos, unsigned num=1)
Insert num variables of the specified kind at position pos.
bool containsPoint(ArrayRef< DynamicAPInt > point) const
Returns true if the given point satisfies the constraints, or false otherwise.
std::optional< SmallVector< DynamicAPInt, 8 > > findIntegerSample() const
Find an integer sample point satisfying the constraints using a branch and bound algorithm with gener...
bool hasInvalidConstraint() const
Checks all rows of equality/inequality constraints for trivial contradictions (for example: 1 == 0,...
LogicalResult unionBoundingBox(const IntegerRelation &other)
Updates the constraints to be the smallest bounding (enclosing) box that contains the points of this ...
IntegerRelation(unsigned numReservedInequalities, unsigned numReservedEqualities, unsigned numReservedCols, const PresburgerSpace &space)
Constructs a relation reserving memory for the specified number of constraints and variables.
bool isHyperRectangular(unsigned pos, unsigned num) const
Returns true if the set can be trivially detected as being hyper-rectangular on the specified contigu...
void convertToLocal(VarKind kind, unsigned varStart, unsigned varLimit)
IntMatrix getBoundedDirections() const
Returns a matrix where each row is a vector along which the polytope is bounded.
LogicalResult gaussianEliminateVar(unsigned position)
Eliminates a single variable at position from equality and inequality constraints.
void clearConstraints()
Removes all equalities and inequalities.
DynamicAPInt atEq(unsigned i, unsigned j) const
Returns the value at the specified equality row and column.
IntegerRelation intersect(IntegerRelation other) const
Return the intersection of the two relations.
std::optional< DynamicAPInt > computeVolume() const
Compute an overapproximation of the number of integer points in the relation.
MaybeOptimum< SmallVector< DynamicAPInt, 8 > > findIntegerLexMin() const
Same as above, but returns lexicographically minimal integer point.
SymbolicLexOpt findSymbolicIntegerLexMin() const
Compute the symbolic integer lexmin of the relation.
void setSpace(const PresburgerSpace &oSpace)
Set the space to oSpace, which should have the same number of ids as the current space.
void inverse()
Invert the relation i.e., swap its domain and range.
void append(const IntegerRelation &other)
Appends constraints from other into this.
void applyDomain(const IntegerRelation &rel)
Given a relation rel, apply the relation to the domain of this relation.
void intersectDomain(const IntegerPolyhedron &poly)
Intersect the given poly with the domain in-place.
PresburgerRelation subtract(const PresburgerRelation &set) const
Return the set difference of this set and the given set, i.e., return this \ set.
bool isEqual(const IntegerRelation &other) const
Return whether this and other are equal.
virtual void printSpace(raw_ostream &os) const
Prints the number of constraints, dimensions, symbols and locals in the IntegerRelation.
void addEquality(ArrayRef< DynamicAPInt > eq)
Adds an equality from the coefficients specified in eq.
void removeRedundantConstraints()
Removes redundant constraints using Simplex.
PresburgerRelation computeReprWithOnlyDivLocals() const
Compute an equivalent representation of the same set, such that all local vars in all disjuncts have ...
void removeRedundantInequalities()
A more expensive check than removeTrivialRedundancy to detect redundant inequalities.
bool isObviouslyEmpty() const
Performs GCD checks and invalid constraint checks.
IntMatrix equalities
Coefficients of affine equalities (in == 0 form).
SymbolicLexOpt findSymbolicIntegerLexMax() const
Same as findSymbolicIntegerLexMin but produces lexmax instead of lexmin.
bool gaussianEliminate()
Perform a Gaussian elimination operation to reduce all equations to standard form.
void truncateVarKind(VarKind kind, unsigned num)
Truncate the vars of the specified kind to the specified number by dropping some vars at the end.
void constantFoldVarRange(unsigned pos, unsigned num)
This method calls constantFoldVar for the specified range of variables, num variables starting at pos...
bool isEmpty() const
Checks for emptiness by performing variable elimination on all variables, running the GCD test on eac...
unsigned getNumCols() const
Returns the number of columns in the constraint system.
void getLowerAndUpperBoundIndices(unsigned pos, SmallVectorImpl< unsigned > *lbIndices, SmallVectorImpl< unsigned > *ubIndices, SmallVectorImpl< unsigned > *eqIndices=nullptr, unsigned offset=0, unsigned num=0) const
Gather positions of all lower and upper bounds of the variable at pos, and optionally any equalities ...
void gcdTightenInequalities()
Tightens inequalities given that we are dealing with integer spaces.
void removeVar(VarKind kind, unsigned pos)
Removes variables of the specified kind with the specified pos (or within the specified range) from t...
void setSpaceExceptLocals(const PresburgerSpace &oSpace)
Set the space to oSpace, which should not have any local ids.
unsigned gaussianEliminateVars(unsigned posStart, unsigned posLimit)
Eliminates variables from equality and inequality constraints in column range [posStart,...
void mergeAndCompose(const IntegerRelation &other)
Given a relation other: (A -> B), this operation merges the symbol and local variables and then takes...
IntegerPolyhedron getDomainSet() const
Return a set corresponding to all points in the domain of the relation.
DivisionRepr getLocalReprs(std::vector< MaybeLocalRepr > *repr=nullptr) const
Returns a DivisonRepr representing the division representation of local variables in the constraint s...
bool hasOnlyDivLocals() const
Check whether all local ids have a division representation.
constexpr static unsigned kExplosionFactor
A parameter that controls detection of an unrealistic number of constraints.
std::optional< DynamicAPInt > getConstantBound(BoundType type, unsigned pos) const
Returns the constant bound for the pos^th variable if there is one; std::nullopt otherwise.
virtual void clearAndCopyFrom(const IntegerRelation &other)
Replaces the contents of this IntegerRelation with other.
void projectOut(unsigned pos, unsigned num)
Projects out (aka eliminates) num variables starting at position pos.
void addInequality(ArrayRef< DynamicAPInt > inEq)
Adds an inequality (>= 0) from the coefficients specified in inEq.
void mergeAndAlignSymbols(IntegerRelation &other)
Merge and align symbol variables of this and other with respect to identifiers.
void removeRedundantLocalVars()
Removes local variables using equalities.
unsigned mergeLocalVars(IntegerRelation &other)
Adds additional local vars to the sets such that they both have the union of the local vars in each s...
MaybeOptimum< SmallVector< Fraction, 8 > > findRationalLexMin() const
Get the lexicographically minimum rational point satisfying the constraints.
IntMatrix inequalities
Coefficients of affine inequalities (in >= 0 form).
virtual bool hasConsistentState() const
Returns false if the fields corresponding to various variable counts, or equality/inequality buffer s...
ArrayRef< DynamicAPInt > getEquality(unsigned idx) const
bool findConstraintWithNonZeroAt(unsigned colIdx, bool isEq, unsigned *rowIdx) const
Searches for a constraint with a non-zero coefficient at colIdx in equality (isEq=true) or inequality...
bool isSubsetOf(const IntegerRelation &other) const
Return whether this is a subset of the given IntegerRelation.
std::unique_ptr< IntegerRelation > clone() const
const PresburgerSpace & getSpace() const
Returns a reference to the underlying space.
void setAndEliminate(unsigned pos, ArrayRef< DynamicAPInt > values)
Sets the values.size() variables starting at pos to the specified values and removes them.
bool isColZero(unsigned pos) const
Returns true if the pos^th column is all zero for both inequalities and equalities.
unsigned getVarKindOffset(VarKind kind) const
Return the index at which the specified kind of vars starts.
virtual void removeVarRange(VarKind kind, unsigned varStart, unsigned varLimit)
virtual void fourierMotzkinEliminate(unsigned pos, bool darkShadow=false, bool *isResultIntegerExact=nullptr)
Eliminates the variable at the specified position using Fourier-Motzkin variable elimination,...
bool removeDuplicateConstraints()
Checks for identical inequalities and eliminates redundant inequalities.
A class for lexicographic optimization without any symbols.
Definition: Simplex.h:478
MaybeOptimum< SmallVector< Fraction, 8 > > findRationalLexMin()
Return the lexicographically minimum rational solution to the constraints.
Definition: Simplex.cpp:235
MaybeOptimum< SmallVector< DynamicAPInt, 8 > > findIntegerLexMin()
Return the lexicographically minimum integer solution to the constraints.
Definition: Simplex.cpp:306
static std::pair< unsigned, LinearTransform > makeTransformToColumnEchelon(const IntMatrix &m)
IntegerRelation applyTo(const IntegerRelation &rel) const
SmallVector< DynamicAPInt, 8 > postMultiplyWithColumn(ArrayRef< DynamicAPInt > colVec) const
void moveColumns(unsigned srcPos, unsigned num, unsigned dstPos)
Move the columns in the source range [srcPos, srcPos + num) to the specified destination [dstPos,...
Definition: Matrix.cpp:266
bool hasConsistentState() const
Return whether the Matrix is in a consistent state with all its invariants satisfied.
Definition: Matrix.cpp:435
unsigned getNumRows() const
Definition: Matrix.h:86
void swapColumns(unsigned column, unsigned otherColumn)
Swap the given columns.
Definition: Matrix.cpp:120
unsigned appendExtraRow()
Add an extra row at the bottom of the matrix and return its position.
Definition: Matrix.cpp:65
void addToColumn(unsigned sourceColumn, unsigned targetColumn, const T &scale)
Add scale multiples of the source column to the target column.
Definition: Matrix.cpp:319
void copyRow(unsigned sourceRow, unsigned targetRow)
Definition: Matrix.cpp:244
void removeColumns(unsigned pos, unsigned count)
Remove the columns having positions pos, pos + 1, ...
Definition: Matrix.cpp:198
void insertColumns(unsigned pos, unsigned count)
Insert columns having positions pos, pos + 1, ...
Definition: Matrix.cpp:152
void removeRow(unsigned pos)
Definition: Matrix.cpp:230
void resizeVertically(unsigned newNRows)
Definition: Matrix.cpp:104
void swapRows(unsigned row, unsigned otherRow)
Swap the given rows.
Definition: Matrix.cpp:110
void reserveRows(unsigned rows)
Reserve enough space to resize to the specified number of rows without reallocations.
Definition: Matrix.cpp:60
void fillRow(unsigned row, const T &value)
Definition: Matrix.cpp:252
void negateRow(unsigned row)
Negate the specified row.
Definition: Matrix.cpp:334
void removeRows(unsigned pos, unsigned count)
Remove the rows having positions pos, pos + 1, ...
Definition: Matrix.cpp:234
bool isBounded() const
Definition: Utils.h:51
OptimumKind getKind() const
Definition: Utils.h:50
This class represents a multi-affine function with the domain as Z^d, where d is the number of domain...
Definition: PWMAFunction.h:41
const PresburgerSpace & getSpace() const
Definition: PWMAFunction.h:170
void removeOutputs(unsigned start, unsigned end)
Remove the specified range of outputs.
unsigned getNumOutputs() const
Definition: PWMAFunction.h:180
ArrayRef< Piece > getAllPieces() const
Return all the pieces of this piece-wise function.
Definition: PWMAFunction.h:204
PresburgerSet getDomain() const
Return the domain of this piece-wise MultiAffineFunction.
A PresburgerRelation represents a union of IntegerRelations that live in the same PresburgerSpace wit...
void setSpace(const PresburgerSpace &oSpace)
Set the space to oSpace.
PresburgerRelation subtract(const PresburgerRelation &set) const
Return the set difference of this set and the given set, i.e., return this \ set.
bool isSubsetOf(const PresburgerRelation &set) const
Return true if this set is a subset of the given set, and false otherwise.
bool isEqual(const PresburgerRelation &set) const
Return true if this set is equal to the given set, and false otherwise.
PresburgerSet unionSet(const PresburgerRelation &set) const
These operations are the same as the ones in PresburgeRelation, they just forward the arguement and r...
PresburgerSpace is the space of all possible values of a tuple of integer valued variables/variables.
void setId(VarKind kind, unsigned pos, Identifier id)
Set the identifier of pos^th variable of the specified kind.
unsigned getNumVarKind(VarKind kind) const
Get the number of vars of the specified kind.
void resetIds()
Reset the stored identifiers in the space.
bool isEqual(const PresburgerSpace &other) const
Returns true if both the spaces are equal including local variables i.e.
bool isUsingIds() const
Returns if identifiers are being used.
void convertVarKind(VarKind srcKind, unsigned srcPos, unsigned num, VarKind dstKind, unsigned dstPos)
Converts variables of the specified kind in the column range [srcPos, srcPos + num) to variables of t...
void removeVarRange(VarKind kind, unsigned varStart, unsigned varLimit)
Removes variables of the specified kind in the column range [varStart, varLimit).
unsigned getVarKindOffset(VarKind kind) const
Return the index at which the specified kind of var starts.
Identifier getId(VarKind kind, unsigned pos) const
Get the identifier of pos^th variable of the specified kind.
VarKind getVarKindAt(unsigned pos) const
Return the VarKind of the var at the specified position.
static PresburgerSpace getSetSpace(unsigned numDims=0, unsigned numSymbols=0, unsigned numLocals=0)
ArrayRef< Identifier > getIds(VarKind kind) const
bool isCompatible(const PresburgerSpace &other) const
Returns true if both the spaces are compatible i.e.
void print(llvm::raw_ostream &os) const
static PresburgerSpace getRelationSpace(unsigned numDomain=0, unsigned numRange=0, unsigned numSymbols=0, unsigned numLocals=0)
void swapVar(VarKind kindA, VarKind kindB, unsigned posA, unsigned posB)
Swaps the posA^th variable of kindA and posB^th variable of kindB.
unsigned insertVar(VarKind kind, unsigned pos, unsigned num=1)
Insert num variables of the specified kind at position pos.
bool isEmpty() const
Returns true if the tableau is empty (has conflicting constraints), false otherwise.
Definition: Simplex.cpp:1070
The Simplex class uses the Normal pivot rule and supports integer emptiness checks as well as detecti...
Definition: Simplex.h:691
std::pair< MaybeOptimum< DynamicAPInt >, MaybeOptimum< DynamicAPInt > > computeIntegerBounds(ArrayRef< DynamicAPInt > coeffs)
Returns a (min, max) pair denoting the minimum and maximum integer values of the given expression.
Definition: Simplex.cpp:2108
bool isMarkedRedundant(unsigned constraintIndex) const
Returns whether the specified constraint has been marked as redundant.
Definition: Simplex.cpp:1409
bool isFlatAlong(ArrayRef< DynamicAPInt > coeffs)
Check if the simplex takes only one rational value along the direction of coeffs.
Definition: Simplex.cpp:2116
bool isBoundedAlongConstraint(unsigned constraintIndex)
Returns whether the perpendicular of the specified constraint is a is a direction along which the pol...
Definition: Simplex.cpp:1399
bool isUnbounded()
Returns true if the polytope is unbounded, i.e., extends to infinity in some direction.
Definition: Simplex.cpp:1471
void detectRedundant(unsigned offset, unsigned count)
Finds a subset of constraints that is redundant, i.e., such that the set of solutions does not change...
Definition: Simplex.cpp:1429
std::optional< SmallVector< Fraction, 8 > > getRationalSample() const
Returns the current sample point, which may contain non-integer (rational) coordinates.
Definition: Simplex.cpp:1571
std::optional< SmallVector< DynamicAPInt, 8 > > findIntegerSample()
Returns an integer sample point if one exists, or std::nullopt otherwise.
Definition: Simplex.cpp:1997
A class to perform symbolic lexicographic optimization, i.e., to find, for every assignment to the sy...
Definition: Simplex.h:572
SymbolicLexOpt computeSymbolicIntegerLexMin()
The lexmin will be stored as a function lexopt from symbols to non-symbols in the result.
Definition: Simplex.cpp:537
BoundType
The type of bound: equal, lower bound or upper bound.
VarKind
Kind of variable.
MaybeLocalRepr computeSingleVarRepr(const IntegerRelation &cst, ArrayRef< bool > foundRepr, unsigned pos, MutableArrayRef< DynamicAPInt > dividend, DynamicAPInt &divisor)
Returns the MaybeLocalRepr struct which contains the indices of the constraints that can be expressed...
Definition: Utils.cpp:228
void mergeLocalVars(IntegerRelation &relA, IntegerRelation &relB, llvm::function_ref< bool(unsigned i, unsigned j)> merge)
Given two relations, A and B, add additional local vars to the sets such that both have the union of ...
Definition: Utils.cpp:289
DynamicAPInt ceil(const Fraction &f)
Definition: Fraction.h:79
Fraction abs(const Fraction &f)
Definition: Fraction.h:107
SmallVector< DynamicAPInt, 8 > getDivUpperBound(ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor, unsigned localVarIdx)
If q is defined to be equal to expr floordiv d, this equivalent to saying that q is an integer and q ...
Definition: Utils.cpp:316
SmallVector< DynamicAPInt, 8 > getDivLowerBound(ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor, unsigned localVarIdx)
Definition: Utils.cpp:328
Include the generated interface declarations.
The struct CountsSnapshot stores the count of each VarKind, and also of each constraint type.
MaybeLocalRepr contains the indices of the constraints that can be expressed as a floordiv of an affi...
Definition: Utils.h:97
Example usage: Print .12, 3.4, 56.7 preAlign = ".", minSpacing = 1, .12 .12 3.4 3....
Definition: Utils.h:303
Represents the result of a symbolic lexicographic optimization computation.
Definition: Simplex.h:529
PWMAFunction lexopt
This maps assignments of symbols to the corresponding lexopt.
Definition: Simplex.h:537
PresburgerSet unboundedDomain
Contains all assignments to the symbols that made the lexopt unbounded.
Definition: Simplex.h:541
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.