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"
39#define DEBUG_TYPE "presburger"
44using llvm::SmallDenseMap;
47 return std::make_unique<IntegerRelation>(*
this);
51 return std::make_unique<IntegerPolyhedron>(*
this);
60 assert(oSpace.
getNumLocalVars() == 0 &&
"no locals should be present!");
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);
76 if (!
space.isUsingIds())
78 return space.getIds(kind);
82 assert(
space.isEqual(other.
getSpace()) &&
"Spaces must be equal.");
98 result.mergeLocalVars(other);
104 assert(
space.isCompatible(other.
getSpace()) &&
"Spaces must be compatible.");
118 for (
unsigned j = 0;
j < cols; ++
j) {
124 for (
unsigned j = 0;
j < cols; ++
j) {
133 assert(
space.isCompatible(other.
getSpace()) &&
"Spaces must be compatible.");
152 "Incorrect number of vars in lexMin!");
172 "Incorrect number of vars in lexMin!");
178 return llvm::all_of(range, [](
const DynamicAPInt &x) {
return x == 0; });
182 unsigned begin,
unsigned count) {
201 assert(num <= curNum &&
"Can't truncate to more vars!");
230 copy.getLocalReprs(&reprs);
234 unsigned numNonDivLocals = 0;
236 for (
unsigned i = 0, e =
copy.getNumLocalVars(); i < e - numNonDivLocals;) {
241 copy.swapVar(offset + i, offset + e - numNonDivLocals - 1);
242 std::swap(reprs[i], reprs[e - numNonDivLocals - 1]);
250 if (numNonDivLocals == 0)
267 copy.getNumVars() - numNonDivLocals)))
284 llvm::SmallBitVector isSymbol(
getNumVars(),
false);
303 result.lexopt.getNumOutputs());
328 symbolicIntegerLexMax(
331 for (
auto &flippedPiece :
333 IntMatrix mat = flippedPiece.output.getOutputMatrix();
334 for (
unsigned i = 0, e = mat.
getNumRows(); i < e; i++)
338 symbolicIntegerLexMax.lexopt.addPiece(piece);
340 symbolicIntegerLexMax.unboundedDomain =
342 return symbolicIntegerLexMax;
353 unsigned insertPos =
space.insertVar(kind, pos, num);
367 for (
unsigned i = 0, e = eq.size(); i < e; ++i)
374 for (
unsigned i = 0, e = inEq.size(); i < e; ++i)
388 if (varStart >= varLimit)
393 equalities.removeColumns(offset + varStart, varLimit - varStart);
394 inequalities.removeColumns(offset + varStart, varLimit - varStart);
397 space.removeVarRange(kind, varStart, varLimit);
403 if (varStart >= varLimit)
409 auto removeVarKindInRange = [
this](
VarKind kind,
unsigned &start,
418 unsigned relativeStart =
419 start <= offset ? 0 : std::min(num, start - offset);
420 unsigned relativeLimit =
421 limit <= offset ? 0 : std::min(num, limit - offset);
429 limit -= relativeLimit - relativeStart;
467 assert(posA <
getNumVars() &&
"invalid position A");
468 assert(posB <
getNumVars() &&
"invalid position B");
477 space.swapVar(kindA, kindB, relativePosA, relativePosB);
494 unsigned offset,
unsigned num)
const {
495 assert(pos <
getNumVars() &&
"invalid position");
496 assert(offset + num <
getNumCols() &&
"invalid range");
500 auto containsConstraintDependentOnRange = [&](
unsigned r,
bool isEq) {
503 for (c = offset, f = offset + num; c < f; ++c) {
517 if (containsConstraintDependentOnRange(r,
false))
519 if (
atIneq(r, pos) >= 1) {
521 lbIndices->emplace_back(r);
522 }
else if (
atIneq(r, pos) <= -1) {
524 ubIndices->emplace_back(r);
534 if (
atEq(r, pos) == 0)
536 if (containsConstraintDependentOnRange(r,
true))
538 eqIndices->emplace_back(r);
555 "invalid position or too many values");
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]);
571std::optional<unsigned>
573 assert(colIdx <
getNumCols() &&
"position out of bounds");
574 auto at = [&](
unsigned rowIdx) -> DynamicAPInt {
575 return isEq ?
atEq(rowIdx, colIdx) :
atIneq(rowIdx, colIdx);
578 for (
unsigned rowIdx = 0; rowIdx < e; ++rowIdx) {
594 auto check = [&](
bool isEq) ->
bool {
597 for (
unsigned i = 0, e = numRows; i < e; ++i) {
599 for (
j = 0;
j < numCols - 1; ++
j) {
605 if (
j < numCols - 1) {
610 DynamicAPInt v = isEq ?
atEq(i, numCols - 1) :
atIneq(i, numCols - 1);
611 if ((isEq && v != 0) || (!isEq && v < 0)) {
626 unsigned rowIdx,
unsigned pivotRow,
627 unsigned pivotCol,
unsigned elimColStart,
630 if (isEq && rowIdx == pivotRow)
632 auto at = [&](
unsigned i,
unsigned j) -> DynamicAPInt {
633 return isEq ? constraints->
atEq(i,
j) : constraints->
atIneq(i,
j);
635 DynamicAPInt leadCoeff = at(rowIdx, pivotCol);
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);
646 for (
unsigned j = 0;
j < numCols; ++
j) {
648 if (
j >= elimColStart &&
j < pivotCol)
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;
663 unsigned start,
unsigned end) {
666 auto getProductOfNumLowerUpperBounds = [&](
unsigned pos) {
670 if (cst.
atIneq(r, pos) > 0) {
672 }
else if (cst.
atIneq(r, pos) < 0) {
676 return numLb * numUb;
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;
707 unsigned currentPos = 0;
720 for (
unsigned i = 0, e = tmpCst.
getNumVars(); i < e; i++) {
729 LDBG() <<
"FM constraint explosion detected";
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)));
767 DynamicAPInt v =
abs(
atEq(i, numCols - 1));
768 if (gcd > 0 && (v % gcd != 0)) {
789 assert(!simplex.
isEmpty() &&
"It is not meaningful to ask whether a "
790 "direction is bounded in an empty set.");
797 boundedIneqs.emplace_back(i);
807 for (
unsigned i : boundedIneqs) {
808 for (
unsigned col = 0; col < dirsNumCols; ++col)
809 dirs(row, col) =
atIneq(i, col);
815 for (
unsigned col = 0; col < dirsNumCols; ++col)
816 dirs(row, col) =
atEq(i, col);
870std::optional<SmallVector<DynamicAPInt, 8>>
894 std::pair<unsigned, LinearTransform>
result =
903 unsigned numBoundedDims =
result.first;
904 unsigned numUnboundedDims =
getNumVars() - numBoundedDims;
910 std::optional<SmallVector<DynamicAPInt, 8>> boundedSample =
915 "Simplex returned an invalid sample!");
949 DynamicAPInt coeff = cone.
atIneq(i,
j);
959 Simplex shrunkenConeSimplex(cone);
960 assert(!shrunkenConeSimplex.
isEmpty() &&
"Shrunken cone cannot be empty!");
967 llvm::map_range(shrunkenConeSample,
ceil));
971 sample.append(coneSample.begin(), coneSample.end());
972 return transform.postMultiplyWithColumn(sample);
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];
1011std::optional<SmallVector<DynamicAPInt, 8>>
1014 "Point should contain all vars except locals!");
1016 "This function depends on locals being stored last!");
1018 copy.setAndEliminate(0, point);
1019 return copy.findIntegerSample();
1026 foundRepr[i] =
true;
1036 if (!foundRepr[i + localOffset]) {
1046 foundRepr[localOffset + i] =
true;
1071 atIneq(i, numCols - 1) = floorDiv(
atIneq(i, numCols - 1), gcd);
1078 unsigned posLimit) {
1083 if (posStart >= posLimit)
1088 unsigned pivotCol = 0;
1089 for (pivotCol = posStart; pivotCol < posLimit; ++pivotCol) {
1091 std::optional<unsigned> pivotRow =
1118 posLimit = pivotCol;
1121 return posLimit - posStart;
1124static std::optional<unsigned>
1128 "position out of bounds");
1131 if (rel.
atEq(rowIdx, colIdx) != 0)
1134 return std::nullopt;
1140 unsigned nowDone, eqs;
1141 std::optional<unsigned> pivotRow;
1144 for (; firstVar < vars; ++firstVar) {
1150 if (firstVar >= vars)
1154 if (*pivotRow > nowDone) {
1156 *pivotRow = nowDone;
1160 for (
unsigned i = nowDone + 1; i < eqs; ++i) {
1181 for (
unsigned i = nowDone; i < eqs; ++i) {
1182 if (
atEq(i, vars) == 0)
1239 for (
unsigned r = 0; r < numIneqs; r++) {
1265 return DynamicAPInt(0);
1281 DynamicAPInt count(1);
1283 bool hasUnboundedVar =
false;
1289 assert((!
min.isEmpty() && !
max.isEmpty()) &&
1290 "Polytope should be rationally non-empty!");
1294 if (
min.isUnbounded() ||
max.isUnbounded()) {
1295 hasUnboundedVar =
true;
1301 if (
min.getBoundedOptimum() >
max.getBoundedOptimum())
1302 return DynamicAPInt(0);
1304 count *= (*
max - *
min + 1);
1308 return DynamicAPInt(0);
1309 if (hasUnboundedVar)
1319 posA += localOffset;
1320 posB += localOffset;
1333 "both relations need to have identifers to merge and align");
1342 const Identifier *itr = std::find(findBegin, findEnd, identifier);
1343 if (itr != findEnd) {
1346 std::distance(findBegin, itr));
1381 auto merge = [&relA, &relB, oldALocals](
unsigned i,
unsigned j) ->
bool {
1410 auto merge = [
this](
unsigned i,
unsigned j) ->
bool {
1444 unsigned i, e,
j, f;
1463 if (
atEq(k,
j) != 0) {
1480 unsigned varLimit,
VarKind dstKind,
1482 assert(varLimit <=
getNumVarKind(srcKind) &&
"invalid id range");
1484 if (varStart >= varLimit)
1489 unsigned convertCount = varLimit - varStart;
1490 int forwardMoveOffset = dstOffset > srcOffset ? -convertCount : 0;
1492 equalities.moveColumns(srcOffset + varStart, convertCount,
1493 dstOffset + pos + forwardMoveOffset);
1494 inequalities.moveColumns(srcOffset + varStart, convertCount,
1495 dstOffset + pos + forwardMoveOffset);
1497 space.convertVarKind(srcKind, varStart, varLimit - varStart, dstKind, pos);
1501 const DynamicAPInt &value) {
1516 const DynamicAPInt &value) {
1520 for (
unsigned i = 0, e = expr.size(); i < e; ++i)
1533 const DynamicAPInt &divisor) {
1534 assert(dividend.size() ==
getNumCols() &&
"incorrect dividend size");
1535 assert(divisor > 0 &&
"positive divisor expected");
1540 dividendCopy.insert(dividendCopy.end() - 1, DynamicAPInt(0));
1549 const DynamicAPInt &modulus) {
1550 assert(exprs.size() ==
getNumCols() &&
"incorrect exprs size");
1551 assert(modulus > 0 &&
"positive modulus expected");
1563 exprsCopy.insert(exprsCopy.end() - 1,
1564 {DynamicAPInt(-modulus), DynamicAPInt(-1)});
1570 assert(pos <
getNumVars() &&
"invalid position");
1572 DynamicAPInt v =
atEq(r, pos);
1578 for (c = 0; c < f; c++) {
1581 if (
atEq(r, c) != 0) {
1594 assert(pos <
getNumVars() &&
"invalid position");
1600 assert(
atEq(rowIdx, pos) *
atEq(rowIdx, pos) == 1);
1607 for (
unsigned s = pos, t = pos, e = pos + num; s < e; s++) {
1630 unsigned *minLbPos,
unsigned *minUbPos)
const {
1631 assert(pos <
getNumDimVars() &&
"Invalid variable position");
1643 [](
const DynamicAPInt &coeff) { return coeff == 0; }))
1644 return std::nullopt;
1653 DynamicAPInt v =
atEq(eqPos, pos);
1660 (*ub)[c] = (*lb)[c];
1662 assert(boundFloorDivisor &&
1663 "both lb and divisor or none should be provided");
1664 *boundFloorDivisor = 1;
1670 return DynamicAPInt(1);
1681 return std::nullopt;
1694 std::optional<DynamicAPInt> minDiff;
1695 unsigned minLbPosition = 0, minUbPosition = 0;
1696 for (
auto ubPos : ubIndices) {
1697 for (
auto lbPos : lbIndices) {
1715 diff = std::max<DynamicAPInt>(diff, DynamicAPInt(0));
1716 if (minDiff == std::nullopt || diff < minDiff) {
1718 minLbPosition = lbPos;
1719 minUbPosition = ubPos;
1723 if (lb && minDiff) {
1732 *boundFloorDivisor =
atIneq(minLbPosition, pos);
1733 assert(*boundFloorDivisor == -
atIneq(minUbPosition, pos));
1748 *minLbPos = minLbPosition;
1750 *minUbPos = minUbPosition;
1759 if (numConstraints == 0)
1767 while (!rowStack.empty() || !colStack.empty()) {
1768 if (!rowStack.empty()) {
1769 unsigned currentRow = rowStack.pop_back_val();
1772 for (
unsigned colIndex = 0; colIndex <
getNumVars(); ++colIndex) {
1774 relatedCols.insert(colIndex).second) {
1775 colStack.push_back(colIndex);
1779 unsigned currentCol = colStack.pop_back_val();
1782 for (
unsigned rowIndex = 0; rowIndex < numConstraints; ++rowIndex) {
1784 relatedRows.insert(rowIndex).second) {
1785 rowStack.push_back(rowIndex);
1792 for (
int constraintId = numConstraints - 1; constraintId >= 0;
1794 if (!relatedRows.contains(constraintId))
1799template <
bool isLower>
1800std::optional<DynamicAPInt>
1802 assert(pos <
getNumVars() &&
"invalid position");
1827 return std::nullopt;
1829 std::optional<DynamicAPInt> minOrMaxConst;
1838 }
else if (
atIneq(r, 0) >= 0) {
1843 for (c = 0, f =
getNumCols() - 1; c < f; c++)
1844 if (c != 0 &&
atIneq(r, c) != 0)
1850 DynamicAPInt boundConst =
1854 if (minOrMaxConst == std::nullopt || boundConst > minOrMaxConst)
1855 minOrMaxConst = boundConst;
1857 if (minOrMaxConst == std::nullopt || boundConst < minOrMaxConst)
1858 minOrMaxConst = boundConst;
1861 return minOrMaxConst;
1864std::optional<DynamicAPInt>
1868 .computeConstantLowerOrUpperBound<
true>(pos);
1871 .computeConstantLowerOrUpperBound<
false>(pos);
1874 std::optional<DynamicAPInt> lb =
1877 std::optional<DynamicAPInt>
ub =
1879 .computeConstantLowerOrUpperBound<
false>(pos);
1880 return (lb &&
ub && *lb == *
ub) ? std::optional<DynamicAPInt>(*
ub)
1890 for (
unsigned c = pos; c < pos + num; c++) {
1899 for (
unsigned c = pos; c < pos + num; c++) {
1900 if (
atEq(r, c) != 0)
1923 rowsWithoutConstTerm;
1926 auto isTriviallyValid = [&](
unsigned r) ->
bool {
1927 for (
unsigned c = 0, e =
getNumCols() - 1; c < e; c++) {
1938 if (isTriviallyValid(r)) {
1939 redunIneq[r] =
true;
1948 auto rowWithoutConstTerm =
1951 rowsWithoutConstTerm.insert({rowWithoutConstTerm, {r, constTerm}});
1954 auto &val = ret.first->second;
1955 if (val.second > constTerm) {
1957 redunIneq[val.first] =
true;
1958 val = {r, constTerm};
1961 redunIneq[r] =
true;
1979#define DEBUG_TYPE "fm"
2025 bool *isResultIntegerExact) {
2026 LDBG() <<
"FM input (eliminate pos " << pos <<
"):";
2028 assert(pos <
getNumVars() &&
"invalid position");
2033 if (
atEq(r, pos) != 0) {
2037 assert(ret.succeeded() &&
"Gaussian elimination guaranteed to succeed");
2038 LDBG() <<
"FM output (through Gaussian elimination):";
2052 LDBG() <<
"FM output:";
2062 std::vector<unsigned> nbIndices;
2069 if (
atIneq(r, pos) == 0) {
2071 nbIndices.emplace_back(r);
2072 }
else if (
atIneq(r, pos) >= 1) {
2074 lbIndices.emplace_back(r);
2077 ubIndices.emplace_back(r);
2084 newSpace.
removeVarRange(idKindRemove, relativePos, relativePos + 1);
2087 IntegerRelation newRel(lbIndices.size() * ubIndices.size() + nbIndices.size(),
2091 bool allLCMsAreOne =
true;
2103 for (
auto ubPos : ubIndices) {
2104 for (
auto lbPos : lbIndices) {
2107 DynamicAPInt lbCoeff =
atIneq(lbPos, pos);
2111 DynamicAPInt ubCoeff = -
atIneq(ubPos, pos);
2113 for (
unsigned l = 0, e =
getNumCols(); l < e; l++) {
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!");
2122 allLCMsAreOne =
false;
2127 ineq[ineq.size() - 1] += lbCoeff * ubCoeff - lbCoeff - ubCoeff + 1;
2135 LDBG() <<
"FM isResultIntegerExact: " << allLCMsAreOne;
2136 if (allLCMsAreOne && isResultIntegerExact)
2137 *isResultIntegerExact =
true;
2140 for (
auto nbPos : nbIndices) {
2143 for (
unsigned l = 0, e =
getNumCols(); l < e; l++) {
2146 ineq.emplace_back(
atIneq(nbPos, l));
2152 lbIndices.size() * ubIndices.size() + nbIndices.size());
2158 for (
unsigned l = 0, e =
getNumCols(); l < e; l++) {
2161 eq.emplace_back(
atEq(r, l));
2172 LDBG() <<
"FM output:";
2177#define DEBUG_TYPE "presburger"
2185 assert(pos + num <
getNumCols() &&
"invalid range");
2188 unsigned currentPos = pos;
2189 unsigned numToEliminate = num;
2190 unsigned numGaussianEliminated = 0;
2193 unsigned curNumEliminated =
2196 numToEliminate -= curNumEliminated + 1;
2197 numGaussianEliminated += curNumEliminated;
2201 for (
unsigned i = 0; i < num - numGaussianEliminated; i++) {
2202 unsigned numToEliminate = num - numGaussianEliminated - i;
2216enum BoundCmpResult { Greater, Less, Equal,
Unknown };
2222 assert(a.size() ==
b.size());
2228 if (!std::equal(a.begin(), a.end() - 1,
b.begin()))
2231 if (a.back() ==
b.back())
2234 return a.back() <
b.back() ? Less : Greater;
2244 for (
unsigned s = 0, f =
b.getNumInequalities(); s < f; ++s) {
2252 for (
unsigned s = 0, f =
b.getNumEqualities(); s < f; ++s) {
2265 assert(
space.isEqual(otherCst.
getSpace()) &&
"Spaces should match.");
2273 std::vector<SmallVector<DynamicAPInt, 8>> boundingLbs;
2274 std::vector<SmallVector<DynamicAPInt, 8>> boundingUbs;
2286 DynamicAPInt lbFloorDivisor, otherLbFloorDivisor;
2289 if (!extent.has_value())
2295 d, &otherLb, &otherLbFloorDivisor, &otherUb);
2296 if (!otherExtent.has_value() || lbFloorDivisor != otherLbFloorDivisor)
2300 assert(lbFloorDivisor > 0 &&
"divisor always expected to be positive");
2302 auto res = compareBounds(lb, otherLb);
2304 if (res == BoundCmpResult::Less || res == BoundCmpResult::Equal) {
2309 minLb.back() -= lbFloorDivisor - 1;
2310 }
else if (res == BoundCmpResult::Greater) {
2312 minLb.back() -= otherLbFloorDivisor - 1;
2317 if (!constLb.has_value() || !constOtherLb.has_value())
2319 llvm::fill(minLb, 0);
2320 minLb.back() = std::min(*constLb, *constOtherLb);
2324 auto uRes = compareBounds(
ub, otherUb);
2325 if (uRes == BoundCmpResult::Greater || uRes == BoundCmpResult::Equal) {
2327 }
else if (uRes == BoundCmpResult::Less) {
2333 if (!constUb.has_value() || !constOtherUb.has_value())
2335 llvm::fill(maxUb, 0);
2336 maxUb.back() = std::max(*constUb, *constOtherUb);
2339 llvm::fill(newLb, 0);
2340 llvm::fill(newUb, 0);
2344 newLb[d] = lbFloorDivisor;
2345 newUb[d] = -lbFloorDivisor;
2348 std::transform(newLb.begin() +
getNumDimVars(), newLb.end(),
2350 std::negate<DynamicAPInt>());
2353 boundingLbs.emplace_back(newLb);
2354 boundingUbs.emplace_back(newUb);
2386 assert(pos < cst.
getNumVars() &&
"invalid start position");
2387 assert(pos + num <= cst.
getNumVars() &&
"invalid limit");
2392 for (c = pos; c < pos + num; ++c) {
2393 if (cst.
atIneq(r, c) != 0)
2397 nbIneqIndices.emplace_back(r);
2403 for (c = pos; c < pos + num; ++c) {
2404 if (cst.
atEq(r, c) != 0)
2408 nbEqIndices.emplace_back(r);
2413 assert(pos + num <=
getNumVars() &&
"invalid range");
2422 for (
auto nbIndex : llvm::reverse(nbIneqIndices))
2424 for (
auto nbIndex : llvm::reverse(nbEqIndices))
2452 hashTable.insert({row, 0});
2453 for (
unsigned k = 1; k < ineqs; ++k) {
2455 if (hashTable.try_emplace(row, k).second)
2459 unsigned l = hashTable[row];
2470 for (
unsigned k = 0; k < ineqs; ++k) {
2472 negIneq.assign(row.begin(), row.end());
2473 for (DynamicAPInt &ele : negIneq)
2475 if (!hashTable.contains(negIneq))
2480 unsigned l = hashTable[row];
2482 if (sum > 0 || l == k)
2518 "Domain set is not compatible with poly");
2534 "Range set is not compatible with poly");
2554 "Range of `this` should be compatible with Domain of `rel`");
2591 "Range product is only defined for relations with equal domains");
2608 copy.insert(
copy.begin() + relRangeVarStart,
2609 numThisRangeVars + numNewSymbolVars, DynamicAPInt(0));
2616 copy.insert(
copy.begin() + relRangeVarStart,
2617 numThisRangeVars + numNewSymbolVars, DynamicAPInt(0));
2656 "Domain of this and range of other do not match");
2697 for (
unsigned i = 0, e =
result.getNumDomainVars(); i < e; ++i)
2708 result.removeRedundantLocalVars();
2724 constexpr unsigned kMinSpacing = 1;
2745 "Domain has to be zero in a set");
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.
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.
void removeDuplicateDivs(llvm::function_ref< bool(unsigned i, unsigned j)> merge)
Removes duplicate divisions.
void clearRepr(unsigned i)
DynamicAPInt & getDenom(unsigned i)
MutableArrayRef< DynamicAPInt > getDividend(unsigned i)
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.
void removeConstraint(unsigned pos)
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.
CountsSnapshot getCounts() const
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,...
unsigned getNumSymbolVars() const
void removeEquality(unsigned pos)
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 removeDuplicateDivs()
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.
unsigned getNumDomainVars() const
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.
void removeTrivialEqualities()
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.
unsigned getNumVars() const
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.
unsigned getNumRangeVars() const
unsigned getNumLocalVars() const
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.
unsigned getNumDimAndSymbolVars() const
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 removeInequality(unsigned pos)
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...
unsigned getNumConstraints() const
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...
unsigned getNumInequalities() const
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.
unsigned getNumEqualities() const
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.
unsigned getNumDimVars() const
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.
MaybeOptimum< SmallVector< Fraction, 8 > > findRationalLexMin()
Return the lexicographically minimum rational solution to the constraints.
MaybeOptimum< SmallVector< DynamicAPInt, 8 > > findIntegerLexMin()
Return the lexicographically minimum integer solution to the constraints.
unsigned getNumRows() const
void fillRow(unsigned row, const T &value)
void negateRow(unsigned row)
Negate the specified row.
OptimumKind getKind() const
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.
unsigned getNumVars() const
unsigned getNumLocalVars() const
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.
The Simplex class uses the Normal pivot rule and supports integer emptiness checks as well as detecti...
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.
bool isMarkedRedundant(unsigned constraintIndex) const
Returns whether the specified constraint has been marked as redundant.
bool isFlatAlong(ArrayRef< DynamicAPInt > coeffs)
Check if the simplex takes only one rational value along the direction of coeffs.
bool isBoundedAlongConstraint(unsigned constraintIndex)
Returns whether the perpendicular of the specified constraint is a is a direction along which the pol...
bool isUnbounded()
Returns true if the polytope is unbounded, i.e., extends to infinity in some direction.
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...
std::optional< SmallVector< Fraction, 8 > > getRationalSample() const
Returns the current sample point, which may contain non-integer (rational) coordinates.
std::optional< SmallVector< DynamicAPInt, 8 > > findIntegerSample()
Returns an integer sample point if one exists, or std::nullopt otherwise.
A class to perform symbolic lexicographic optimization, i.e., to find, for every assignment to the sy...
SymbolicLexOpt computeSymbolicIntegerLexMin()
The lexmin will be stored as a function lexopt from symbols to non-symbols in the result.
BoundType
The type of bound: equal, lower bound or upper bound.
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...
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 ...
DynamicAPInt ceil(const Fraction &f)
Fraction abs(const Fraction &f)
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 ...
void printWithPrintMetrics(raw_ostream &os, T val, unsigned minSpacing, const PrintTableMetrics &m)
Print val in the table with metrics specified in 'm'.
void updatePrintMetrics(T val, PrintTableMetrics &m)
Iterate over each val in the table and update 'm' where .maxPreIndent and .maxPostIndent are initiali...
SmallVector< DynamicAPInt, 8 > getDivLowerBound(ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor, unsigned localVarIdx)
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.
const PresburgerSpace & getSpace() const
unsigned getNumIneqs() const
unsigned getNumEqs() const
MaybeLocalRepr contains the indices of the constraints that can be expressed as a floordiv of an affi...
Example usage: Print .12, 3.4, 56.7 preAlign = ".", minSpacing = 1, .12 .12 3.4 3....
Represents the result of a symbolic lexicographic optimization computation.
PWMAFunction lexopt
This maps assignments of symbols to the corresponding lexopt.
PresburgerSet unboundedDomain
Contains all assignments to the symbols that made the lexopt unbounded.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.