15 #include "llvm/ADT/DynamicAPInt.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/SmallBitVector.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/Support/Compiler.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include "llvm/Support/LogicalResult.h"
22 #include "llvm/Support/raw_ostream.h"
31 using namespace presburger;
42 assert(a.size() == b.size());
44 res.reserve(a.size());
45 for (
unsigned i = 0, e = a.size(); i < e; ++i)
46 res.emplace_back(a[i] + scale * b[i]);
51 : usingBigM(mustUseBigM), nRedundant(0), nSymbol(0),
52 tableau(0, getNumFixedCols() + nVar), empty(false) {
56 for (
unsigned i = 0; i < nVar; ++i) {
64 const llvm::SmallBitVector &isSymbol)
66 assert(isSymbol.size() == nVar &&
"invalid bitmask!");
70 for (
unsigned symbolIdx : isSymbol.set_bits()) {
71 var[symbolIdx].isSymbol =
true;
78 assert(index !=
nullIndex &&
"nullIndex passed to unknownFromIndex");
79 return index >= 0 ?
var[index] :
con[~index];
93 assert(index !=
nullIndex &&
"nullIndex passed to unknownFromIndex");
94 return index >= 0 ?
var[index] :
con[~index];
122 bool makeRestricted) {
123 assert(coeffs.size() ==
var.size() + 1 &&
124 "Incorrect number of coefficients!");
126 "inconsistent column count!");
129 tableau(newRow, 1) = coeffs.back();
145 DynamicAPInt bigMCoeff(0);
146 for (
unsigned i = 0; i < coeffs.size() - 1; ++i)
147 if (!
var[i].isSymbol)
148 bigMCoeff -= coeffs[i];
150 tableau(newRow, 2) = bigMCoeff;
154 for (
unsigned i = 0; i <
var.size(); ++i) {
155 unsigned pos =
var[i].pos;
171 DynamicAPInt lcm = llvm::lcm(
tableau(newRow, 0),
tableau(pos, 0));
172 DynamicAPInt nRowCoeff = lcm /
tableau(newRow, 0);
173 DynamicAPInt idxRowCoeff = coeffs[i] * (lcm /
tableau(pos, 0));
177 nRowCoeff *
tableau(newRow, col) + idxRowCoeff *
tableau(pos, col);
182 return con.size() - 1;
186 bool signMatchesDirection(
const DynamicAPInt &elem,
Direction direction) {
187 assert(elem != 0 &&
"elem should not be 0");
188 return direction == Direction::Up ? elem > 0 : elem < 0;
236 if (restoreRationalConsistency().failed()) {
240 return getRationalSample();
282 DynamicAPInt d =
tableau(row, 0);
292 std::optional<unsigned> LexSimplex::maybeGetNonIntegralVarRow()
const {
293 for (
const Unknown &u :
var) {
299 unsigned row = u.pos;
308 if (restoreRationalConsistency().failed())
312 while (std::optional<unsigned> maybeRow = maybeGetNonIntegralVarRow()) {
323 if (
addCut(*maybeRow).failed())
325 if (restoreRationalConsistency().failed())
330 assert(!sample.
isEmpty() &&
"If we reached here the sample should exist!");
333 return llvm::to_vector<8>(
348 SymbolicLexSimplex::getSymbolicSampleNumerator(
unsigned row)
const {
351 for (
unsigned col = 3; col < 3 +
nSymbol; ++col)
352 sample.emplace_back(
tableau(row, col));
353 sample.emplace_back(
tableau(row, 1));
358 SymbolicLexSimplex::getSymbolicSampleIneq(
unsigned row)
const {
368 var.back().isSymbol =
true;
373 const DynamicAPInt &divisor) {
374 assert(divisor > 0 &&
"divisor must be positive!");
376 range, [divisor](
const DynamicAPInt &x) {
return x % divisor == 0; });
379 bool SymbolicLexSimplex::isSymbolicSampleIntegral(
unsigned row)
const {
380 DynamicAPInt denom =
tableau(row, 0);
381 return tableau(row, 1) % denom == 0 &&
418 LogicalResult SymbolicLexSimplex::addSymbolicCut(
unsigned row) {
419 DynamicAPInt d =
tableau(row, 0);
429 divCoeffs.reserve(
nSymbol + 1);
430 DynamicAPInt divDenom = d;
431 for (
unsigned col = 3; col < 3 +
nSymbol; ++col)
432 divCoeffs.emplace_back(mod(-
tableau(row, col), divDenom));
433 divCoeffs.emplace_back(mod(-
tableau(row, 1), divDenom));
448 for (
unsigned col = 3; col < 3 +
nSymbol - 1; ++col)
457 void SymbolicLexSimplex::recordOutput(
SymbolicLexOpt &result)
const {
460 for (
const Unknown &u :
var) {
471 DynamicAPInt denom =
tableau(u.pos, 0);
472 if (
tableau(u.pos, 2) < denom) {
479 assert(
tableau(u.pos, 2) == denom &&
480 "Coefficient of M should not be greater than 1!");
483 for (DynamicAPInt &elem : sample) {
484 assert(elem % denom == 0 &&
"coefficients must be integral!");
487 output.appendExtraRow(sample);
499 std::optional<unsigned> SymbolicLexSimplex::maybeGetAlwaysViolatedRow() {
502 for (
unsigned row = 0, e =
getNumRows(); row < e; ++row)
506 for (
unsigned row = 0, e =
getNumRows(); row < e; ++row) {
517 std::optional<unsigned> SymbolicLexSimplex::maybeGetNonIntegralVarRow() {
518 for (
const Unknown &u :
var) {
521 assert(!u.isSymbol &&
"Symbol should not be in row orientation!");
522 if (!isSymbolicSampleIntegral(u.pos))
530 LogicalResult SymbolicLexSimplex::doNonBranchingPivots() {
531 while (std::optional<unsigned> row = maybeGetAlwaysViolatedRow())
560 unsigned domainSnapshot;
566 assert(level >= stack.size());
567 if (level > stack.size()) {
574 if (doNonBranchingPivots().failed()) {
581 unsigned splitRow = 0;
582 for (
unsigned e =
getNumRows(); splitRow < e; ++splitRow) {
585 assert(
tableau(splitRow, 2) == 0 &&
586 "Non-branching pivots should have been handled already!");
588 symbolicSample = getSymbolicSampleIneq(splitRow);
596 "Non-branching pivots should have been handled already!");
601 unsigned domainSnapshot = domainSimplex.
getSnapshot();
626 StackFrame{splitIndex, snapshot, domainSnapshot, domainPolyCounts});
633 if (std::optional<unsigned> row = maybeGetNonIntegralVarRow()) {
634 if (addSymbolicCut(*row).failed()) {
645 recordOutput(result);
650 if (level == stack.size()) {
652 const StackFrame &frame = stack.back();
653 domainPoly.
truncate(frame.domainPolyCounts);
654 domainSimplex.
rollback(frame.domainSnapshot);
664 "The split row should have been returned to row orientation!");
688 bool LexSimplex::rowIsViolated(
unsigned row)
const {
696 std::optional<unsigned> LexSimplex::maybeGetViolatedRow()
const {
697 for (
unsigned row = 0, e =
getNumRows(); row < e; ++row)
698 if (rowIsViolated(row))
706 LogicalResult LexSimplex::restoreRationalConsistency() {
709 while (std::optional<unsigned> maybeViolatedRow = maybeGetViolatedRow())
778 std::optional<unsigned> maybeColumn;
789 pivot(row, *maybeColumn);
794 unsigned colB)
const {
839 auto getSampleChangeCoeffForVar = [
this, row](
unsigned col,
841 DynamicAPInt a =
tableau(row, col);
856 DynamicAPInt c =
tableau(u.pos, col);
861 Fraction changeA = getSampleChangeCoeffForVar(colA, u);
862 Fraction changeB = getSampleChangeCoeffForVar(colB, u);
863 if (changeA < changeB)
865 if (changeA > changeB)
886 std::optional<SimplexBase::Pivot>
887 Simplex::findPivot(
int row,
Direction direction)
const {
888 std::optional<unsigned> col;
890 DynamicAPInt elem =
tableau(row,
j);
895 !signMatchesDirection(elem, direction))
905 tableau(row, *col) < 0 ? flippedDirection(direction) : direction;
906 std::optional<unsigned> maybePivotRow = findPivotRow(row, newDirection, *col);
907 return Pivot{maybePivotRow.value_or(row), *col};
952 assert(pivotCol >=
getNumFixedCols() &&
"Refusing to pivot invalid column");
958 if (
tableau(pivotRow, 0) < 0) {
964 for (
unsigned col = 1, e =
getNumColumns(); col < e; ++col) {
972 for (
unsigned row = 0, numRows =
getNumRows(); row < numRows; ++row) {
975 if (
tableau(row, pivotCol) == 0)
978 for (
unsigned col = 1, numCols =
getNumColumns(); col < numCols; ++col) {
993 LogicalResult Simplex::restoreRow(Unknown &u) {
995 "unknown should be in row position");
997 while (
tableau(u.pos, 1) < 0) {
998 std::optional<Pivot> maybePivot = findPivot(u.pos,
Direction::Up);
1006 return success(
tableau(u.pos, 1) >= 0);
1031 std::optional<unsigned> Simplex::findPivotRow(std::optional<unsigned> skipRow,
1033 unsigned col)
const {
1034 std::optional<unsigned> retRow;
1039 DynamicAPInt retElem, retConst;
1041 if (skipRow && row == *skipRow)
1043 DynamicAPInt elem =
tableau(row, col);
1048 if (signMatchesDirection(elem, direction))
1050 DynamicAPInt constTerm =
tableau(row, 1);
1055 retConst = constTerm;
1059 DynamicAPInt diff = retConst * elem - constTerm * retElem;
1061 (diff != 0 && !signMatchesDirection(diff, direction))) {
1064 retConst = constTerm;
1083 "Invalid columns provided!");
1111 unsigned conIndex =
addRow(coeffs,
true);
1112 LogicalResult result = restoreRow(
con[conIndex]);
1113 if (result.failed())
1126 negatedCoeffs.reserve(coeffs.size());
1127 for (
const DynamicAPInt &coeff : coeffs)
1128 negatedCoeffs.emplace_back(-coeff);
1144 basis.emplace_back(index);
1184 void Simplex::undoLastConstraint() {
1195 unsigned column =
con.back().pos;
1196 if (std::optional<unsigned> maybeRow =
1198 pivot(*maybeRow, column);
1199 }
else if (std::optional<unsigned> maybeRow =
1201 pivot(*maybeRow, column);
1204 assert(row &&
"Pivot should always exist for a constraint!");
1205 pivot(*row, column);
1221 unsigned column =
con.back().pos;
1223 assert(row &&
"Pivot should always exist for a constraint!");
1224 pivot(*row, column);
1245 "Variable to be removed must be in column orientation!");
1247 if (
var.back().isSymbol)
1261 assert(!
savedBases.empty() &&
"No bases saved!");
1266 for (
int index : basis) {
1273 "Column should not be a fixed column!");
1274 if (llvm::is_contained(basis,
colUnknown[col]))
1292 while (
undoLog.size() > snapshot) {
1305 const DynamicAPInt &denom) {
1306 assert(denom > 0 &&
"Denominator must be positive!");
1310 DynamicAPInt constTerm = ineq.back();
1311 ineq.back() = -denom;
1312 ineq.emplace_back(constTerm);
1315 for (DynamicAPInt &coeff : ineq)
1317 ineq.back() += denom - 1;
1324 var.reserve(
var.size() + count);
1326 for (
unsigned i = 0; i < count; ++i) {
1338 "IntegerRelation must have same dimensionality as simplex");
1348 while (std::optional<Pivot> maybePivot = findPivot(row, direction)) {
1351 if (maybePivot->row == row)
1370 unsigned conIndex =
addRow(coeffs);
1371 unsigned row =
con[conIndex].pos;
1380 unsigned column = u.pos;
1381 std::optional<unsigned> pivotRow = findPivotRow({}, direction, column);
1386 pivot(*pivotRow, column);
1389 unsigned row = u.pos;
1393 if (restoreRow(u).failed())
1394 llvm_unreachable(
"Could not restore row!");
1400 assert(!
empty &&
"It is not meaningful to ask whether a direction is bounded "
1401 "in an empty set.");
1419 void Simplex::markRowRedundant(Unknown &u) {
1421 "Unknown should be in row position!");
1422 assert(u.pos >=
nRedundant &&
"Unknown is already marked redundant!");
1430 assert(offset + count <=
con.size() &&
"invalid range!");
1444 for (
unsigned i = 0; i < count; ++i) {
1447 unsigned column = u.
pos;
1448 std::optional<unsigned> pivotRow =
1454 pivot(*pivotRow, column);
1457 unsigned row = u.
pos;
1462 if (restoreRow(u).failed())
1463 llvm_unreachable(
"Could not restore non-redundant row!");
1467 markRowRedundant(u);
1476 for (
unsigned i = 0; i <
var.size(); ++i) {
1509 result.reserve(v.size() + w.size());
1510 result.insert(result.end(), v.begin(), v.end());
1511 result.insert(result.end(), w.begin(), w.end());
1517 auto indexFromBIndex = [&](
int index) {
1534 auto appendRowFromA = [&](
unsigned row) {
1536 for (
unsigned col = 0, e = a.
getNumColumns(); col < e; ++col)
1545 auto appendRowFromB = [&](
unsigned row) {
1551 for (
unsigned col = 2, e = b.
getNumColumns(); col < e; ++col)
1559 for (
unsigned row = 0; row < a.
nRedundant; ++row)
1560 appendRowFromA(row);
1561 for (
unsigned row = 0; row < b.
nRedundant; ++row)
1562 appendRowFromB(row);
1564 appendRowFromA(row);
1566 appendRowFromB(row);
1576 sample.reserve(
var.size());
1581 sample.emplace_back(0, 1);
1585 DynamicAPInt denom =
tableau(u.pos, 0);
1586 sample.emplace_back(
tableau(u.pos, 1), denom);
1601 sample.reserve(
var.size());
1603 for (
const Unknown &u :
var) {
1617 DynamicAPInt denom =
tableau(u.pos, 0);
1619 if (
tableau(u.pos, 2) != denom)
1621 sample.emplace_back(
tableau(u.pos, 1), denom);
1626 std::optional<SmallVector<DynamicAPInt, 8>>
1635 integerSample.reserve(
var.size());
1636 for (
const Fraction &coord : rationalSample) {
1638 if (coord.num % coord.den != 0)
1640 integerSample.emplace_back(coord.num / coord.den);
1642 return integerSample;
1660 : simplex(
Simplex::makeProduct(originalSimplex, originalSimplex)),
1661 simplexConstraintOffset(simplex.getNumConstraints()) {}
1667 assert(llvm::any_of(dir, [](
const DynamicAPInt &x) {
return x != 0; }) &&
1668 "Direction passed is the zero vector!");
1669 snapshotStack.emplace_back(simplex.getSnapshot());
1670 simplex.addEquality(getCoeffsForDirection(dir));
1675 simplex.computeOptimum(Direction::Up, getCoeffsForDirection(dir));
1676 assert(maybeWidth.
isBounded() &&
"Width should be bounded!");
1684 DynamicAPInt &dualDenom) {
1692 unsigned conIndex = simplex.addRow(getCoeffsForDirection(dir));
1693 unsigned row = simplex.con[conIndex].pos;
1696 assert(maybeWidth.
isBounded() &&
"Width should be bounded!");
1697 dualDenom = simplex.tableau(row, 0);
1699 dual.reserve((conIndex - simplexConstraintOffset) / 2);
1703 for (
unsigned i = simplexConstraintOffset; i < conIndex; i += 2) {
1724 assert((simplex.con[i].orientation != Orientation::Column ||
1725 simplex.con[i + 1].orientation != Orientation::Column) &&
1726 "Both inequalities for the equality cannot be in column "
1728 if (simplex.con[i].orientation == Orientation::Column)
1729 dual.emplace_back(-simplex.tableau(row, simplex.con[i].pos));
1730 else if (simplex.con[i + 1].orientation == Orientation::Column)
1731 dual.emplace_back(simplex.tableau(row, simplex.con[i + 1].pos));
1733 dual.emplace_back(0);
1743 assert(!snapshotStack.empty() &&
"Snapshot stack is empty!");
1744 simplex.rollback(snapshotStack.back());
1745 snapshotStack.pop_back();
1755 assert(2 * dir.size() == simplex.getNumVariables() &&
1756 "Direction vector has wrong dimensionality");
1758 coeffs.reserve(dir.size() + 1);
1759 for (
const DynamicAPInt &coeff : dir)
1760 coeffs.emplace_back(-coeff);
1761 coeffs.emplace_back(0);
1768 unsigned simplexConstraintOffset;
1828 void Simplex::reduceBasis(
IntMatrix &basis,
unsigned level) {
1837 DynamicAPInt dualDenom;
1857 auto updateBasisWithUAndGetFCandidate = [&](
unsigned i) ->
Fraction {
1858 assert(i < level + dual.size() &&
"dual_i is not known!");
1860 DynamicAPInt u = floorDiv(dual[i - level], dualDenom);
1862 if (dual[i - level] % dualDenom != 0) {
1864 DynamicAPInt candidateDualDenom[2];
1868 widthI[0] = gbrSimplex.computeWidthAndDuals(
1869 basis.
getRow(i + 1), candidateDual[0], candidateDualDenom[0]);
1874 widthI[1] = gbrSimplex.computeWidthAndDuals(
1875 basis.
getRow(i + 1), candidateDual[1], candidateDualDenom[1]);
1877 unsigned j = widthI[0] < widthI[1] ? 0 : 1;
1891 basis.
getRow(i + 1), DynamicAPInt(-1), basis.
getRow(i))) >=
1893 "Computed u value does not minimize the width!");
1896 basis.
getRow(i + 1), DynamicAPInt(+1), basis.
getRow(i))) >=
1898 "Computed u value does not minimize the width!");
1900 dual = std::move(candidateDual[
j]);
1901 dualDenom = candidateDualDenom[
j];
1905 assert(i + 1 - level < width.size() &&
"width_{i+1} wasn't saved");
1909 assert(gbrSimplex.computeWidth(basis.
getRow(i + 1)) ==
1910 width[i + 1 - level]);
1911 return width[i + 1 - level];
1918 if (i >= level + width.size()) {
1923 assert((i == 0 || i - 1 < level + width.size()) &&
1924 "We are at level i but we don't know the value of width_{i-1}");
1929 assert(i == level &&
"This case should only occur when i == level");
1931 gbrSimplex.computeWidthAndDuals(basis.
getRow(i), dual, dualDenom));
1934 if (i >= level + dual.size()) {
1935 assert(i + 1 >= level + width.size() &&
1936 "We don't know dual_i but we know width_{i+1}");
1938 gbrSimplex.addEqualityForDirection(basis.
getRow(i));
1939 width.emplace_back(gbrSimplex.computeWidthAndDuals(basis.
getRow(i + 1),
1941 gbrSimplex.removeLastEquality();
1945 Fraction widthICandidate = updateBasisWithUAndGetFCandidate(i);
1946 if (widthICandidate < epsilon * width[i - level]) {
1948 width[i - level] = widthICandidate;
1951 width.resize(i - level + 1);
1957 gbrSimplex.removeLastEquality();
1964 gbrSimplex.addEqualityForDirection(basis.
getRow(i));
2001 unsigned nDims =
var.size();
2015 while (level != -1u) {
2025 if (level >= upperBoundStack.size()) {
2031 llvm::to_vector<8>(basis.
getRow(level));
2032 basisCoeffs.emplace_back(0);
2038 if (minRoundedUp.isEmpty() || maxRoundedDown.isEmpty()) {
2039 assert((minRoundedUp.isEmpty() && maxRoundedDown.isEmpty()) &&
2040 "If one bound is empty, both should be.");
2041 snapshotStack.pop_back();
2042 nextValueStack.pop_back();
2043 upperBoundStack.pop_back();
2049 assert((minRoundedUp.isBounded() && maxRoundedDown.isBounded()) &&
2050 "Polyhedron should be bounded!");
2055 return *maybeSample;
2057 if (*minRoundedUp < *maxRoundedDown) {
2058 reduceBasis(basis, level);
2059 basisCoeffs = llvm::to_vector<8>(basis.
getRow(level));
2060 basisCoeffs.emplace_back(0);
2061 std::tie(minRoundedUp, maxRoundedDown) =
2069 nextValueStack.emplace_back(*minRoundedUp);
2070 upperBoundStack.emplace_back(*maxRoundedDown);
2073 assert((snapshotStack.size() - 1 == level &&
2074 nextValueStack.size() - 1 == level &&
2075 upperBoundStack.size() - 1 == level) &&
2076 "Mismatched variable stack sizes!");
2082 DynamicAPInt nextValue = nextValueStack.back();
2083 ++nextValueStack.back();
2084 if (nextValue > upperBoundStack.back()) {
2087 snapshotStack.pop_back();
2088 nextValueStack.pop_back();
2089 upperBoundStack.pop_back();
2096 basis.
getRow(level).end());
2097 basisCoeffs.emplace_back(-nextValue);
2113 return {minRoundedUp, maxRoundedDown};
2117 assert(!
isEmpty() &&
"cannot check for flatness of empty simplex!");
2121 if (!upOpt.isBounded())
2123 if (!downOpt.isBounded())
2126 return *upOpt == *downOpt;
2132 os <<
"Simplex marked empty!\n";
2134 for (
unsigned i = 0; i <
var.size(); ++i) {
2140 for (
unsigned i = 0; i <
con.size(); ++i) {
2146 for (
unsigned row = 0, e =
getNumRows(); row < e; ++row) {
2152 os <<
"c0: denom, c1: const";
2154 os <<
", c" << col <<
": " <<
colUnknown[col];
2157 for (
unsigned row = 0, numRows =
getNumRows(); row < numRows; ++row)
2158 for (
unsigned col = 0, numCols =
getNumColumns(); col < numCols; ++col)
2159 updatePrintMetrics<DynamicAPInt>(
tableau(row, col), ptm);
2160 unsigned MIN_SPACING = 1;
2161 for (
unsigned row = 0, numRows =
getNumRows(); row < numRows; ++row) {
2162 for (
unsigned col = 0, numCols =
getNumColumns(); col < numCols; ++col) {
2163 printWithPrintMetrics<DynamicAPInt>(os,
tableau(row, col), MIN_SPACING,
2219 "It is not meaningful to ask about redundancy in an empty set!");
2229 "It is not meaningful to ask about redundancy in an empty set!");
2233 "Optima should be non-empty for a non-empty set");
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static bool isRangeDivisibleBy(ArrayRef< DynamicAPInt > range, const DynamicAPInt &divisor)
static LLVM_ATTRIBUTE_UNUSED SmallVector< DynamicAPInt, 8 > scaleAndAddForAssert(ArrayRef< DynamicAPInt > a, const DynamicAPInt &scale, ArrayRef< DynamicAPInt > b)
static IntMatrix identity(unsigned dimension)
Return the identity matrix of the specified dimension.
DynamicAPInt normalizeRow(unsigned row, unsigned nCols)
Divide the first nCols of the specified row by their GCD.
An IntegerRelation represents the set of points from a PresburgerSpace that satisfy a list of affine ...
void truncate(const CountsSnapshot &counts)
CountsSnapshot getCounts() const
unsigned getNumSymbolVars() const
ArrayRef< DynamicAPInt > getInequality(unsigned idx) const
void addLocalFloorDiv(ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor)
Adds a new local variable as the floordiv of an affine function of other variables,...
unsigned getNumVars() const
unsigned getNumLocalVars() const
DivisionRepr getLocalReprs(std::vector< MaybeLocalRepr > *repr=nullptr) const
Returns a DivisonRepr representing the division representation of local variables in the constraint s...
void addInequality(ArrayRef< DynamicAPInt > inEq)
Adds an inequality (>= 0) from the coefficients specified in inEq.
ArrayRef< DynamicAPInt > getEquality(unsigned idx) const
unsigned getNumInequalities() const
unsigned getNumEqualities() const
unsigned getNumDimVars() const
void undoLastConstraint() final
Undo the addition of the last constraint.
LogicalResult moveRowUnknownToColumn(unsigned row)
Try to move the specified row to column orientation while preserving the lexicopositivity of the basi...
LogicalResult addCut(unsigned row)
Given a row that has a non-integer sample value, add an inequality to cut away this fractional sample...
unsigned getLexMinPivotColumn(unsigned row, unsigned colA, unsigned colB) const
Given two potential pivot columns for a row, return the one that results in the lexicographically sma...
void addInequality(ArrayRef< DynamicAPInt > coeffs) final
Add an inequality to the tableau.
unsigned getSnapshot()
Get a snapshot of the current state. This is used for rolling back.
void appendSymbol()
Add new symbolic variables to the end of the list of variables.
MaybeOptimum< SmallVector< Fraction, 8 > > findRationalLexMin()
Return the lexicographically minimum rational solution to the constraints.
bool isSeparateInequality(ArrayRef< DynamicAPInt > coeffs)
Return whether the specified inequality is redundant/separate for the polytope.
bool isRedundantInequality(ArrayRef< DynamicAPInt > coeffs)
MaybeOptimum< SmallVector< DynamicAPInt, 8 > > findIntegerLexMin()
Return the lexicographically minimum integer solution to the constraints.
unsigned getNumRows() const
void swapColumns(unsigned column, unsigned otherColumn)
Swap the given columns.
unsigned appendExtraRow()
Add an extra row at the bottom of the matrix and return its position.
MutableArrayRef< T > getRow(unsigned row)
Get a [Mutable]ArrayRef corresponding to the specified row.
void resizeVertically(unsigned newNRows)
void swapRows(unsigned row, unsigned otherRow)
Swap the given rows.
void resizeHorizontally(unsigned newNColumns)
void reserveRows(unsigned rows)
Reserve enough space to resize to the specified number of rows without reallocations.
void addToRow(unsigned sourceRow, unsigned targetRow, const T &scale)
Add scale multiples of the source row to the target row.
This class represents a multi-affine function with the domain as Z^d, where d is the number of domain...
const PresburgerSpace & getSpace() const
void addPiece(const Piece &piece)
unsigned getNumOutputs() const
void unionInPlace(const IntegerRelation &disjunct)
Mutate this set, turning it into the union of this set and the given disjunct.
PresburgerSpace is the space of all possible values of a tuple of integer valued variables/variables.
static PresburgerSpace getRelationSpace(unsigned numDomain=0, unsigned numRange=0, unsigned numSymbols=0, unsigned numLocals=0)
unsigned insertVar(VarKind kind, unsigned pos, unsigned num=1)
Insert num variables of the specified kind at position pos.
The Simplex class implements a version of the Simplex and Generalized Basis Reduction algorithms,...
unsigned addZeroRow(bool makeRestricted=false)
Add a new row to the tableau and the associated data structures.
bool isEmpty() const
Returns true if the tableau is empty (has conflicting constraints), false otherwise.
void appendVariable(unsigned count=1)
Add new variables to the end of the list of variables.
virtual void undoLastConstraint()=0
Undo the addition of the last constraint.
SmallVector< int, 8 > rowUnknown
These hold the indexes of the unknown at a given row or column position.
SmallVector< SmallVector< int, 8 >, 8 > savedBases
Holds a vector of bases.
void intersectIntegerRelation(const IntegerRelation &rel)
Add all the constraints from the given IntegerRelation.
SmallVector< UndoLogEntry, 8 > undoLog
Holds a log of operations, used for rolling back to a previous state.
bool usingBigM
Stores whether or not a big M column is present in the tableau.
unsigned getSnapshot() const
Get a snapshot of the current state.
void print(raw_ostream &os) const
Print the tableau's internal state.
UndoLogEntry
Enum to denote operations that need to be undone during rollback.
unsigned getNumRows() const
const Unknown & unknownFromRow(unsigned row) const
Returns the unknown associated with row.
SmallVector< int, 8 > colUnknown
SmallVector< Unknown, 8 > var
void addEquality(ArrayRef< DynamicAPInt > coeffs)
Add an equality to the tableau.
unsigned getSnapshotBasis()
Get a snapshot of the current state including the basis.
unsigned getNumFixedCols() const
Return the number of fixed columns, as described in the constructor above, this is the number of colu...
SmallVector< Unknown, 8 > con
These hold information about each unknown.
void markEmpty()
Mark the tableau as being empty.
bool empty
This is true if the tableau has been detected to be empty, false otherwise.
void addDivisionVariable(ArrayRef< DynamicAPInt > coeffs, const DynamicAPInt &denom)
Append a new variable to the simplex and constrain it such that its only integer value is the floor d...
void swapColumns(unsigned i, unsigned j)
void removeLastConstraintRowOrientation()
Remove the last constraint, which must be in row orientation.
std::optional< unsigned > findAnyPivotRow(unsigned col)
Return any row that this column can be pivoted with, ignoring tableau consistency.
virtual void addInequality(ArrayRef< DynamicAPInt > coeffs)=0
Add an inequality to the tableau.
const Unknown & unknownFromColumn(unsigned col) const
Returns the unknown associated with col.
void rollback(unsigned snapshot)
Rollback to a snapshot. This invalidates all later snapshots.
IntMatrix tableau
The matrix representing the tableau.
void pivot(unsigned row, unsigned col)
Pivot the row with the column.
void swapRows(unsigned i, unsigned j)
Swap the two rows/columns in the tableau and associated data structures.
void undo(UndoLogEntry entry)
Undo the operation represented by the log entry.
const Unknown & unknownFromIndex(int index) const
Returns the unknown associated with index.
unsigned nSymbol
The number of parameters.
unsigned nRedundant
The number of redundant rows in the tableau.
unsigned addRow(ArrayRef< DynamicAPInt > coeffs, bool makeRestricted=false)
Add a new row to the tableau and the associated data structures.
unsigned getNumVariables() const
Returns the number of variables in the tableau.
void swapRowWithCol(unsigned row, unsigned col)
Swap the row with the column in the tableau's data structures but not the tableau itself.
unsigned getNumColumns() const
unsigned getNumConstraints() const
Returns the number of constraints in the tableau.
Takes a snapshot of the simplex state on construction and rolls back to the snapshot on destruction.
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.
std::optional< SmallVector< DynamicAPInt, 8 > > getSamplePointIfIntegral() const
Returns the current sample point if it is integral.
bool isFlatAlong(ArrayRef< DynamicAPInt > coeffs)
Check if the simplex takes only one rational value along the direction of coeffs.
bool isRedundantEquality(ArrayRef< DynamicAPInt > coeffs)
Check if the specified equality already holds in the polytope.
IneqType findIneqType(ArrayRef< DynamicAPInt > coeffs)
Returns the type of the inequality with coefficients coeffs.
static Simplex makeProduct(const Simplex &a, const Simplex &b)
Make a tableau to represent a pair of points in the given tableaus, one in tableau A and one in B.
MaybeOptimum< Fraction > computeRowOptimum(Direction direction, unsigned row)
Compute the maximum or minimum value of the given row, depending on direction.
bool isRationalSubsetOf(const IntegerRelation &rel)
Returns true if this Simplex's polytope is a rational subset of rel.
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.
bool isRedundantInequality(ArrayRef< DynamicAPInt > coeffs)
Check if the specified inequality already holds in the polytope.
void addInequality(ArrayRef< DynamicAPInt > coeffs) final
Add an inequality to the tableau.
MaybeOptimum< Fraction > computeOptimum(Direction direction, ArrayRef< DynamicAPInt > coeffs)
Compute the maximum or minimum value of the given expression, depending on direction.
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.
SymbolicLexOpt computeSymbolicIntegerLexMin()
The lexmin will be stored as a function lexopt from symbols to non-symbols in the result.
Given a simplex for a polytope, construct a new simplex whose variables are identified with a pair of...
Fraction computeWidthAndDuals(ArrayRef< DynamicAPInt > dir, SmallVectorImpl< DynamicAPInt > &dual, DynamicAPInt &dualDenom)
Compute max(dotProduct(dir, x - y)) and save the dual variables for only the direction equalities to ...
void removeLastEquality()
Remove the last equality that was added through addEqualityForDirection.
Fraction computeWidth(ArrayRef< DynamicAPInt > dir)
Compute max(dotProduct(dir, x - y)).
GBRSimplex(const Simplex &originalSimplex)
void addEqualityForDirection(ArrayRef< DynamicAPInt > dir)
Add an equality dotProduct(dir, x - y) == 0.
SmallVector< AffineExpr, 4 > concat(ArrayRef< AffineExpr > a, ArrayRef< AffineExpr > b)
Return the vector that is the concatenation of a and b.
void normalizeDiv(MutableArrayRef< DynamicAPInt > num, DynamicAPInt &denom)
Normalize the given (numerator, denominator) pair by dividing out the common factors between them.
DynamicAPInt floor(const Fraction &f)
DynamicAPInt ceil(const Fraction &f)
DynamicAPInt normalizeRange(MutableArrayRef< DynamicAPInt > range)
Divide the range by its gcd and return the gcd.
SmallVector< DynamicAPInt, 8 > getComplementIneq(ArrayRef< DynamicAPInt > ineq)
Return the complement of the given inequality.
Include the generated interface declarations.
A class to represent fractions.
DynamicAPInt getAsInteger() const
The struct CountsSnapshot stores the count of each VarKind, and also of each constraint type.
Example usage: Print .12, 3.4, 56.7 preAlign = ".", minSpacing = 1, .12 .12 3.4 3....
An Unknown is either a variable or a constraint.
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.