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