xref: /llvm-project/mlir/lib/Analysis/Presburger/IntegerRelation.cpp (revision 2740273505ab27c0d8531d35948f0647309842cd)
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 
15 #include "mlir/Analysis/Presburger/IntegerRelation.h"
16 #include "mlir/Analysis/Presburger/Fraction.h"
17 #include "mlir/Analysis/Presburger/LinearTransform.h"
18 #include "mlir/Analysis/Presburger/PWMAFunction.h"
19 #include "mlir/Analysis/Presburger/PresburgerRelation.h"
20 #include "mlir/Analysis/Presburger/PresburgerSpace.h"
21 #include "mlir/Analysis/Presburger/Simplex.h"
22 #include "mlir/Analysis/Presburger/Utils.h"
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 
58 void IntegerRelation::setSpace(const PresburgerSpace &oSpace) {
59   assert(space.getNumVars() == oSpace.getNumVars() && "invalid space!");
60   space = oSpace;
61 }
62 
63 void IntegerRelation::setSpaceExceptLocals(const PresburgerSpace &oSpace) {
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 
79 ArrayRef<Identifier> IntegerRelation::getIds(VarKind kind) {
80   if (!space.isUsingIds())
81     space.resetIds();
82   return space.getIds(kind);
83 }
84 
85 void IntegerRelation::append(const IntegerRelation &other) {
86   assert(space.isEqual(other.getSpace()) && "Spaces must be equal.");
87 
88   inequalities.reserveRows(inequalities.getNumRows() +
89                            other.getNumInequalities());
90   equalities.reserveRows(equalities.getNumRows() + other.getNumEqualities());
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 
100 IntegerRelation IntegerRelation::intersect(IntegerRelation other) const {
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 
112 bool IntegerRelation::isObviouslyEqual(const IntegerRelation &other) const {
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 
136 bool IntegerRelation::isSubsetOf(const IntegerRelation &other) const {
137   assert(space.isCompatible(other.getSpace()) && "Spaces must be compatible.");
138   return PresburgerRelation(*this).isSubsetOf(PresburgerRelation(other));
139 }
140 
141 MaybeOptimum<SmallVector<Fraction, 8>>
142 IntegerRelation::findRationalLexMin() const {
143   assert(getNumSymbolVars() == 0 && "Symbols are not supported!");
144   MaybeOptimum<SmallVector<Fraction, 8>> maybeLexMin =
145       LexSimplex(*this).findRationalLexMin();
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 
161 MaybeOptimum<SmallVector<DynamicAPInt, 8>>
162 IntegerRelation::findIntegerLexMin() const {
163   assert(getNumSymbolVars() == 0 && "Symbols are not supported!");
164   MaybeOptimum<SmallVector<DynamicAPInt, 8>> maybeLexMin =
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 
181 static bool rangeIsZero(ArrayRef<DynamicAPInt> range) {
182   return llvm::all_of(range, [](const DynamicAPInt &x) { return x == 0; });
183 }
184 
185 static void removeConstraintsInvolvingVarRange(IntegerRelation &poly,
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 
199 IntegerRelation::CountsSnapshot IntegerRelation::getCounts() const {
200   return {getSpace(), getNumInequalities(), getNumEqualities()};
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 
209 void IntegerRelation::truncateVarKind(VarKind kind,
210                                       const CountsSnapshot &counts) {
211   truncateVarKind(kind, counts.getSpace().getNumVarKind(kind));
212 }
213 
214 void IntegerRelation::truncate(const CountsSnapshot &counts) {
215   truncateVarKind(VarKind::Domain, counts);
216   truncateVarKind(VarKind::Range, counts);
217   truncateVarKind(VarKind::Symbol, counts);
218   truncateVarKind(VarKind::Local, counts);
219   removeInequalityRange(counts.getNumIneqs(), getNumInequalities());
220   removeEqualityRange(counts.getNumEqs(), getNumEqualities());
221 }
222 
223 PresburgerRelation IntegerRelation::computeReprWithOnlyDivLocals() const {
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,
270                          IntegerPolyhedron(PresburgerSpace::getSetSpace(
271                              /*numDims=*/copy.getNumVars() - numNonDivLocals)))
272           .computeSymbolicIntegerLexMin();
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.
278   PresburgerSpace space = getSpace();
279   space.removeVarRange(VarKind::Local, 0, getNumLocalVars());
280   result.setSpace(space);
281   return result;
282 }
283 
284 SymbolicLexOpt IntegerRelation::findSymbolicIntegerLexMin() const {
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),
290                getVarKindEnd(VarKind::Symbol));
291   isSymbol.set(getVarKindOffset(VarKind::Domain),
292                getVarKindEnd(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,
298                          IntegerPolyhedron(PresburgerSpace::getSetSpace(
299                              /*numDims=*/getNumDomainVars(),
300                              /*numSymbols=*/getNumSymbolVars())),
301                          isSymbol)
302           .computeSymbolicIntegerLexMin();
303 
304   // We want to return only the lexmin over the dims, so strip the locals from
305   // the computed lexmin.
306   result.lexopt.removeOutputs(result.lexopt.getNumOutputs() - getNumLocalVars(),
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.
318 SymbolicLexOpt IntegerRelation::findSymbolicIntegerLexMax() const {
319   IntegerRelation flippedRel = *this;
320   // Flip range sign by flipping the sign of range variables in all constraints.
321   for (unsigned j = getNumDomainVars(),
322                 b = getNumDomainVars() + getNumRangeVars();
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 
349 PresburgerRelation
350 IntegerRelation::subtract(const PresburgerRelation &set) const {
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 
368 void IntegerRelation::addEquality(ArrayRef<DynamicAPInt> eq) {
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 
375 void IntegerRelation::addInequality(ArrayRef<DynamicAPInt> inEq) {
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 
442 void IntegerRelation::removeEquality(unsigned pos) {
443   equalities.removeRow(pos);
444 }
445 
446 void IntegerRelation::removeInequality(unsigned pos) {
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 
479 void IntegerRelation::clearConstraints() {
480   equalities.resizeVertically(0);
481   inequalities.resizeVertically(0);
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`).
487 void IntegerRelation::getLowerAndUpperBoundIndices(
488     unsigned pos, SmallVectorImpl<unsigned> *lbIndices,
489     SmallVectorImpl<unsigned> *ubIndices, SmallVectorImpl<unsigned> *eqIndices,
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 
538 bool IntegerRelation::hasConsistentState() const {
539   if (!inequalities.hasConsistentState())
540     return false;
541   if (!equalities.hasConsistentState())
542     return false;
543   return true;
544 }
545 
546 void IntegerRelation::setAndEliminate(unsigned pos,
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 
563 void IntegerRelation::clearAndCopyFrom(const IntegerRelation &other) {
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 
585 void IntegerRelation::normalizeConstraintsByGCD() {
586   for (unsigned i = 0, e = getNumEqualities(); i < e; ++i)
587     equalities.normalizeRow(i);
588   for (unsigned i = 0, e = getNumInequalities(); i < e; ++i)
589     inequalities.normalizeRow(i);
590 }
591 
592 bool IntegerRelation::hasInvalidConstraint() const {
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.
695 bool IntegerRelation::isEmpty() const {
696   if (isEmptyByGCDTest() || hasInvalidConstraint())
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++) {
721     tmpCst.fourierMotzkinEliminate(
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 
741 bool IntegerRelation::isObviouslyEmpty() const {
742   return isEmptyByGCDTest() || hasInvalidConstraint();
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.
759 bool IntegerRelation::isEmptyByGCDTest() const {
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.
782 IntMatrix IntegerRelation::getBoundedDirections() const {
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 
823 bool IntegerRelation::isIntegerEmpty() const { return !findIntegerSample(); }
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>>
871 IntegerRelation::findIntegerSample() const {
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.
889   IntMatrix m = getBoundedDirections();
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 =
895       LinearTransform::makeTransformToColumnEchelon(m);
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.
991 bool IntegerRelation::containsPoint(ArrayRef<DynamicAPInt> point) const {
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>>
1012 IntegerRelation::containsPointNoLocal(ArrayRef<DynamicAPInt> point) const {
1013   assert(point.size() == getNumVars() - getNumLocalVars() &&
1014          "Point should contain all vars except locals!");
1015   assert(getVarKindOffset(VarKind::Local) == getNumVars() - getNumLocalVars() &&
1016          "This function depends on locals being stored last!");
1017   IntegerRelation copy = *this;
1018   copy.setAndEliminate(0, point);
1019   return copy.findIntegerSample();
1020 }
1021 
1022 DivisionRepr
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);
1029   DivisionRepr divs(getNumVars(), getNumLocalVars());
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.
1065 void IntegerRelation::gcdTightenInequalities() {
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 
1086   gcdTightenInequalities();
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);
1106       equalities.normalizeRow(i);
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);
1113       inequalities.normalizeRow(i);
1114     }
1115     removeEquality(pivotRow);
1116     gcdTightenInequalities();
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 
1125 bool IntegerRelation::gaussianEliminate() {
1126   gcdTightenInequalities();
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);
1149       equalities.normalizeRow(i);
1150     }
1151     for (unsigned i = 0, ineqs = getNumInequalities(); i < ineqs; ++i) {
1152       eliminateFromConstraint(this, i, pivotRow, firstVar, 0, false);
1153       inequalities.normalizeRow(i);
1154     }
1155     gcdTightenInequalities();
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.
1178 void IntegerRelation::removeRedundantInequalities() {
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   }
1205   inequalities.resizeVertically(pos);
1206 }
1207 
1208 // A more complex check to eliminate redundant inequalities and equalities. Uses
1209 // Simplex to check if a constraint is redundant.
1210 void IntegerRelation::removeRedundantConstraints() {
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.
1214   gcdTightenInequalities();
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   }
1226   inequalities.resizeVertically(pos);
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   }
1238   equalities.resizeVertically(pos);
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);
1265   SmallVector<DynamicAPInt, 8> dim(getNumVars() + 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`.
1314 void IntegerRelation::mergeAndAlignSymbols(IntegerRelation &other) {
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) {
1338     insertVar(VarKind::Symbol, i);
1339     space.setId(VarKind::Symbol, i, other.space.getId(VarKind::Symbol, 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.
1356 unsigned IntegerRelation::mergeLocalVars(IntegerRelation &other) {
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 
1387 bool IntegerRelation::hasOnlyDivLocals() const {
1388   return getLocalReprs().hasAllReprs();
1389 }
1390 
1391 void IntegerRelation::removeDuplicateDivs() {
1392   DivisionRepr divs = getLocalReprs();
1393   auto merge = [this](unsigned i, unsigned j) -> bool {
1394     eliminateRedundantLocalVar(i, j);
1395     return true;
1396   };
1397   divs.removeDuplicateDivs(merge);
1398 }
1399 
1400 void IntegerRelation::simplify() {
1401   bool changed = true;
1402   // Repeat until we reach a fixed point.
1403   while (changed) {
1404     if (isObviouslyEmpty())
1405       return;
1406     changed = false;
1407     normalizeConstraintsByGCD();
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.
1420 void IntegerRelation::removeRedundantLocalVars() {
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)
1424     equalities.normalizeRow(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);
1448         equalities.normalizeRow(k);
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 
1498 void IntegerRelation::addBound(BoundType type, ArrayRef<DynamicAPInt> expr,
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];
1505   inequalities(inequalities.getNumRows() - 1, getNumCols() - 1) +=
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.
1514 void IntegerRelation::addLocalFloorDiv(ArrayRef<DynamicAPInt> dividend,
1515                                        const DynamicAPInt &divisor) {
1516   assert(dividend.size() == getNumCols() && "incorrect dividend size");
1517   assert(divisor > 0 && "positive divisor expected");
1518 
1519   appendVar(VarKind::Local);
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)).
1593 std::optional<DynamicAPInt> IntegerRelation::getConstantBoundOnDimSize(
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>
1721 IntegerRelation::computeConstantLowerOrUpperBound(unsigned pos) {
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>
1778 IntegerRelation::getConstantBound(BoundType type, unsigned pos) const {
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.
1828 void IntegerRelation::removeTrivialRedundancy() {
1829   gcdTightenInequalities();
1830   normalizeConstraintsByGCD();
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 
1888   inequalities.resizeVertically(pos);
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.
1961   gcdTightenInequalities();
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) {
2021       SmallVector<DynamicAPInt, 4> ineq;
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) {
2058     SmallVector<DynamicAPInt, 4> ineq;
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++) {
2073     SmallVector<DynamicAPInt, 4> eq;
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;
2120     fourierMotzkinEliminate(
2121         getBestVarToEliminate(*this, pos, pos + numToEliminate));
2122   }
2123 
2124   // Fast/trivial simplifications.
2125   gcdTightenInequalities();
2126   // Normalize constraints after tightening since the latter impacts this, but
2127   // not the other way round.
2128   normalizeConstraintsByGCD();
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,
2138                                     ArrayRef<DynamicAPInt> b) {
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.
2156 static void getCommonConstraints(const IntegerRelation &a,
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
2181 IntegerRelation::unionBoundingBox(const IntegerRelation &otherCst) {
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.
2187   IntegerRelation commonCst(PresburgerSpace::getRelationSpace());
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.
2198   SmallVector<DynamicAPInt, 4> minLb(getNumSymbolVars() + 1);
2199   SmallVector<DynamicAPInt, 4> maxUb(getNumSymbolVars() + 1);
2200   // To compute final new lower and upper bounds for the union.
2201   SmallVector<DynamicAPInt, 8> newLb(getNumCols()), newUb(getNumCols());
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);
2283   removeTrivialRedundancy();
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 
2346 IntegerPolyhedron IntegerRelation::getDomainSet() const {
2347   IntegerRelation copyRel = *this;
2348 
2349   // Convert Range variables to Local variables.
2350   copyRel.convertVarKind(VarKind::Range, 0, getNumVarKind(VarKind::Range),
2351                          VarKind::Local);
2352 
2353   // Convert Domain variables to SetDim(Range) variables.
2354   copyRel.convertVarKind(VarKind::Domain, 0, getNumVarKind(VarKind::Domain),
2355                          VarKind::SetDim);
2356 
2357   return IntegerPolyhedron(std::move(copyRel));
2358 }
2359 
2360 bool IntegerRelation::removeDuplicateConstraints() {
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) {
2409       addEquality(getInequality(k));
2410       removeInequality(k);
2411       removeInequality(l);
2412     } else
2413       *this = getEmpty(getSpace());
2414     break;
2415   }
2416 
2417   return changed;
2418 }
2419 
2420 IntegerPolyhedron IntegerRelation::getRangeSet() const {
2421   IntegerRelation copyRel = *this;
2422 
2423   // Convert Domain variables to Local variables.
2424   copyRel.convertVarKind(VarKind::Domain, 0, getNumVarKind(VarKind::Domain),
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 
2433 void IntegerRelation::intersectDomain(const IntegerPolyhedron &poly) {
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.
2442   rel.appendVar(VarKind::Range, getNumRangeVars());
2443 
2444   // Intersect in place.
2445   mergeLocalVars(rel);
2446   append(rel);
2447 }
2448 
2449 void IntegerRelation::intersectRange(const IntegerPolyhedron &poly) {
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.
2456   rel.appendVar(VarKind::Domain, getNumDomainVars());
2457 
2458   mergeLocalVars(rel);
2459   append(rel);
2460 }
2461 
2462 void IntegerRelation::inverse() {
2463   unsigned numRangeVars = getNumVarKind(VarKind::Range);
2464   convertVarKind(VarKind::Domain, 0, getVarKindEnd(VarKind::Domain),
2465                  VarKind::Range);
2466   convertVarKind(VarKind::Range, 0, numRangeVars, VarKind::Domain);
2467 }
2468 
2469 void IntegerRelation::compose(const IntegerRelation &rel) {
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).
2483   appendVar(VarKind::Range, copyRel.getNumRangeVars());
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.
2489   intersectRange(IntegerPolyhedron(copyRel));
2490 
2491   // Project out B in R1.
2492   convertVarKind(VarKind::Range, 0, numBVars, VarKind::Local);
2493 }
2494 
2495 void IntegerRelation::applyDomain(const IntegerRelation &rel) {
2496   inverse();
2497   compose(rel);
2498   inverse();
2499 }
2500 
2501 void IntegerRelation::applyRange(const IntegerRelation &rel) { compose(rel); }
2502 
2503 void IntegerRelation::printSpace(raw_ostream &os) const {
2504   space.print(os);
2505   os << getNumConstraints() << " constraints\n";
2506 }
2507 
2508 void IntegerRelation::removeTrivialEqualities() {
2509   for (int i = getNumEqualities() - 1; i >= 0; --i)
2510     if (rangeIsZero(getEquality(i)))
2511       removeEquality(i);
2512 }
2513 
2514 bool IntegerRelation::isFullDim() {
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.
2521   removeTrivialEqualities();
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 
2533 void IntegerRelation::mergeAndCompose(const IntegerRelation &other) {
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())
2578       space.setId(VarKind::Domain, i,
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())
2583       result.space.setId(VarKind::Range, i, space.getId(VarKind::Range, i));
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 }
2627 IntegerPolyhedron
2628 IntegerPolyhedron::intersect(const IntegerPolyhedron &other) const {
2629   return IntegerPolyhedron(IntegerRelation::intersect(other));
2630 }
2631 
2632 PresburgerSet IntegerPolyhedron::subtract(const PresburgerSet &other) const {
2633   return PresburgerSet(IntegerRelation::subtract(other));
2634 }
2635