110a898b3SArjun P //===- Simplex.cpp - MLIR Simplex Class -----------------------------------===//
210a898b3SArjun P //
310a898b3SArjun P // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
410a898b3SArjun P // See https://llvm.org/LICENSE.txt for license information.
510a898b3SArjun P // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610a898b3SArjun P //
710a898b3SArjun P //===----------------------------------------------------------------------===//
810a898b3SArjun P 
910a898b3SArjun P #include "mlir/Analysis/Presburger/Simplex.h"
1010a898b3SArjun P #include "mlir/Analysis/Presburger/Matrix.h"
1110a898b3SArjun P #include "mlir/Support/MathExtras.h"
126ebeba88SArjun P #include "llvm/ADT/Optional.h"
13497f87bbSStella Laurenzo #include "llvm/Support/Compiler.h"
1410a898b3SArjun P 
150c1f6865SGroverkss using namespace mlir;
160c1f6865SGroverkss using namespace presburger;
178e799588SArjun P 
1810a898b3SArjun P using Direction = Simplex::Direction;
1910a898b3SArjun P 
2010a898b3SArjun P const int nullIndex = std::numeric_limits<int>::max();
2110a898b3SArjun P 
22497f87bbSStella Laurenzo // Return a + scale*b;
23497f87bbSStella Laurenzo LLVM_ATTRIBUTE_UNUSED
24497f87bbSStella Laurenzo static SmallVector<int64_t, 8>
scaleAndAddForAssert(ArrayRef<int64_t> a,int64_t scale,ArrayRef<int64_t> b)25497f87bbSStella Laurenzo scaleAndAddForAssert(ArrayRef<int64_t> a, int64_t scale, ArrayRef<int64_t> b) {
26497f87bbSStella Laurenzo   assert(a.size() == b.size());
27497f87bbSStella Laurenzo   SmallVector<int64_t, 8> res;
28497f87bbSStella Laurenzo   res.reserve(a.size());
29497f87bbSStella Laurenzo   for (unsigned i = 0, e = a.size(); i < e; ++i)
30497f87bbSStella Laurenzo     res.push_back(a[i] + scale * b[i]);
31497f87bbSStella Laurenzo   return res;
32497f87bbSStella Laurenzo }
33497f87bbSStella Laurenzo 
SimplexBase(unsigned nVar,bool mustUseBigM)34*c2fcaf84SArjun P SimplexBase::SimplexBase(unsigned nVar, bool mustUseBigM)
35*c2fcaf84SArjun P     : usingBigM(mustUseBigM), nRedundant(0), nSymbol(0),
368bc2cff9SArjun P       tableau(0, getNumFixedCols() + nVar), empty(false) {
37b97aa413SArjun P   colUnknown.insert(colUnknown.begin(), getNumFixedCols(), nullIndex);
3810a898b3SArjun P   for (unsigned i = 0; i < nVar; ++i) {
396db01958SArjun P     var.emplace_back(Orientation::Column, /*restricted=*/false,
40b97aa413SArjun P                      /*pos=*/getNumFixedCols() + i);
4110a898b3SArjun P     colUnknown.push_back(i);
4210a898b3SArjun P   }
43*c2fcaf84SArjun P }
4479ad5fb2SArjun P 
SimplexBase(unsigned nVar,bool mustUseBigM,const llvm::SmallBitVector & isSymbol)45*c2fcaf84SArjun P SimplexBase::SimplexBase(unsigned nVar, bool mustUseBigM,
46*c2fcaf84SArjun P                          const llvm::SmallBitVector &isSymbol)
47*c2fcaf84SArjun P     : SimplexBase(nVar, mustUseBigM) {
48*c2fcaf84SArjun P   assert(isSymbol.size() == nVar && "invalid bitmask!");
49*c2fcaf84SArjun P   // Invariant: nSymbol is the number of symbols that have been marked
50*c2fcaf84SArjun P   // already and these occupy the columns
51*c2fcaf84SArjun P   // [getNumFixedCols(), getNumFixedCols() + nSymbol).
52*c2fcaf84SArjun P   for (unsigned symbolIdx : isSymbol.set_bits()) {
53*c2fcaf84SArjun P     var[symbolIdx].isSymbol = true;
54*c2fcaf84SArjun P     swapColumns(var[symbolIdx].pos, getNumFixedCols() + nSymbol);
55*c2fcaf84SArjun P     ++nSymbol;
5679ad5fb2SArjun P   }
5710a898b3SArjun P }
5810a898b3SArjun P 
unknownFromIndex(int index) const594fa96b7eSArjun P const Simplex::Unknown &SimplexBase::unknownFromIndex(int index) const {
6010a898b3SArjun P   assert(index != nullIndex && "nullIndex passed to unknownFromIndex");
6110a898b3SArjun P   return index >= 0 ? var[index] : con[~index];
6210a898b3SArjun P }
6310a898b3SArjun P 
unknownFromColumn(unsigned col) const644fa96b7eSArjun P const Simplex::Unknown &SimplexBase::unknownFromColumn(unsigned col) const {
658bc2cff9SArjun P   assert(col < getNumColumns() && "Invalid column");
6610a898b3SArjun P   return unknownFromIndex(colUnknown[col]);
6710a898b3SArjun P }
6810a898b3SArjun P 
unknownFromRow(unsigned row) const694fa96b7eSArjun P const Simplex::Unknown &SimplexBase::unknownFromRow(unsigned row) const {
708bc2cff9SArjun P   assert(row < getNumRows() && "Invalid row");
7110a898b3SArjun P   return unknownFromIndex(rowUnknown[row]);
7210a898b3SArjun P }
7310a898b3SArjun P 
unknownFromIndex(int index)744fa96b7eSArjun P Simplex::Unknown &SimplexBase::unknownFromIndex(int index) {
7510a898b3SArjun P   assert(index != nullIndex && "nullIndex passed to unknownFromIndex");
7610a898b3SArjun P   return index >= 0 ? var[index] : con[~index];
7710a898b3SArjun P }
7810a898b3SArjun P 
unknownFromColumn(unsigned col)794fa96b7eSArjun P Simplex::Unknown &SimplexBase::unknownFromColumn(unsigned col) {
808bc2cff9SArjun P   assert(col < getNumColumns() && "Invalid column");
8110a898b3SArjun P   return unknownFromIndex(colUnknown[col]);
8210a898b3SArjun P }
8310a898b3SArjun P 
unknownFromRow(unsigned row)844fa96b7eSArjun P Simplex::Unknown &SimplexBase::unknownFromRow(unsigned row) {
858bc2cff9SArjun P   assert(row < getNumRows() && "Invalid row");
8610a898b3SArjun P   return unknownFromIndex(rowUnknown[row]);
8710a898b3SArjun P }
8810a898b3SArjun P 
addZeroRow(bool makeRestricted)899f8cb685SArjun P unsigned SimplexBase::addZeroRow(bool makeRestricted) {
908f99cdd2SArjun P   // Resize the tableau to accommodate the extra row.
918bc2cff9SArjun P   unsigned newRow = tableau.appendExtraRow();
928bc2cff9SArjun P   assert(getNumRows() == getNumRows() && "Inconsistent tableau size");
9310a898b3SArjun P   rowUnknown.push_back(~con.size());
948bc2cff9SArjun P   con.emplace_back(Orientation::Row, makeRestricted, newRow);
9593ccd7c4SArjun P   undoLog.push_back(UndoLogEntry::RemoveLastConstraint);
968bc2cff9SArjun P   tableau(newRow, 0) = 1;
978bc2cff9SArjun P   return newRow;
989f8cb685SArjun P }
999f8cb685SArjun P 
1009f8cb685SArjun P /// Add a new row to the tableau corresponding to the given constant term and
1019f8cb685SArjun P /// list of coefficients. The coefficients are specified as a vector of
1029f8cb685SArjun P /// (variable index, coefficient) pairs.
addRow(ArrayRef<int64_t> coeffs,bool makeRestricted)1039f8cb685SArjun P unsigned SimplexBase::addRow(ArrayRef<int64_t> coeffs, bool makeRestricted) {
1049f8cb685SArjun P   assert(coeffs.size() == var.size() + 1 &&
1059f8cb685SArjun P          "Incorrect number of coefficients!");
1068bc2cff9SArjun P   assert(var.size() + getNumFixedCols() == getNumColumns() &&
1078bc2cff9SArjun P          "inconsistent column count!");
1089f8cb685SArjun P 
1098bc2cff9SArjun P   unsigned newRow = addZeroRow(makeRestricted);
1108bc2cff9SArjun P   tableau(newRow, 1) = coeffs.back();
1116db01958SArjun P   if (usingBigM) {
1126db01958SArjun P     // When the lexicographic pivot rule is used, instead of the variables
1136db01958SArjun P     //
1146db01958SArjun P     // x, y, z ...
1156db01958SArjun P     //
1166db01958SArjun P     // we internally use the variables
1176db01958SArjun P     //
1186db01958SArjun P     // M, M + x, M + y, M + z, ...
1196db01958SArjun P     //
1206db01958SArjun P     // where M is the big M parameter. As such, when the user tries to add
1216db01958SArjun P     // a row ax + by + cz + d, we express it in terms of our internal variables
1226db01958SArjun P     // as -(a + b + c)M + a(M + x) + b(M + y) + c(M + z) + d.
12379ad5fb2SArjun P     //
12479ad5fb2SArjun P     // Symbols don't use the big M parameter since they do not get lex
12579ad5fb2SArjun P     // optimized.
1266db01958SArjun P     int64_t bigMCoeff = 0;
1276db01958SArjun P     for (unsigned i = 0; i < coeffs.size() - 1; ++i)
12879ad5fb2SArjun P       if (!var[i].isSymbol)
1296db01958SArjun P         bigMCoeff -= coeffs[i];
1306db01958SArjun P     // The coefficient to the big M parameter is stored in column 2.
1318bc2cff9SArjun P     tableau(newRow, 2) = bigMCoeff;
1326db01958SArjun P   }
13310a898b3SArjun P 
13410a898b3SArjun P   // Process each given variable coefficient.
13510a898b3SArjun P   for (unsigned i = 0; i < var.size(); ++i) {
13610a898b3SArjun P     unsigned pos = var[i].pos;
13710a898b3SArjun P     if (coeffs[i] == 0)
13810a898b3SArjun P       continue;
13910a898b3SArjun P 
14010a898b3SArjun P     if (var[i].orientation == Orientation::Column) {
14110a898b3SArjun P       // If a variable is in column position at column col, then we just add the
14210a898b3SArjun P       // coefficient for that variable (scaled by the common row denominator) to
14310a898b3SArjun P       // the corresponding entry in the new row.
1448bc2cff9SArjun P       tableau(newRow, pos) += coeffs[i] * tableau(newRow, 0);
14510a898b3SArjun P       continue;
14610a898b3SArjun P     }
14710a898b3SArjun P 
14810a898b3SArjun P     // If the variable is in row position, we need to add that row to the new
14910a898b3SArjun P     // row, scaled by the coefficient for the variable, accounting for the two
15010a898b3SArjun P     // rows potentially having different denominators. The new denominator is
15110a898b3SArjun P     // the lcm of the two.
1528bc2cff9SArjun P     int64_t lcm = mlir::lcm(tableau(newRow, 0), tableau(pos, 0));
1538bc2cff9SArjun P     int64_t nRowCoeff = lcm / tableau(newRow, 0);
15410a898b3SArjun P     int64_t idxRowCoeff = coeffs[i] * (lcm / tableau(pos, 0));
1558bc2cff9SArjun P     tableau(newRow, 0) = lcm;
1568bc2cff9SArjun P     for (unsigned col = 1, e = getNumColumns(); col < e; ++col)
1578bc2cff9SArjun P       tableau(newRow, col) =
1588bc2cff9SArjun P           nRowCoeff * tableau(newRow, col) + idxRowCoeff * tableau(pos, col);
15910a898b3SArjun P   }
16010a898b3SArjun P 
1618bc2cff9SArjun P   tableau.normalizeRow(newRow);
16210a898b3SArjun P   // Push to undo log along with the index of the new constraint.
16310a898b3SArjun P   return con.size() - 1;
16410a898b3SArjun P }
16510a898b3SArjun P 
16610a898b3SArjun P namespace {
signMatchesDirection(int64_t elem,Direction direction)16710a898b3SArjun P bool signMatchesDirection(int64_t elem, Direction direction) {
16810a898b3SArjun P   assert(elem != 0 && "elem should not be 0");
16910a898b3SArjun P   return direction == Direction::Up ? elem > 0 : elem < 0;
17010a898b3SArjun P }
17110a898b3SArjun P 
flippedDirection(Direction direction)17210a898b3SArjun P Direction flippedDirection(Direction direction) {
17310a898b3SArjun P   return direction == Direction::Up ? Direction::Down : Simplex::Direction::Up;
17410a898b3SArjun P }
175be0a7e9fSMehdi Amini } // namespace
17610a898b3SArjun P 
17779ad5fb2SArjun P /// We simply make the tableau consistent while maintaining a lexicopositive
17879ad5fb2SArjun P /// basis transform, and then return the sample value. If the tableau becomes
17979ad5fb2SArjun P /// empty, we return empty.
18079ad5fb2SArjun P ///
18179ad5fb2SArjun P /// Let the variables be x = (x_1, ... x_n).
18279ad5fb2SArjun P /// Let the basis unknowns be y = (y_1, ... y_n).
18379ad5fb2SArjun P /// We have that x = A*y + b for some n x n matrix A and n x 1 column vector b.
18479ad5fb2SArjun P ///
18579ad5fb2SArjun P /// As we will show below, A*y is either zero or lexicopositive.
18679ad5fb2SArjun P /// Adding a lexicopositive vector to b will make it lexicographically
18779ad5fb2SArjun P /// greater, so A*y + b is always equal to or lexicographically greater than b.
18879ad5fb2SArjun P /// Thus, since we can attain x = b, that is the lexicographic minimum.
18979ad5fb2SArjun P ///
19079ad5fb2SArjun P /// We have that that every column in A is lexicopositive, i.e., has at least
19179ad5fb2SArjun P /// one non-zero element, with the first such element being positive. Since for
19279ad5fb2SArjun P /// the tableau to be consistent we must have non-negative sample values not
19379ad5fb2SArjun P /// only for the constraints but also for the variables, we also have x >= 0 and
19479ad5fb2SArjun P /// y >= 0, by which we mean every element in these vectors is non-negative.
19579ad5fb2SArjun P ///
19679ad5fb2SArjun P /// Proof that if every column in A is lexicopositive, and y >= 0, then
19779ad5fb2SArjun P /// A*y is zero or lexicopositive. Begin by considering A_1, the first row of A.
19879ad5fb2SArjun P /// If this row is all zeros, then (A*y)_1 = (A_1)*y = 0; proceed to the next
19979ad5fb2SArjun P /// row. If we run out of rows, A*y is zero and we are done; otherwise, we
20079ad5fb2SArjun P /// encounter some row A_i that has a non-zero element. Every column is
20179ad5fb2SArjun P /// lexicopositive and so has some positive element before any negative elements
20279ad5fb2SArjun P /// occur, so the element in this row for any column, if non-zero, must be
20379ad5fb2SArjun P /// positive. Consider (A*y)_i = (A_i)*y. All the elements in both vectors are
20479ad5fb2SArjun P /// non-negative, so if this is non-zero then it must be positive. Then the
20579ad5fb2SArjun P /// first non-zero element of A*y is positive so A*y is lexicopositive.
20679ad5fb2SArjun P ///
20779ad5fb2SArjun P /// Otherwise, if (A_i)*y is zero, then for every column j that had a non-zero
20879ad5fb2SArjun P /// element in A_i, y_j is zero. Thus these columns have no contribution to A*y
20979ad5fb2SArjun P /// and we can completely ignore these columns of A. We now continue downwards,
21079ad5fb2SArjun P /// looking for rows of A that have a non-zero element other than in the ignored
21179ad5fb2SArjun P /// columns. If we find one, say A_k, once again these elements must be positive
21279ad5fb2SArjun P /// since they are the first non-zero element in each of these columns, so if
21379ad5fb2SArjun P /// (A_k)*y is not zero then we have that A*y is lexicopositive and if not we
21479ad5fb2SArjun P /// add these to the set of ignored columns and continue to the next row. If we
21579ad5fb2SArjun P /// run out of rows, then A*y is zero and we are done.
findRationalLexMin()216cfd6ba89SArjun P MaybeOptimum<SmallVector<Fraction, 8>> LexSimplex::findRationalLexMin() {
21769c1a354SArjun P   if (restoreRationalConsistency().failed()) {
21869c1a354SArjun P     markEmpty();
21979ad5fb2SArjun P     return OptimumKind::Empty;
22069c1a354SArjun P   }
2216db01958SArjun P   return getRationalSample();
2226db01958SArjun P }
2236db01958SArjun P 
22479ad5fb2SArjun P /// Given a row that has a non-integer sample value, add an inequality such
22579ad5fb2SArjun P /// that this fractional sample value is cut away from the polytope. The added
22679ad5fb2SArjun P /// inequality will be such that no integer points are removed. i.e., the
22779ad5fb2SArjun P /// integer lexmin, if it exists, is the same with and without this constraint.
22879ad5fb2SArjun P ///
22979ad5fb2SArjun P /// Let the row be
23079ad5fb2SArjun P /// (c + coeffM*M + a_1*s_1 + ... + a_m*s_m + b_1*y_1 + ... + b_n*y_n)/d,
23179ad5fb2SArjun P /// where s_1, ... s_m are the symbols and
23279ad5fb2SArjun P ///       y_1, ... y_n are the other basis unknowns.
23379ad5fb2SArjun P ///
23479ad5fb2SArjun P /// For this to be an integer, we want
23579ad5fb2SArjun P /// coeffM*M + a_1*s_1 + ... + a_m*s_m + b_1*y_1 + ... + b_n*y_n = -c (mod d)
23679ad5fb2SArjun P /// Note that this constraint must always hold, independent of the basis,
23779ad5fb2SArjun P /// becuse the row unknown's value always equals this expression, even if *we*
23879ad5fb2SArjun P /// later compute the sample value from a different expression based on a
23979ad5fb2SArjun P /// different basis.
24079ad5fb2SArjun P ///
24179ad5fb2SArjun P /// Let us assume that M has a factor of d in it. Imposing this constraint on M
24279ad5fb2SArjun P /// does not in any way hinder us from finding a value of M that is big enough.
24379ad5fb2SArjun P /// Moreover, this function is only called when the symbolic part of the sample,
24479ad5fb2SArjun P /// a_1*s_1 + ... + a_m*s_m, is known to be an integer.
24579ad5fb2SArjun P ///
24679ad5fb2SArjun P /// Also, we can safely reduce the coefficients modulo d, so we have:
24779ad5fb2SArjun P ///
24879ad5fb2SArjun P /// (b_1%d)y_1 + ... + (b_n%d)y_n = (-c%d) + k*d for some integer `k`
24979ad5fb2SArjun P ///
25079ad5fb2SArjun P /// Note that all coefficient modulos here are non-negative. Also, all the
25179ad5fb2SArjun P /// unknowns are non-negative here as both constraints and variables are
25279ad5fb2SArjun P /// non-negative in LexSimplexBase. (We used the big M trick to make the
25379ad5fb2SArjun P /// variables non-negative). Therefore, the LHS here is non-negative.
25479ad5fb2SArjun P /// Since 0 <= (-c%d) < d, k is the quotient of dividing the LHS by d and
25579ad5fb2SArjun P /// is therefore non-negative as well.
25679ad5fb2SArjun P ///
25779ad5fb2SArjun P /// So we have
25879ad5fb2SArjun P /// ((b_1%d)y_1 + ... + (b_n%d)y_n - (-c%d))/d >= 0.
25979ad5fb2SArjun P ///
26079ad5fb2SArjun P /// The constraint is violated when added (it would be useless otherwise)
26179ad5fb2SArjun P /// so we immediately try to move it to a column.
addCut(unsigned row)262acb378e2SArjun P LogicalResult LexSimplexBase::addCut(unsigned row) {
26379ad5fb2SArjun P   int64_t d = tableau(row, 0);
2648bc2cff9SArjun P   unsigned cutRow = addZeroRow(/*makeRestricted=*/true);
2658bc2cff9SArjun P   tableau(cutRow, 0) = d;
2668bc2cff9SArjun P   tableau(cutRow, 1) = -mod(-tableau(row, 1), d); // -c%d.
2678bc2cff9SArjun P   tableau(cutRow, 2) = 0;
2688bc2cff9SArjun P   for (unsigned col = 3 + nSymbol, e = getNumColumns(); col < e; ++col)
2698bc2cff9SArjun P     tableau(cutRow, col) = mod(tableau(row, col), d); // b_i%d.
2708bc2cff9SArjun P   return moveRowUnknownToColumn(cutRow);
2719f8cb685SArjun P }
2729f8cb685SArjun P 
maybeGetNonIntegralVarRow() const27335b73917SArjun P Optional<unsigned> LexSimplex::maybeGetNonIntegralVarRow() const {
2749f8cb685SArjun P   for (const Unknown &u : var) {
2759f8cb685SArjun P     if (u.orientation == Orientation::Column)
2769f8cb685SArjun P       continue;
2779f8cb685SArjun P     // If the sample value is of the form (a/d)M + b/d, we need b to be
27879ad5fb2SArjun P     // divisible by d. We assume M contains all possible
2799f8cb685SArjun P     // factors and is divisible by everything.
2809f8cb685SArjun P     unsigned row = u.pos;
2819f8cb685SArjun P     if (tableau(row, 1) % tableau(row, 0) != 0)
2829f8cb685SArjun P       return row;
2839f8cb685SArjun P   }
2849f8cb685SArjun P   return {};
2859f8cb685SArjun P }
2869f8cb685SArjun P 
findIntegerLexMin()287cfd6ba89SArjun P MaybeOptimum<SmallVector<int64_t, 8>> LexSimplex::findIntegerLexMin() {
28879ad5fb2SArjun P   // We first try to make the tableau consistent.
28979ad5fb2SArjun P   if (restoreRationalConsistency().failed())
2909f8cb685SArjun P     return OptimumKind::Empty;
2919f8cb685SArjun P 
29279ad5fb2SArjun P   // Then, if the sample value is integral, we are done.
29379ad5fb2SArjun P   while (Optional<unsigned> maybeRow = maybeGetNonIntegralVarRow()) {
29479ad5fb2SArjun P     // Otherwise, for the variable whose row has a non-integral sample value,
29579ad5fb2SArjun P     // we add a cut, a constraint that remove this rational point
29679ad5fb2SArjun P     // while preserving all integer points, thus keeping the lexmin the same.
29779ad5fb2SArjun P     // We then again try to make the tableau with the new constraint
29879ad5fb2SArjun P     // consistent. This continues until the tableau becomes empty, in which
29979ad5fb2SArjun P     // case there is no integer point, or until there are no variables with
30079ad5fb2SArjun P     // non-integral sample values.
30179ad5fb2SArjun P     //
30279ad5fb2SArjun P     // Failure indicates that the tableau became empty, which occurs when the
30379ad5fb2SArjun P     // polytope is integer empty.
30479ad5fb2SArjun P     if (addCut(*maybeRow).failed())
3059f8cb685SArjun P       return OptimumKind::Empty;
30679ad5fb2SArjun P     if (restoreRationalConsistency().failed())
30779ad5fb2SArjun P       return OptimumKind::Empty;
3089f8cb685SArjun P   }
3099f8cb685SArjun P 
3109f8cb685SArjun P   MaybeOptimum<SmallVector<Fraction, 8>> sample = getRationalSample();
3119f8cb685SArjun P   assert(!sample.isEmpty() && "If we reached here the sample should exist!");
3129f8cb685SArjun P   if (sample.isUnbounded())
3139f8cb685SArjun P     return OptimumKind::Unbounded;
314ef6f7c4aSArjun P   return llvm::to_vector<8>(
315ef6f7c4aSArjun P       llvm::map_range(*sample, std::mem_fn(&Fraction::getAsInteger)));
3169f8cb685SArjun P }
3179f8cb685SArjun P 
isSeparateInequality(ArrayRef<int64_t> coeffs)318fbeb0db5SArjun P bool LexSimplex::isSeparateInequality(ArrayRef<int64_t> coeffs) {
319fbeb0db5SArjun P   SimplexRollbackScopeExit scopeExit(*this);
320fbeb0db5SArjun P   addInequality(coeffs);
321fbeb0db5SArjun P   return findIntegerLexMin().isEmpty();
322fbeb0db5SArjun P }
323fbeb0db5SArjun P 
isRedundantInequality(ArrayRef<int64_t> coeffs)324fbeb0db5SArjun P bool LexSimplex::isRedundantInequality(ArrayRef<int64_t> coeffs) {
325fbeb0db5SArjun P   return isSeparateInequality(getComplementIneq(coeffs));
326fbeb0db5SArjun P }
32779ad5fb2SArjun P 
32879ad5fb2SArjun P SmallVector<int64_t, 8>
getSymbolicSampleNumerator(unsigned row) const32979ad5fb2SArjun P SymbolicLexSimplex::getSymbolicSampleNumerator(unsigned row) const {
33079ad5fb2SArjun P   SmallVector<int64_t, 8> sample;
33179ad5fb2SArjun P   sample.reserve(nSymbol + 1);
33279ad5fb2SArjun P   for (unsigned col = 3; col < 3 + nSymbol; ++col)
33379ad5fb2SArjun P     sample.push_back(tableau(row, col));
33479ad5fb2SArjun P   sample.push_back(tableau(row, 1));
33579ad5fb2SArjun P   return sample;
33679ad5fb2SArjun P }
33779ad5fb2SArjun P 
338aafb4282SArjun P SmallVector<int64_t, 8>
getSymbolicSampleIneq(unsigned row) const339aafb4282SArjun P SymbolicLexSimplex::getSymbolicSampleIneq(unsigned row) const {
340aafb4282SArjun P   SmallVector<int64_t, 8> sample = getSymbolicSampleNumerator(row);
341aafb4282SArjun P   // The inequality is equivalent to the GCD-normalized one.
342aafb4282SArjun P   normalizeRange(sample);
343aafb4282SArjun P   return sample;
344aafb4282SArjun P }
345aafb4282SArjun P 
appendSymbol()34679ad5fb2SArjun P void LexSimplexBase::appendSymbol() {
34779ad5fb2SArjun P   appendVariable();
3488bc2cff9SArjun P   swapColumns(3 + nSymbol, getNumColumns() - 1);
34979ad5fb2SArjun P   var.back().isSymbol = true;
35079ad5fb2SArjun P   nSymbol++;
35179ad5fb2SArjun P }
35279ad5fb2SArjun P 
isRangeDivisibleBy(ArrayRef<int64_t> range,int64_t divisor)35379ad5fb2SArjun P static bool isRangeDivisibleBy(ArrayRef<int64_t> range, int64_t divisor) {
35479ad5fb2SArjun P   assert(divisor > 0 && "divisor must be positive!");
35579ad5fb2SArjun P   return llvm::all_of(range, [divisor](int64_t x) { return x % divisor == 0; });
35679ad5fb2SArjun P }
35779ad5fb2SArjun P 
isSymbolicSampleIntegral(unsigned row) const35879ad5fb2SArjun P bool SymbolicLexSimplex::isSymbolicSampleIntegral(unsigned row) const {
35979ad5fb2SArjun P   int64_t denom = tableau(row, 0);
36079ad5fb2SArjun P   return tableau(row, 1) % denom == 0 &&
36179ad5fb2SArjun P          isRangeDivisibleBy(tableau.getRow(row).slice(3, nSymbol), denom);
36279ad5fb2SArjun P }
36379ad5fb2SArjun P 
3644aeb2a57SArjun P /// This proceeds similarly to LexSimplexBase::addCut(). We are given a row that
3654aeb2a57SArjun P /// has a symbolic sample value with fractional coefficients.
36679ad5fb2SArjun P ///
36779ad5fb2SArjun P /// Let the row be
36879ad5fb2SArjun P /// (c + coeffM*M + sum_i a_i*s_i + sum_j b_j*y_j)/d,
36979ad5fb2SArjun P /// where s_1, ... s_m are the symbols and
37079ad5fb2SArjun P ///       y_1, ... y_n are the other basis unknowns.
37179ad5fb2SArjun P ///
37279ad5fb2SArjun P /// As in LexSimplex::addCut, for this to be an integer, we want
37379ad5fb2SArjun P ///
37479ad5fb2SArjun P /// coeffM*M + sum_j b_j*y_j = -c + sum_i (-a_i*s_i) (mod d)
37579ad5fb2SArjun P ///
37679ad5fb2SArjun P /// This time, a_1*s_1 + ... + a_m*s_m may not be an integer. We find that
37779ad5fb2SArjun P ///
37879ad5fb2SArjun P /// sum_i (b_i%d)y_i = ((-c%d) + sum_i (-a_i%d)s_i)%d + k*d for some integer k
37979ad5fb2SArjun P ///
38079ad5fb2SArjun P /// where we take a modulo of the whole symbolic expression on the right to
3814aeb2a57SArjun P /// bring it into the range [0, d - 1]. Therefore, as in addCut(),
38279ad5fb2SArjun P /// k is the quotient on dividing the LHS by d, and since LHS >= 0, we have
3834aeb2a57SArjun P /// k >= 0 as well. If all the a_i are divisible by d, then we can add the
3844aeb2a57SArjun P /// constraint directly.  Otherwise, we realize the modulo of the symbolic
3854aeb2a57SArjun P /// expression by adding a division variable
38679ad5fb2SArjun P ///
38779ad5fb2SArjun P /// q = ((-c%d) + sum_i (-a_i%d)s_i)/d
38879ad5fb2SArjun P ///
38979ad5fb2SArjun P /// to the symbol domain, so the equality becomes
39079ad5fb2SArjun P ///
39179ad5fb2SArjun P /// sum_i (b_i%d)y_i = (-c%d) + sum_i (-a_i%d)s_i - q*d + k*d for some integer k
39279ad5fb2SArjun P ///
39379ad5fb2SArjun P /// So the cut is
39479ad5fb2SArjun P /// (sum_i (b_i%d)y_i - (-c%d) - sum_i (-a_i%d)s_i + q*d)/d >= 0
39579ad5fb2SArjun P /// This constraint is violated when added so we immediately try to move it to a
39679ad5fb2SArjun P /// column.
addSymbolicCut(unsigned row)39779ad5fb2SArjun P LogicalResult SymbolicLexSimplex::addSymbolicCut(unsigned row) {
39879ad5fb2SArjun P   int64_t d = tableau(row, 0);
399ef8b2a7cSArjun P   if (isRangeDivisibleBy(tableau.getRow(row).slice(3, nSymbol), d)) {
400ef8b2a7cSArjun P     // The coefficients of symbols in the symbol numerator are divisible
401ef8b2a7cSArjun P     // by the denominator, so we can add the constraint directly,
402ef8b2a7cSArjun P     // i.e., ignore the symbols and add a regular cut as in addCut().
403ef8b2a7cSArjun P     return addCut(row);
404ef8b2a7cSArjun P   }
40579ad5fb2SArjun P 
4064aeb2a57SArjun P   // Construct the division variable `q = ((-c%d) + sum_i (-a_i%d)s_i)/d`.
407aafb4282SArjun P   SmallVector<int64_t, 8> divCoeffs;
408aafb4282SArjun P   divCoeffs.reserve(nSymbol + 1);
409aafb4282SArjun P   int64_t divDenom = d;
41079ad5fb2SArjun P   for (unsigned col = 3; col < 3 + nSymbol; ++col)
411aafb4282SArjun P     divCoeffs.push_back(mod(-tableau(row, col), divDenom)); // (-a_i%d)s_i
412aafb4282SArjun P   divCoeffs.push_back(mod(-tableau(row, 1), divDenom));     // -c%d.
413aafb4282SArjun P   normalizeDiv(divCoeffs, divDenom);
4144aeb2a57SArjun P 
415aafb4282SArjun P   domainSimplex.addDivisionVariable(divCoeffs, divDenom);
416aafb4282SArjun P   domainPoly.addLocalFloorDiv(divCoeffs, divDenom);
41779ad5fb2SArjun P 
41879ad5fb2SArjun P   // Update `this` to account for the additional symbol we just added.
41979ad5fb2SArjun P   appendSymbol();
42079ad5fb2SArjun P 
42179ad5fb2SArjun P   // Add the cut (sum_i (b_i%d)y_i - (-c%d) + sum_i -(-a_i%d)s_i + q*d)/d >= 0.
4228bc2cff9SArjun P   unsigned cutRow = addZeroRow(/*makeRestricted=*/true);
4238bc2cff9SArjun P   tableau(cutRow, 0) = d;
4248bc2cff9SArjun P   tableau(cutRow, 2) = 0;
42579ad5fb2SArjun P 
4268bc2cff9SArjun P   tableau(cutRow, 1) = -mod(-tableau(row, 1), d); // -(-c%d).
42779ad5fb2SArjun P   for (unsigned col = 3; col < 3 + nSymbol - 1; ++col)
4288bc2cff9SArjun P     tableau(cutRow, col) = -mod(-tableau(row, col), d); // -(-a_i%d)s_i.
4298bc2cff9SArjun P   tableau(cutRow, 3 + nSymbol - 1) = d;                 // q*d.
43079ad5fb2SArjun P 
4318bc2cff9SArjun P   for (unsigned col = 3 + nSymbol, e = getNumColumns(); col < e; ++col)
4328bc2cff9SArjun P     tableau(cutRow, col) = mod(tableau(row, col), d); // (b_i%d)y_i.
4338bc2cff9SArjun P   return moveRowUnknownToColumn(cutRow);
43479ad5fb2SArjun P }
43579ad5fb2SArjun P 
recordOutput(SymbolicLexMin & result) const43679ad5fb2SArjun P void SymbolicLexSimplex::recordOutput(SymbolicLexMin &result) const {
437d95140a5SGroverkss   Matrix output(0, domainPoly.getNumVars() + 1);
43879ad5fb2SArjun P   output.reserveRows(result.lexmin.getNumOutputs());
43979ad5fb2SArjun P   for (const Unknown &u : var) {
44079ad5fb2SArjun P     if (u.isSymbol)
44179ad5fb2SArjun P       continue;
44279ad5fb2SArjun P 
44379ad5fb2SArjun P     if (u.orientation == Orientation::Column) {
44479ad5fb2SArjun P       // M + u has a sample value of zero so u has a sample value of -M, i.e,
44579ad5fb2SArjun P       // unbounded.
44679ad5fb2SArjun P       result.unboundedDomain.unionInPlace(domainPoly);
44779ad5fb2SArjun P       return;
44879ad5fb2SArjun P     }
44979ad5fb2SArjun P 
45079ad5fb2SArjun P     int64_t denom = tableau(u.pos, 0);
45179ad5fb2SArjun P     if (tableau(u.pos, 2) < denom) {
45279ad5fb2SArjun P       // M + u has a sample value of fM + something, where f < 1, so
45379ad5fb2SArjun P       // u = (f - 1)M + something, which has a negative coefficient for M,
45479ad5fb2SArjun P       // and so is unbounded.
45579ad5fb2SArjun P       result.unboundedDomain.unionInPlace(domainPoly);
45679ad5fb2SArjun P       return;
45779ad5fb2SArjun P     }
45879ad5fb2SArjun P     assert(tableau(u.pos, 2) == denom &&
45979ad5fb2SArjun P            "Coefficient of M should not be greater than 1!");
46079ad5fb2SArjun P 
46179ad5fb2SArjun P     SmallVector<int64_t, 8> sample = getSymbolicSampleNumerator(u.pos);
46279ad5fb2SArjun P     for (int64_t &elem : sample) {
46379ad5fb2SArjun P       assert(elem % denom == 0 && "coefficients must be integral!");
46479ad5fb2SArjun P       elem /= denom;
46579ad5fb2SArjun P     }
46679ad5fb2SArjun P     output.appendExtraRow(sample);
46779ad5fb2SArjun P   }
46879ad5fb2SArjun P   result.lexmin.addPiece(domainPoly, output);
46979ad5fb2SArjun P }
47079ad5fb2SArjun P 
maybeGetAlwaysViolatedRow()47179ad5fb2SArjun P Optional<unsigned> SymbolicLexSimplex::maybeGetAlwaysViolatedRow() {
47279ad5fb2SArjun P   // First look for rows that are clearly violated just from the big M
47379ad5fb2SArjun P   // coefficient, without needing to perform any simplex queries on the domain.
4748bc2cff9SArjun P   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
47579ad5fb2SArjun P     if (tableau(row, 2) < 0)
47679ad5fb2SArjun P       return row;
47779ad5fb2SArjun P 
4788bc2cff9SArjun P   for (unsigned row = 0, e = getNumRows(); row < e; ++row) {
47979ad5fb2SArjun P     if (tableau(row, 2) > 0)
48079ad5fb2SArjun P       continue;
481aafb4282SArjun P     if (domainSimplex.isSeparateInequality(getSymbolicSampleIneq(row))) {
48279ad5fb2SArjun P       // Sample numerator always takes negative values in the symbol domain.
48379ad5fb2SArjun P       return row;
48479ad5fb2SArjun P     }
48579ad5fb2SArjun P   }
48679ad5fb2SArjun P   return {};
48779ad5fb2SArjun P }
48879ad5fb2SArjun P 
maybeGetNonIntegralVarRow()48979ad5fb2SArjun P Optional<unsigned> SymbolicLexSimplex::maybeGetNonIntegralVarRow() {
49079ad5fb2SArjun P   for (const Unknown &u : var) {
49179ad5fb2SArjun P     if (u.orientation == Orientation::Column)
49279ad5fb2SArjun P       continue;
49379ad5fb2SArjun P     assert(!u.isSymbol && "Symbol should not be in row orientation!");
49479ad5fb2SArjun P     if (!isSymbolicSampleIntegral(u.pos))
49579ad5fb2SArjun P       return u.pos;
49679ad5fb2SArjun P   }
49779ad5fb2SArjun P   return {};
49879ad5fb2SArjun P }
49979ad5fb2SArjun P 
50079ad5fb2SArjun P /// The non-branching pivots are just the ones moving the rows
50179ad5fb2SArjun P /// that are always violated in the symbol domain.
doNonBranchingPivots()50279ad5fb2SArjun P LogicalResult SymbolicLexSimplex::doNonBranchingPivots() {
50379ad5fb2SArjun P   while (Optional<unsigned> row = maybeGetAlwaysViolatedRow())
50479ad5fb2SArjun P     if (moveRowUnknownToColumn(*row).failed())
50579ad5fb2SArjun P       return failure();
50679ad5fb2SArjun P   return success();
50779ad5fb2SArjun P }
50879ad5fb2SArjun P 
computeSymbolicIntegerLexMin()50979ad5fb2SArjun P SymbolicLexMin SymbolicLexSimplex::computeSymbolicIntegerLexMin() {
510*c2fcaf84SArjun P   SymbolicLexMin result(domainPoly.getSpace(), var.size() - nSymbol);
51179ad5fb2SArjun P 
51279ad5fb2SArjun P   /// The algorithm is more naturally expressed recursively, but we implement
51379ad5fb2SArjun P   /// it iteratively here to avoid potential issues with stack overflows in the
51479ad5fb2SArjun P   /// compiler. We explicitly maintain the stack frames in a vector.
51579ad5fb2SArjun P   ///
51679ad5fb2SArjun P   /// To "recurse", we store the current "stack frame", i.e., state variables
51779ad5fb2SArjun P   /// that we will need when we "return", into `stack`, increment `level`, and
51879ad5fb2SArjun P   /// `continue`. To "tail recurse", we just `continue`.
51979ad5fb2SArjun P   /// To "return", we decrement `level` and `continue`.
52079ad5fb2SArjun P   ///
52179ad5fb2SArjun P   /// When there is no stack frame for the current `level`, this indicates that
52279ad5fb2SArjun P   /// we have just "recursed" or "tail recursed". When there does exist one,
52379ad5fb2SArjun P   /// this indicates that we have just "returned" from recursing. There is only
52479ad5fb2SArjun P   /// one point at which non-tail calls occur so we always "return" there.
52579ad5fb2SArjun P   unsigned level = 1;
52679ad5fb2SArjun P   struct StackFrame {
52779ad5fb2SArjun P     int splitIndex;
52879ad5fb2SArjun P     unsigned snapshot;
52979ad5fb2SArjun P     unsigned domainSnapshot;
53079ad5fb2SArjun P     IntegerRelation::CountsSnapshot domainPolyCounts;
53179ad5fb2SArjun P   };
53279ad5fb2SArjun P   SmallVector<StackFrame, 8> stack;
53379ad5fb2SArjun P 
53479ad5fb2SArjun P   while (level > 0) {
53579ad5fb2SArjun P     assert(level >= stack.size());
53679ad5fb2SArjun P     if (level > stack.size()) {
53779ad5fb2SArjun P       if (empty || domainSimplex.findIntegerLexMin().isEmpty()) {
53879ad5fb2SArjun P         // No integer points; return.
53979ad5fb2SArjun P         --level;
54079ad5fb2SArjun P         continue;
54179ad5fb2SArjun P       }
54279ad5fb2SArjun P 
54379ad5fb2SArjun P       if (doNonBranchingPivots().failed()) {
54479ad5fb2SArjun P         // Could not find pivots for violated constraints; return.
54579ad5fb2SArjun P         --level;
54679ad5fb2SArjun P         continue;
54779ad5fb2SArjun P       }
54879ad5fb2SArjun P 
54979ad5fb2SArjun P       SmallVector<int64_t, 8> symbolicSample;
5508bc2cff9SArjun P       unsigned splitRow = 0;
5518bc2cff9SArjun P       for (unsigned e = getNumRows(); splitRow < e; ++splitRow) {
55279ad5fb2SArjun P         if (tableau(splitRow, 2) > 0)
55379ad5fb2SArjun P           continue;
55479ad5fb2SArjun P         assert(tableau(splitRow, 2) == 0 &&
55579ad5fb2SArjun P                "Non-branching pivots should have been handled already!");
55679ad5fb2SArjun P 
557aafb4282SArjun P         symbolicSample = getSymbolicSampleIneq(splitRow);
55879ad5fb2SArjun P         if (domainSimplex.isRedundantInequality(symbolicSample))
55979ad5fb2SArjun P           continue;
56079ad5fb2SArjun P 
56179ad5fb2SArjun P         // It's neither redundant nor separate, so it takes both positive and
56279ad5fb2SArjun P         // negative values, and hence constitutes a row for which we need to
56379ad5fb2SArjun P         // split the domain and separately run each case.
56479ad5fb2SArjun P         assert(!domainSimplex.isSeparateInequality(symbolicSample) &&
56579ad5fb2SArjun P                "Non-branching pivots should have been handled already!");
56679ad5fb2SArjun P         break;
56779ad5fb2SArjun P       }
56879ad5fb2SArjun P 
5698bc2cff9SArjun P       if (splitRow < getNumRows()) {
57079ad5fb2SArjun P         unsigned domainSnapshot = domainSimplex.getSnapshot();
57179ad5fb2SArjun P         IntegerRelation::CountsSnapshot domainPolyCounts =
57279ad5fb2SArjun P             domainPoly.getCounts();
57379ad5fb2SArjun P 
57479ad5fb2SArjun P         // First, we consider the part of the domain where the row is not
57579ad5fb2SArjun P         // violated. We don't have to do any pivots for the row in this case,
57679ad5fb2SArjun P         // but we record the additional constraint that defines this part of
57779ad5fb2SArjun P         // the domain.
57879ad5fb2SArjun P         domainSimplex.addInequality(symbolicSample);
57979ad5fb2SArjun P         domainPoly.addInequality(symbolicSample);
58079ad5fb2SArjun P 
58179ad5fb2SArjun P         // Recurse.
58279ad5fb2SArjun P         //
58379ad5fb2SArjun P         // On return, the basis as a set is preserved but not the internal
58479ad5fb2SArjun P         // ordering within rows or columns. Thus, we take note of the index of
58579ad5fb2SArjun P         // the Unknown that caused the split, which may be in a different
58679ad5fb2SArjun P         // row when we come back from recursing. We will need this to recurse
58779ad5fb2SArjun P         // on the other part of the split domain, where the row is violated.
58879ad5fb2SArjun P         //
58979ad5fb2SArjun P         // Note that we have to capture the index above and not a reference to
59079ad5fb2SArjun P         // the Unknown itself, since the array it lives in might get
59179ad5fb2SArjun P         // reallocated.
59279ad5fb2SArjun P         int splitIndex = rowUnknown[splitRow];
59379ad5fb2SArjun P         unsigned snapshot = getSnapshot();
59479ad5fb2SArjun P         stack.push_back(
59579ad5fb2SArjun P             {splitIndex, snapshot, domainSnapshot, domainPolyCounts});
59679ad5fb2SArjun P         ++level;
59779ad5fb2SArjun P         continue;
59879ad5fb2SArjun P       }
59979ad5fb2SArjun P 
60079ad5fb2SArjun P       // The tableau is rationally consistent for the current domain.
60179ad5fb2SArjun P       // Now we look for non-integral sample values and add cuts for them.
60279ad5fb2SArjun P       if (Optional<unsigned> row = maybeGetNonIntegralVarRow()) {
60379ad5fb2SArjun P         if (addSymbolicCut(*row).failed()) {
60479ad5fb2SArjun P           // No integral points; return.
60579ad5fb2SArjun P           --level;
60679ad5fb2SArjun P           continue;
60779ad5fb2SArjun P         }
60879ad5fb2SArjun P 
60979ad5fb2SArjun P         // Rerun this level with the added cut constraint (tail recurse).
61079ad5fb2SArjun P         continue;
61179ad5fb2SArjun P       }
61279ad5fb2SArjun P 
61379ad5fb2SArjun P       // Record output and return.
61479ad5fb2SArjun P       recordOutput(result);
61579ad5fb2SArjun P       --level;
61679ad5fb2SArjun P       continue;
61779ad5fb2SArjun P     }
61879ad5fb2SArjun P 
61979ad5fb2SArjun P     if (level == stack.size()) {
62079ad5fb2SArjun P       // We have "returned" from "recursing".
62179ad5fb2SArjun P       const StackFrame &frame = stack.back();
62279ad5fb2SArjun P       domainPoly.truncate(frame.domainPolyCounts);
62379ad5fb2SArjun P       domainSimplex.rollback(frame.domainSnapshot);
62479ad5fb2SArjun P       rollback(frame.snapshot);
62579ad5fb2SArjun P       const Unknown &u = unknownFromIndex(frame.splitIndex);
62679ad5fb2SArjun P 
62779ad5fb2SArjun P       // Drop the frame. We don't need it anymore.
62879ad5fb2SArjun P       stack.pop_back();
62979ad5fb2SArjun P 
63079ad5fb2SArjun P       // Now we consider the part of the domain where the unknown `splitIndex`
63179ad5fb2SArjun P       // was negative.
63279ad5fb2SArjun P       assert(u.orientation == Orientation::Row &&
63379ad5fb2SArjun P              "The split row should have been returned to row orientation!");
63479ad5fb2SArjun P       SmallVector<int64_t, 8> splitIneq =
635aafb4282SArjun P           getComplementIneq(getSymbolicSampleIneq(u.pos));
636aafb4282SArjun P       normalizeRange(splitIneq);
63779ad5fb2SArjun P       if (moveRowUnknownToColumn(u.pos).failed()) {
63879ad5fb2SArjun P         // The unknown can't be made non-negative; return.
63979ad5fb2SArjun P         --level;
64079ad5fb2SArjun P         continue;
64179ad5fb2SArjun P       }
64279ad5fb2SArjun P 
64379ad5fb2SArjun P       // The unknown can be made negative; recurse with the corresponding domain
64479ad5fb2SArjun P       // constraints.
64579ad5fb2SArjun P       domainSimplex.addInequality(splitIneq);
64679ad5fb2SArjun P       domainPoly.addInequality(splitIneq);
64779ad5fb2SArjun P 
64879ad5fb2SArjun P       // We are now taking care of the second half of the domain and we don't
64979ad5fb2SArjun P       // need to do anything else here after returning, so it's a tail recurse.
65079ad5fb2SArjun P       continue;
65179ad5fb2SArjun P     }
65279ad5fb2SArjun P   }
65379ad5fb2SArjun P 
65479ad5fb2SArjun P   return result;
65579ad5fb2SArjun P }
65679ad5fb2SArjun P 
rowIsViolated(unsigned row) const6576db01958SArjun P bool LexSimplex::rowIsViolated(unsigned row) const {
6586db01958SArjun P   if (tableau(row, 2) < 0)
6596db01958SArjun P     return true;
6606db01958SArjun P   if (tableau(row, 2) == 0 && tableau(row, 1) < 0)
6616db01958SArjun P     return true;
6626db01958SArjun P   return false;
6636db01958SArjun P }
6646db01958SArjun P 
maybeGetViolatedRow() const6656db01958SArjun P Optional<unsigned> LexSimplex::maybeGetViolatedRow() const {
6668bc2cff9SArjun P   for (unsigned row = 0, e = getNumRows(); row < e; ++row)
6676db01958SArjun P     if (rowIsViolated(row))
6686db01958SArjun P       return row;
6696db01958SArjun P   return {};
6706db01958SArjun P }
6716db01958SArjun P 
67279ad5fb2SArjun P /// We simply look for violated rows and keep trying to move them to column
67379ad5fb2SArjun P /// orientation, which always succeeds unless the constraints have no solution
67479ad5fb2SArjun P /// in which case we just give up and return.
restoreRationalConsistency()67579ad5fb2SArjun P LogicalResult LexSimplex::restoreRationalConsistency() {
67679ad5fb2SArjun P   if (empty)
67779ad5fb2SArjun P     return failure();
67879ad5fb2SArjun P   while (Optional<unsigned> maybeViolatedRow = maybeGetViolatedRow())
67979ad5fb2SArjun P     if (moveRowUnknownToColumn(*maybeViolatedRow).failed())
68079ad5fb2SArjun P       return failure();
68179ad5fb2SArjun P   return success();
6826db01958SArjun P }
6836db01958SArjun P 
6846db01958SArjun P // Move the row unknown to column orientation while preserving lexicopositivity
68569c1a354SArjun P // of the basis transform. The sample value of the row must be non-positive.
6866db01958SArjun P //
6876db01958SArjun P // We only consider pivots where the pivot element is positive. Suppose no such
6886db01958SArjun P // pivot exists, i.e., some violated row has no positive coefficient for any
6896db01958SArjun P // basis unknown. The row can be represented as (s + c_1*u_1 + ... + c_n*u_n)/d,
6906db01958SArjun P // where d is the denominator, s is the sample value and the c_i are the basis
69169c1a354SArjun P // coefficients. If s != 0, then since any feasible assignment of the basis
69269c1a354SArjun P // satisfies u_i >= 0 for all i, and we have s < 0 as well as c_i < 0 for all i,
69369c1a354SArjun P // any feasible assignment would violate this row and therefore the constraints
69469c1a354SArjun P // have no solution.
6956db01958SArjun P //
6966db01958SArjun P // We can preserve lexicopositivity by picking the pivot column with positive
6976db01958SArjun P // pivot element that makes the lexicographically smallest change to the sample
6986db01958SArjun P // point.
6996db01958SArjun P //
7006db01958SArjun P // Proof. Let
7016db01958SArjun P // x = (x_1, ... x_n) be the variables,
7026db01958SArjun P // z = (z_1, ... z_m) be the constraints,
7036db01958SArjun P // y = (y_1, ... y_n) be the current basis, and
7046db01958SArjun P // define w = (x_1, ... x_n, z_1, ... z_m) = B*y + s.
7056db01958SArjun P // B is basically the simplex tableau of our implementation except that instead
7066db01958SArjun P // of only describing the transform to get back the non-basis unknowns, it
7076db01958SArjun P // defines the values of all the unknowns in terms of the basis unknowns.
7086db01958SArjun P // Similarly, s is the column for the sample value.
7096db01958SArjun P //
7106db01958SArjun P // Our goal is to show that each column in B, restricted to the first n
7116db01958SArjun P // rows, is lexicopositive after the pivot if it is so before. This is
7126db01958SArjun P // equivalent to saying the columns in the whole matrix are lexicopositive;
7136db01958SArjun P // there must be some non-zero element in every column in the first n rows since
7146db01958SArjun P // the n variables cannot be spanned without using all the n basis unknowns.
7156db01958SArjun P //
7166db01958SArjun P // Consider a pivot where z_i replaces y_j in the basis. Recall the pivot
7176db01958SArjun P // transform for the tableau derived for SimplexBase::pivot:
7186db01958SArjun P //
7196db01958SArjun P //            pivot col    other col                   pivot col    other col
7206db01958SArjun P // pivot row     a             b       ->   pivot row     1/a         -b/a
7216db01958SArjun P // other row     c             d            other row     c/a        d - bc/a
7226db01958SArjun P //
7236db01958SArjun P // Similarly, a pivot results in B changing to B' and c to c'; the difference
7246db01958SArjun P // between the tableau and these matrices B and B' is that there is no special
7256db01958SArjun P // case for the pivot row, since it continues to represent the same unknown. The
7266db01958SArjun P // same formula applies for all rows:
7276db01958SArjun P //
7286db01958SArjun P // B'.col(j) = B.col(j) / B(i,j)
7296db01958SArjun P // B'.col(k) = B.col(k) - B(i,k) * B.col(j) / B(i,j) for k != j
7306db01958SArjun P // and similarly, s' = s - s_i * B.col(j) / B(i,j).
7316db01958SArjun P //
73269c1a354SArjun P // If s_i == 0, then the sample value remains unchanged. Otherwise, if s_i < 0,
73369c1a354SArjun P // the change in sample value when pivoting with column a is lexicographically
73469c1a354SArjun P // smaller than that when pivoting with column b iff B.col(a) / B(i, a) is
73569c1a354SArjun P // lexicographically smaller than B.col(b) / B(i, b).
7366db01958SArjun P //
7376db01958SArjun P // Since B(i, j) > 0, column j remains lexicopositive.
7386db01958SArjun P //
7396db01958SArjun P // For the other columns, suppose C.col(k) is not lexicopositive.
7406db01958SArjun P // This means that for some p, for all t < p,
7416db01958SArjun P // C(t,k) = 0 => B(t,k) = B(t,j) * B(i,k) / B(i,j) and
7426db01958SArjun P // C(t,k) < 0 => B(p,k) < B(t,j) * B(i,k) / B(i,j),
7436db01958SArjun P // which is in contradiction to the fact that B.col(j) / B(i,j) must be
7446db01958SArjun P // lexicographically smaller than B.col(k) / B(i,k), since it lexicographically
7456db01958SArjun P // minimizes the change in sample value.
moveRowUnknownToColumn(unsigned row)746acb378e2SArjun P LogicalResult LexSimplexBase::moveRowUnknownToColumn(unsigned row) {
7476db01958SArjun P   Optional<unsigned> maybeColumn;
7488bc2cff9SArjun P   for (unsigned col = 3 + nSymbol, e = getNumColumns(); col < e; ++col) {
7496db01958SArjun P     if (tableau(row, col) <= 0)
7506db01958SArjun P       continue;
7516db01958SArjun P     maybeColumn =
7526db01958SArjun P         !maybeColumn ? col : getLexMinPivotColumn(row, *maybeColumn, col);
7536db01958SArjun P   }
7546db01958SArjun P 
75569c1a354SArjun P   if (!maybeColumn)
7566db01958SArjun P     return failure();
7576db01958SArjun P 
7586db01958SArjun P   pivot(row, *maybeColumn);
7596db01958SArjun P   return success();
7606db01958SArjun P }
7616db01958SArjun P 
getLexMinPivotColumn(unsigned row,unsigned colA,unsigned colB) const762acb378e2SArjun P unsigned LexSimplexBase::getLexMinPivotColumn(unsigned row, unsigned colA,
7636db01958SArjun P                                               unsigned colB) const {
76479ad5fb2SArjun P   // First, let's consider the non-symbolic case.
7656db01958SArjun P   // A pivot causes the following change. (in the diagram the matrix elements
7666db01958SArjun P   // are shown as rationals and there is no common denominator used)
7676db01958SArjun P   //
7686db01958SArjun P   //            pivot col    big M col      const col
7696db01958SArjun P   // pivot row     a            p               b
7706db01958SArjun P   // other row     c            q               d
7716db01958SArjun P   //                        |
7726db01958SArjun P   //                        v
7736db01958SArjun P   //
7746db01958SArjun P   //            pivot col    big M col      const col
7756db01958SArjun P   // pivot row     1/a         -p/a           -b/a
7766db01958SArjun P   // other row     c/a        q - pc/a       d - bc/a
7776db01958SArjun P   //
7786db01958SArjun P   // Let the sample value of the pivot row be s = pM + b before the pivot. Since
7796db01958SArjun P   // the pivot row represents a violated constraint we know that s < 0.
7806db01958SArjun P   //
7816db01958SArjun P   // If the variable is a non-pivot column, its sample value is zero before and
7826db01958SArjun P   // after the pivot.
7836db01958SArjun P   //
7846db01958SArjun P   // If the variable is the pivot column, then its sample value goes from 0 to
7856db01958SArjun P   // (-p/a)M + (-b/a), i.e. 0 to -(pM + b)/a. Thus the change in the sample
7866db01958SArjun P   // value is -s/a.
7876db01958SArjun P   //
78879ad5fb2SArjun P   // If the variable is the pivot row, its sample value goes from s to 0, for a
7896db01958SArjun P   // change of -s.
7906db01958SArjun P   //
7916db01958SArjun P   // If the variable is a non-pivot row, its sample value changes from
7926db01958SArjun P   // qM + d to qM + d + (-pc/a)M + (-bc/a). Thus the change in sample value
7936db01958SArjun P   // is -(pM + b)(c/a) = -sc/a.
7946db01958SArjun P   //
7956db01958SArjun P   // Thus the change in sample value is either 0, -s/a, -s, or -sc/a. Here -s is
7966db01958SArjun P   // fixed for all calls to this function since the row and tableau are fixed.
7976db01958SArjun P   // The callee just wants to compare the return values with the return value of
7986db01958SArjun P   // other invocations of the same function. So the -s is common for all
7996db01958SArjun P   // comparisons involved and can be ignored, since -s is strictly positive.
8006db01958SArjun P   //
8016db01958SArjun P   // Thus we take away this common factor and just return 0, 1/a, 1, or c/a as
80279ad5fb2SArjun P   // appropriate. This allows us to run the entire algorithm treating M
80379ad5fb2SArjun P   // symbolically, as the pivot to be performed does not depend on the value
80479ad5fb2SArjun P   // of M, so long as the sample value s is negative. Note that this is not
80579ad5fb2SArjun P   // because of any special feature of M; by the same argument, we ignore the
80679ad5fb2SArjun P   // symbols too. The caller ensure that the sample value s is negative for
80779ad5fb2SArjun P   // all possible values of the symbols.
8086db01958SArjun P   auto getSampleChangeCoeffForVar = [this, row](unsigned col,
8096db01958SArjun P                                                 const Unknown &u) -> Fraction {
8106db01958SArjun P     int64_t a = tableau(row, col);
8116db01958SArjun P     if (u.orientation == Orientation::Column) {
8126db01958SArjun P       // Pivot column case.
8136db01958SArjun P       if (u.pos == col)
8146db01958SArjun P         return {1, a};
8156db01958SArjun P 
8166db01958SArjun P       // Non-pivot column case.
8176db01958SArjun P       return {0, 1};
8186db01958SArjun P     }
8196db01958SArjun P 
8206db01958SArjun P     // Pivot row case.
8216db01958SArjun P     if (u.pos == row)
8226db01958SArjun P       return {1, 1};
8236db01958SArjun P 
8246db01958SArjun P     // Non-pivot row case.
8256db01958SArjun P     int64_t c = tableau(u.pos, col);
8266db01958SArjun P     return {c, a};
8276db01958SArjun P   };
8286db01958SArjun P 
8296db01958SArjun P   for (const Unknown &u : var) {
8306db01958SArjun P     Fraction changeA = getSampleChangeCoeffForVar(colA, u);
8316db01958SArjun P     Fraction changeB = getSampleChangeCoeffForVar(colB, u);
8326db01958SArjun P     if (changeA < changeB)
8336db01958SArjun P       return colA;
8346db01958SArjun P     if (changeA > changeB)
8356db01958SArjun P       return colB;
8366db01958SArjun P   }
8376db01958SArjun P 
8386db01958SArjun P   // If we reached here, both result in exactly the same changes, so it
8396db01958SArjun P   // doesn't matter which we return.
8406db01958SArjun P   return colA;
8416db01958SArjun P }
8426db01958SArjun P 
84310a898b3SArjun P /// Find a pivot to change the sample value of the row in the specified
84410a898b3SArjun P /// direction. The returned pivot row will involve `row` if and only if the
84510a898b3SArjun P /// unknown is unbounded in the specified direction.
84610a898b3SArjun P ///
84710a898b3SArjun P /// To increase (resp. decrease) the value of a row, we need to find a live
84810a898b3SArjun P /// column with a non-zero coefficient. If the coefficient is positive, we need
84910a898b3SArjun P /// to increase (decrease) the value of the column, and if the coefficient is
85010a898b3SArjun P /// negative, we need to decrease (increase) the value of the column. Also,
85110a898b3SArjun P /// we cannot decrease the sample value of restricted columns.
85210a898b3SArjun P ///
85310a898b3SArjun P /// If multiple columns are valid, we break ties by considering a lexicographic
85410a898b3SArjun P /// ordering where we prefer unknowns with lower index.
findPivot(int row,Direction direction) const8556db01958SArjun P Optional<SimplexBase::Pivot> Simplex::findPivot(int row,
85610a898b3SArjun P                                                 Direction direction) const {
85710a898b3SArjun P   Optional<unsigned> col;
8588bc2cff9SArjun P   for (unsigned j = 2, e = getNumColumns(); j < e; ++j) {
85910a898b3SArjun P     int64_t elem = tableau(row, j);
86010a898b3SArjun P     if (elem == 0)
86110a898b3SArjun P       continue;
86210a898b3SArjun P 
86310a898b3SArjun P     if (unknownFromColumn(j).restricted &&
86410a898b3SArjun P         !signMatchesDirection(elem, direction))
86510a898b3SArjun P       continue;
86610a898b3SArjun P     if (!col || colUnknown[j] < colUnknown[*col])
86710a898b3SArjun P       col = j;
86810a898b3SArjun P   }
86910a898b3SArjun P 
87010a898b3SArjun P   if (!col)
87110a898b3SArjun P     return {};
87210a898b3SArjun P 
87310a898b3SArjun P   Direction newDirection =
87410a898b3SArjun P       tableau(row, *col) < 0 ? flippedDirection(direction) : direction;
87510a898b3SArjun P   Optional<unsigned> maybePivotRow = findPivotRow(row, newDirection, *col);
87630c67587SKazu Hirata   return Pivot{maybePivotRow.value_or(row), *col};
87710a898b3SArjun P }
87810a898b3SArjun P 
87910a898b3SArjun P /// Swap the associated unknowns for the row and the column.
88010a898b3SArjun P ///
88110a898b3SArjun P /// First we swap the index associated with the row and column. Then we update
88210a898b3SArjun P /// the unknowns to reflect their new position and orientation.
swapRowWithCol(unsigned row,unsigned col)8834fa96b7eSArjun P void SimplexBase::swapRowWithCol(unsigned row, unsigned col) {
88410a898b3SArjun P   std::swap(rowUnknown[row], colUnknown[col]);
88510a898b3SArjun P   Unknown &uCol = unknownFromColumn(col);
88610a898b3SArjun P   Unknown &uRow = unknownFromRow(row);
88710a898b3SArjun P   uCol.orientation = Orientation::Column;
88810a898b3SArjun P   uRow.orientation = Orientation::Row;
88910a898b3SArjun P   uCol.pos = col;
89010a898b3SArjun P   uRow.pos = row;
89110a898b3SArjun P }
89210a898b3SArjun P 
pivot(Pivot pair)8934fa96b7eSArjun P void SimplexBase::pivot(Pivot pair) { pivot(pair.row, pair.column); }
89410a898b3SArjun P 
89510a898b3SArjun P /// Pivot pivotRow and pivotCol.
89610a898b3SArjun P ///
89710a898b3SArjun P /// Let R be the pivot row unknown and let C be the pivot col unknown.
89810a898b3SArjun P /// Since initially R = a*C + sum b_i * X_i
89910a898b3SArjun P /// (where the sum is over the other column's unknowns, x_i)
90010a898b3SArjun P /// C = (R - (sum b_i * X_i))/a
90110a898b3SArjun P ///
90210a898b3SArjun P /// Let u be some other row unknown.
90310a898b3SArjun P /// u = c*C + sum d_i * X_i
90410a898b3SArjun P /// So u = c*(R - sum b_i * X_i)/a + sum d_i * X_i
90510a898b3SArjun P ///
90610a898b3SArjun P /// This results in the following transform:
90710a898b3SArjun P ///            pivot col    other col                   pivot col    other col
90810a898b3SArjun P /// pivot row     a             b       ->   pivot row     1/a         -b/a
90910a898b3SArjun P /// other row     c             d            other row     c/a        d - bc/a
91010a898b3SArjun P ///
91110a898b3SArjun P /// Taking into account the common denominators p and q:
91210a898b3SArjun P ///
91310a898b3SArjun P ///            pivot col    other col                    pivot col   other col
91410a898b3SArjun P /// pivot row     a/p          b/p     ->   pivot row      p/a         -b/a
91510a898b3SArjun P /// other row     c/q          d/q          other row     cp/aq    (da - bc)/aq
91610a898b3SArjun P ///
91710a898b3SArjun P /// The pivot row transform is accomplished be swapping a with the pivot row's
91810a898b3SArjun P /// common denominator and negating the pivot row except for the pivot column
91910a898b3SArjun P /// element.
pivot(unsigned pivotRow,unsigned pivotCol)9204fa96b7eSArjun P void SimplexBase::pivot(unsigned pivotRow, unsigned pivotCol) {
9216db01958SArjun P   assert(pivotCol >= getNumFixedCols() && "Refusing to pivot invalid column");
92279ad5fb2SArjun P   assert(!unknownFromColumn(pivotCol).isSymbol);
92310a898b3SArjun P 
92410a898b3SArjun P   swapRowWithCol(pivotRow, pivotCol);
92510a898b3SArjun P   std::swap(tableau(pivotRow, 0), tableau(pivotRow, pivotCol));
92610a898b3SArjun P   // We need to negate the whole pivot row except for the pivot column.
92710a898b3SArjun P   if (tableau(pivotRow, 0) < 0) {
92810a898b3SArjun P     // If the denominator is negative, we negate the row by simply negating the
92910a898b3SArjun P     // denominator.
93010a898b3SArjun P     tableau(pivotRow, 0) = -tableau(pivotRow, 0);
93110a898b3SArjun P     tableau(pivotRow, pivotCol) = -tableau(pivotRow, pivotCol);
93210a898b3SArjun P   } else {
9338bc2cff9SArjun P     for (unsigned col = 1, e = getNumColumns(); col < e; ++col) {
93410a898b3SArjun P       if (col == pivotCol)
93510a898b3SArjun P         continue;
93610a898b3SArjun P       tableau(pivotRow, col) = -tableau(pivotRow, col);
93710a898b3SArjun P     }
93810a898b3SArjun P   }
939aafb4282SArjun P   tableau.normalizeRow(pivotRow);
94010a898b3SArjun P 
9418bc2cff9SArjun P   for (unsigned row = 0, numRows = getNumRows(); row < numRows; ++row) {
94210a898b3SArjun P     if (row == pivotRow)
94310a898b3SArjun P       continue;
94410a898b3SArjun P     if (tableau(row, pivotCol) == 0) // Nothing to do.
94510a898b3SArjun P       continue;
94610a898b3SArjun P     tableau(row, 0) *= tableau(pivotRow, 0);
9478bc2cff9SArjun P     for (unsigned col = 1, numCols = getNumColumns(); col < numCols; ++col) {
9488bc2cff9SArjun P       if (col == pivotCol)
94910a898b3SArjun P         continue;
95010a898b3SArjun P       // Add rather than subtract because the pivot row has been negated.
9518bc2cff9SArjun P       tableau(row, col) = tableau(row, col) * tableau(pivotRow, 0) +
9528bc2cff9SArjun P                           tableau(row, pivotCol) * tableau(pivotRow, col);
95310a898b3SArjun P     }
95410a898b3SArjun P     tableau(row, pivotCol) *= tableau(pivotRow, pivotCol);
955aafb4282SArjun P     tableau.normalizeRow(row);
95610a898b3SArjun P   }
95710a898b3SArjun P }
95810a898b3SArjun P 
95910a898b3SArjun P /// Perform pivots until the unknown has a non-negative sample value or until
960ad48ef1eSArjun P /// no more upward pivots can be performed. Return success if we were able to
961ad48ef1eSArjun P /// bring the row to a non-negative sample value, and failure otherwise.
restoreRow(Unknown & u)9626db01958SArjun P LogicalResult Simplex::restoreRow(Unknown &u) {
96310a898b3SArjun P   assert(u.orientation == Orientation::Row &&
96410a898b3SArjun P          "unknown should be in row position");
96510a898b3SArjun P 
96610a898b3SArjun P   while (tableau(u.pos, 1) < 0) {
96710a898b3SArjun P     Optional<Pivot> maybePivot = findPivot(u.pos, Direction::Up);
96810a898b3SArjun P     if (!maybePivot)
96910a898b3SArjun P       break;
97010a898b3SArjun P 
97110a898b3SArjun P     pivot(*maybePivot);
97210a898b3SArjun P     if (u.orientation == Orientation::Column)
973e21adfa3SRiver Riddle       return success(); // the unknown is unbounded above.
97410a898b3SArjun P   }
97510a898b3SArjun P   return success(tableau(u.pos, 1) >= 0);
97610a898b3SArjun P }
97710a898b3SArjun P 
97810a898b3SArjun P /// Find a row that can be used to pivot the column in the specified direction.
97910a898b3SArjun P /// This returns an empty optional if and only if the column is unbounded in the
98010a898b3SArjun P /// specified direction (ignoring skipRow, if skipRow is set).
98110a898b3SArjun P ///
98210a898b3SArjun P /// If skipRow is set, this row is not considered, and (if it is restricted) its
98310a898b3SArjun P /// restriction may be violated by the returned pivot. Usually, skipRow is set
98410a898b3SArjun P /// because we don't want to move it to column position unless it is unbounded,
98510a898b3SArjun P /// and we are either trying to increase the value of skipRow or explicitly
98610a898b3SArjun P /// trying to make skipRow negative, so we are not concerned about this.
98710a898b3SArjun P ///
98810a898b3SArjun P /// If the direction is up (resp. down) and a restricted row has a negative
98910a898b3SArjun P /// (positive) coefficient for the column, then this row imposes a bound on how
99010a898b3SArjun P /// much the sample value of the column can change. Such a row with constant
99110a898b3SArjun P /// term c and coefficient f for the column imposes a bound of c/|f| on the
99210a898b3SArjun P /// change in sample value (in the specified direction). (note that c is
99310a898b3SArjun P /// non-negative here since the row is restricted and the tableau is consistent)
99410a898b3SArjun P ///
99510a898b3SArjun P /// We iterate through the rows and pick the row which imposes the most
99610a898b3SArjun P /// stringent bound, since pivoting with a row changes the row's sample value to
99710a898b3SArjun P /// 0 and hence saturates the bound it imposes. We break ties between rows that
99810a898b3SArjun P /// impose the same bound by considering a lexicographic ordering where we
99910a898b3SArjun P /// prefer unknowns with lower index value.
findPivotRow(Optional<unsigned> skipRow,Direction direction,unsigned col) const10006db01958SArjun P Optional<unsigned> Simplex::findPivotRow(Optional<unsigned> skipRow,
100110a898b3SArjun P                                          Direction direction,
100210a898b3SArjun P                                          unsigned col) const {
100310a898b3SArjun P   Optional<unsigned> retRow;
1004ef835159SArjun P   // Initialize these to zero in order to silence a warning about retElem and
1005ef835159SArjun P   // retConst being used uninitialized in the initialization of `diff` below. In
1006ef835159SArjun P   // reality, these are always initialized when that line is reached since these
1007ef835159SArjun P   // are set whenever retRow is set.
1008ef835159SArjun P   int64_t retElem = 0, retConst = 0;
10098bc2cff9SArjun P   for (unsigned row = nRedundant, e = getNumRows(); row < e; ++row) {
101010a898b3SArjun P     if (skipRow && row == *skipRow)
101110a898b3SArjun P       continue;
101210a898b3SArjun P     int64_t elem = tableau(row, col);
101310a898b3SArjun P     if (elem == 0)
101410a898b3SArjun P       continue;
101510a898b3SArjun P     if (!unknownFromRow(row).restricted)
101610a898b3SArjun P       continue;
101710a898b3SArjun P     if (signMatchesDirection(elem, direction))
101810a898b3SArjun P       continue;
101910a898b3SArjun P     int64_t constTerm = tableau(row, 1);
102010a898b3SArjun P 
102110a898b3SArjun P     if (!retRow) {
102210a898b3SArjun P       retRow = row;
102310a898b3SArjun P       retElem = elem;
102410a898b3SArjun P       retConst = constTerm;
102510a898b3SArjun P       continue;
102610a898b3SArjun P     }
102710a898b3SArjun P 
102810a898b3SArjun P     int64_t diff = retConst * elem - constTerm * retElem;
102910a898b3SArjun P     if ((diff == 0 && rowUnknown[row] < rowUnknown[*retRow]) ||
103010a898b3SArjun P         (diff != 0 && !signMatchesDirection(diff, direction))) {
103110a898b3SArjun P       retRow = row;
103210a898b3SArjun P       retElem = elem;
103310a898b3SArjun P       retConst = constTerm;
103410a898b3SArjun P     }
103510a898b3SArjun P   }
103610a898b3SArjun P   return retRow;
103710a898b3SArjun P }
103810a898b3SArjun P 
isEmpty() const10394fa96b7eSArjun P bool SimplexBase::isEmpty() const { return empty; }
104010a898b3SArjun P 
swapRows(unsigned i,unsigned j)10414fa96b7eSArjun P void SimplexBase::swapRows(unsigned i, unsigned j) {
104210a898b3SArjun P   if (i == j)
104310a898b3SArjun P     return;
104410a898b3SArjun P   tableau.swapRows(i, j);
104510a898b3SArjun P   std::swap(rowUnknown[i], rowUnknown[j]);
104610a898b3SArjun P   unknownFromRow(i).pos = i;
104710a898b3SArjun P   unknownFromRow(j).pos = j;
104810a898b3SArjun P }
104910a898b3SArjun P 
swapColumns(unsigned i,unsigned j)10504fa96b7eSArjun P void SimplexBase::swapColumns(unsigned i, unsigned j) {
10518bc2cff9SArjun P   assert(i < getNumColumns() && j < getNumColumns() &&
10528bc2cff9SArjun P          "Invalid columns provided!");
10532b44a732SArjun P   if (i == j)
10542b44a732SArjun P     return;
10552b44a732SArjun P   tableau.swapColumns(i, j);
10562b44a732SArjun P   std::swap(colUnknown[i], colUnknown[j]);
10572b44a732SArjun P   unknownFromColumn(i).pos = i;
10582b44a732SArjun P   unknownFromColumn(j).pos = j;
10592b44a732SArjun P }
10602b44a732SArjun P 
106110a898b3SArjun P /// Mark this tableau empty and push an entry to the undo stack.
markEmpty()10624fa96b7eSArjun P void SimplexBase::markEmpty() {
1063ad34ce94SArjun P   // If the set is already empty, then we shouldn't add another UnmarkEmpty log
1064ad34ce94SArjun P   // entry, since in that case the Simplex will be erroneously marked as
1065ad34ce94SArjun P   // non-empty when rolling back past this point.
1066ad34ce94SArjun P   if (empty)
1067ad34ce94SArjun P     return;
106810a898b3SArjun P   undoLog.push_back(UndoLogEntry::UnmarkEmpty);
106910a898b3SArjun P   empty = true;
107010a898b3SArjun P }
107110a898b3SArjun P 
107210a898b3SArjun P /// Add an inequality to the tableau. If coeffs is c_0, c_1, ... c_n, where n
107341b09f4eSKazuaki Ishizaki /// is the current number of variables, then the corresponding inequality is
107410a898b3SArjun P /// c_n + c_0*x_0 + c_1*x_1 + ... + c_{n-1}*x_{n-1} >= 0.
107510a898b3SArjun P ///
107610a898b3SArjun P /// We add the inequality and mark it as restricted. We then try to make its
107710a898b3SArjun P /// sample value non-negative. If this is not possible, the tableau has become
107810a898b3SArjun P /// empty and we mark it as such.
addInequality(ArrayRef<int64_t> coeffs)10796db01958SArjun P void Simplex::addInequality(ArrayRef<int64_t> coeffs) {
10806db01958SArjun P   unsigned conIndex = addRow(coeffs, /*makeRestricted=*/true);
10816db01958SArjun P   LogicalResult result = restoreRow(con[conIndex]);
108210a898b3SArjun P   if (failed(result))
108310a898b3SArjun P     markEmpty();
108410a898b3SArjun P }
108510a898b3SArjun P 
108610a898b3SArjun P /// Add an equality to the tableau. If coeffs is c_0, c_1, ... c_n, where n
108741b09f4eSKazuaki Ishizaki /// is the current number of variables, then the corresponding equality is
108810a898b3SArjun P /// c_n + c_0*x_0 + c_1*x_1 + ... + c_{n-1}*x_{n-1} == 0.
108910a898b3SArjun P ///
109010a898b3SArjun P /// We simply add two opposing inequalities, which force the expression to
109110a898b3SArjun P /// be zero.
addEquality(ArrayRef<int64_t> coeffs)1092b97aa413SArjun P void SimplexBase::addEquality(ArrayRef<int64_t> coeffs) {
109310a898b3SArjun P   addInequality(coeffs);
109410a898b3SArjun P   SmallVector<int64_t, 8> negatedCoeffs;
109510a898b3SArjun P   for (int64_t coeff : coeffs)
109610a898b3SArjun P     negatedCoeffs.emplace_back(-coeff);
109710a898b3SArjun P   addInequality(negatedCoeffs);
109810a898b3SArjun P }
109910a898b3SArjun P 
getNumVariables() const11004fa96b7eSArjun P unsigned SimplexBase::getNumVariables() const { return var.size(); }
getNumConstraints() const11014fa96b7eSArjun P unsigned SimplexBase::getNumConstraints() const { return con.size(); }
110210a898b3SArjun P 
110341b09f4eSKazuaki Ishizaki /// Return a snapshot of the current state. This is just the current size of the
110410a898b3SArjun P /// undo log.
getSnapshot() const11054fa96b7eSArjun P unsigned SimplexBase::getSnapshot() const { return undoLog.size(); }
110610a898b3SArjun P 
getSnapshotBasis()11076db01958SArjun P unsigned SimplexBase::getSnapshotBasis() {
11086db01958SArjun P   SmallVector<int, 8> basis;
11096db01958SArjun P   for (int index : colUnknown) {
11106db01958SArjun P     if (index != nullIndex)
11116db01958SArjun P       basis.push_back(index);
11126db01958SArjun P   }
11136db01958SArjun P   savedBases.push_back(std::move(basis));
111410a898b3SArjun P 
11156db01958SArjun P   undoLog.emplace_back(UndoLogEntry::RestoreBasis);
11166db01958SArjun P   return undoLog.size() - 1;
111710a898b3SArjun P }
11186db01958SArjun P 
removeLastConstraintRowOrientation()11196db01958SArjun P void SimplexBase::removeLastConstraintRowOrientation() {
11206db01958SArjun P   assert(con.back().orientation == Orientation::Row);
112110a898b3SArjun P 
112210a898b3SArjun P   // Move this unknown to the last row and remove the last row from the
112310a898b3SArjun P   // tableau.
11248bc2cff9SArjun P   swapRows(con.back().pos, getNumRows() - 1);
112510a898b3SArjun P   // It is not strictly necessary to shrink the tableau, but for now we
11268bc2cff9SArjun P   // maintain the invariant that the tableau has exactly getNumRows()
11278bc2cff9SArjun P   // rows.
11288bc2cff9SArjun P   tableau.resizeVertically(getNumRows() - 1);
112910a898b3SArjun P   rowUnknown.pop_back();
113010a898b3SArjun P   con.pop_back();
11316db01958SArjun P }
11326db01958SArjun P 
11336db01958SArjun P // This doesn't find a pivot row only if the column has zero
11346db01958SArjun P // coefficients for every row.
11356db01958SArjun P //
11366db01958SArjun P // If the unknown is a constraint, this can't happen, since it was added
11376db01958SArjun P // initially as a row. Such a row could never have been pivoted to a column. So
11386db01958SArjun P // a pivot row will always be found if we have a constraint.
11396db01958SArjun P //
11406db01958SArjun P // If we have a variable, then the column has zero coefficients for every row
11416db01958SArjun P // iff no constraints have been added with a non-zero coefficient for this row.
findAnyPivotRow(unsigned col)11426db01958SArjun P Optional<unsigned> SimplexBase::findAnyPivotRow(unsigned col) {
11438bc2cff9SArjun P   for (unsigned row = nRedundant, e = getNumRows(); row < e; ++row)
11446db01958SArjun P     if (tableau(row, col) != 0)
11456db01958SArjun P       return row;
11466db01958SArjun P   return {};
11476db01958SArjun P }
11486db01958SArjun P 
11496db01958SArjun P // It's not valid to remove the constraint by deleting the column since this
11506db01958SArjun P // would result in an invalid basis.
undoLastConstraint()11516db01958SArjun P void Simplex::undoLastConstraint() {
11526db01958SArjun P   if (con.back().orientation == Orientation::Column) {
11536db01958SArjun P     // We try to find any pivot row for this column that preserves tableau
11546db01958SArjun P     // consistency (except possibly the column itself, which is going to be
11556db01958SArjun P     // deallocated anyway).
11566db01958SArjun P     //
11576db01958SArjun P     // If no pivot row is found in either direction, then the unknown is
11586db01958SArjun P     // unbounded in both directions and we are free to perform any pivot at
11596db01958SArjun P     // all. To do this, we just need to find any row with a non-zero
11606db01958SArjun P     // coefficient for the column. findAnyPivotRow will always be able to
11616db01958SArjun P     // find such a row for a constraint.
11626db01958SArjun P     unsigned column = con.back().pos;
11636db01958SArjun P     if (Optional<unsigned> maybeRow = findPivotRow({}, Direction::Up, column)) {
11646db01958SArjun P       pivot(*maybeRow, column);
11656db01958SArjun P     } else if (Optional<unsigned> maybeRow =
11666db01958SArjun P                    findPivotRow({}, Direction::Down, column)) {
11676db01958SArjun P       pivot(*maybeRow, column);
11686db01958SArjun P     } else {
11696db01958SArjun P       Optional<unsigned> row = findAnyPivotRow(column);
11705413bf1bSKazu Hirata       assert(row && "Pivot should always exist for a constraint!");
11716db01958SArjun P       pivot(*row, column);
11726db01958SArjun P     }
11736db01958SArjun P   }
11746db01958SArjun P   removeLastConstraintRowOrientation();
11756db01958SArjun P }
11766db01958SArjun P 
11776db01958SArjun P // It's not valid to remove the constraint by deleting the column since this
11786db01958SArjun P // would result in an invalid basis.
undoLastConstraint()1179acb378e2SArjun P void LexSimplexBase::undoLastConstraint() {
11806db01958SArjun P   if (con.back().orientation == Orientation::Column) {
11816db01958SArjun P     // When removing the last constraint during a rollback, we just need to find
11826db01958SArjun P     // any pivot at all, i.e., any row with non-zero coefficient for the
11836db01958SArjun P     // column, because when rolling back a lexicographic simplex, we always
11846db01958SArjun P     // end by restoring the exact basis that was present at the time of the
11856db01958SArjun P     // snapshot, so what pivots we perform while undoing doesn't matter as
11866db01958SArjun P     // long as we get the unknown to row orientation and remove it.
11876db01958SArjun P     unsigned column = con.back().pos;
11886db01958SArjun P     Optional<unsigned> row = findAnyPivotRow(column);
11895413bf1bSKazu Hirata     assert(row && "Pivot should always exist for a constraint!");
11906db01958SArjun P     pivot(*row, column);
11916db01958SArjun P   }
11926db01958SArjun P   removeLastConstraintRowOrientation();
11936db01958SArjun P }
11946db01958SArjun P 
undo(UndoLogEntry entry)11956db01958SArjun P void SimplexBase::undo(UndoLogEntry entry) {
11966db01958SArjun P   if (entry == UndoLogEntry::RemoveLastConstraint) {
11976db01958SArjun P     // Simplex and LexSimplex handle this differently, so we call out to a
11986db01958SArjun P     // virtual function to handle this.
11996db01958SArjun P     undoLastConstraint();
12002b44a732SArjun P   } else if (entry == UndoLogEntry::RemoveLastVariable) {
12012b44a732SArjun P     // Whenever we are rolling back the addition of a variable, it is guaranteed
12022b44a732SArjun P     // that the variable will be in column position.
12032b44a732SArjun P     //
12042b44a732SArjun P     // We can see this as follows: any constraint that depends on this variable
12052b44a732SArjun P     // was added after this variable was added, so the addition of such
12062b44a732SArjun P     // constraints should already have been rolled back by the time we get to
12072b44a732SArjun P     // rolling back the addition of the variable. Therefore, no constraint
12082b44a732SArjun P     // currently has a component along the variable, so the variable itself must
12092b44a732SArjun P     // be part of the basis.
12102b44a732SArjun P     assert(var.back().orientation == Orientation::Column &&
12112b44a732SArjun P            "Variable to be removed must be in column orientation!");
12122b44a732SArjun P 
121379ad5fb2SArjun P     if (var.back().isSymbol)
121479ad5fb2SArjun P       nSymbol--;
121579ad5fb2SArjun P 
12162b44a732SArjun P     // Move this variable to the last column and remove the column from the
12172b44a732SArjun P     // tableau.
12188bc2cff9SArjun P     swapColumns(var.back().pos, getNumColumns() - 1);
12198bc2cff9SArjun P     tableau.resizeHorizontally(getNumColumns() - 1);
12202b44a732SArjun P     var.pop_back();
12212b44a732SArjun P     colUnknown.pop_back();
122210a898b3SArjun P   } else if (entry == UndoLogEntry::UnmarkEmpty) {
122310a898b3SArjun P     empty = false;
122433f57467SArjun P   } else if (entry == UndoLogEntry::UnmarkLastRedundant) {
122533f57467SArjun P     nRedundant--;
12266db01958SArjun P   } else if (entry == UndoLogEntry::RestoreBasis) {
12276db01958SArjun P     assert(!savedBases.empty() && "No bases saved!");
12286db01958SArjun P 
12296db01958SArjun P     SmallVector<int, 8> basis = std::move(savedBases.back());
12306db01958SArjun P     savedBases.pop_back();
12316db01958SArjun P 
12326db01958SArjun P     for (int index : basis) {
12336db01958SArjun P       Unknown &u = unknownFromIndex(index);
12346db01958SArjun P       if (u.orientation == Orientation::Column)
12356db01958SArjun P         continue;
12368bc2cff9SArjun P       for (unsigned col = getNumFixedCols(), e = getNumColumns(); col < e;
12378bc2cff9SArjun P            col++) {
12386db01958SArjun P         assert(colUnknown[col] != nullIndex &&
12396db01958SArjun P                "Column should not be a fixed column!");
12406db01958SArjun P         if (std::find(basis.begin(), basis.end(), colUnknown[col]) !=
12416db01958SArjun P             basis.end())
12426db01958SArjun P           continue;
12436db01958SArjun P         if (tableau(u.pos, col) == 0)
12446db01958SArjun P           continue;
12456db01958SArjun P         pivot(u.pos, col);
12466db01958SArjun P         break;
12476db01958SArjun P       }
12486db01958SArjun P 
12496db01958SArjun P       assert(u.orientation == Orientation::Column && "No pivot found!");
12506db01958SArjun P     }
125110a898b3SArjun P   }
125210a898b3SArjun P }
125310a898b3SArjun P 
125410a898b3SArjun P /// Rollback to the specified snapshot.
125510a898b3SArjun P ///
125610a898b3SArjun P /// We undo all the log entries until the log size when the snapshot was taken
125710a898b3SArjun P /// is reached.
rollback(unsigned snapshot)12584fa96b7eSArjun P void SimplexBase::rollback(unsigned snapshot) {
125910a898b3SArjun P   while (undoLog.size() > snapshot) {
126010a898b3SArjun P     undo(undoLog.back());
126110a898b3SArjun P     undoLog.pop_back();
126210a898b3SArjun P   }
126310a898b3SArjun P }
126410a898b3SArjun P 
1265ff447604SArjun P /// We add the usual floor division constraints:
1266ff447604SArjun P /// `0 <= coeffs - denom*q <= denom - 1`, where `q` is the new division
1267ff447604SArjun P /// variable.
1268ff447604SArjun P ///
1269ff447604SArjun P /// This constrains the remainder `coeffs - denom*q` to be in the
1270ff447604SArjun P /// range `[0, denom - 1]`, which fixes the integer value of the quotient `q`.
addDivisionVariable(ArrayRef<int64_t> coeffs,int64_t denom)1271ff447604SArjun P void SimplexBase::addDivisionVariable(ArrayRef<int64_t> coeffs, int64_t denom) {
1272ff447604SArjun P   assert(denom != 0 && "Cannot divide by zero!\n");
1273ff447604SArjun P   appendVariable();
1274ff447604SArjun P 
1275ff447604SArjun P   SmallVector<int64_t, 8> ineq(coeffs.begin(), coeffs.end());
1276ff447604SArjun P   int64_t constTerm = ineq.back();
1277ff447604SArjun P   ineq.back() = -denom;
1278ff447604SArjun P   ineq.push_back(constTerm);
1279ff447604SArjun P   addInequality(ineq);
1280ff447604SArjun P 
1281ff447604SArjun P   for (int64_t &coeff : ineq)
1282ff447604SArjun P     coeff = -coeff;
1283ff447604SArjun P   ineq.back() += denom - 1;
1284ff447604SArjun P   addInequality(ineq);
1285ff447604SArjun P }
1286ff447604SArjun P 
appendVariable(unsigned count)12874fa96b7eSArjun P void SimplexBase::appendVariable(unsigned count) {
128876cb8765SArjun P   if (count == 0)
128976cb8765SArjun P     return;
12902b44a732SArjun P   var.reserve(var.size() + count);
12912b44a732SArjun P   colUnknown.reserve(colUnknown.size() + count);
12922b44a732SArjun P   for (unsigned i = 0; i < count; ++i) {
12932b44a732SArjun P     var.emplace_back(Orientation::Column, /*restricted=*/false,
12948bc2cff9SArjun P                      /*pos=*/getNumColumns() + i);
12952b44a732SArjun P     colUnknown.push_back(var.size() - 1);
12962b44a732SArjun P   }
12978bc2cff9SArjun P   tableau.resizeHorizontally(getNumColumns() + count);
12982b44a732SArjun P   undoLog.insert(undoLog.end(), count, UndoLogEntry::RemoveLastVariable);
12992b44a732SArjun P }
13002b44a732SArjun P 
1301bb901355SGroverkss /// Add all the constraints from the given IntegerRelation.
intersectIntegerRelation(const IntegerRelation & rel)1302bb901355SGroverkss void SimplexBase::intersectIntegerRelation(const IntegerRelation &rel) {
1303d95140a5SGroverkss   assert(rel.getNumVars() == getNumVariables() &&
1304bb901355SGroverkss          "IntegerRelation must have same dimensionality as simplex");
1305bb901355SGroverkss   for (unsigned i = 0, e = rel.getNumInequalities(); i < e; ++i)
1306bb901355SGroverkss     addInequality(rel.getInequality(i));
1307bb901355SGroverkss   for (unsigned i = 0, e = rel.getNumEqualities(); i < e; ++i)
1308bb901355SGroverkss     addEquality(rel.getEquality(i));
130963dead20SArjun P }
131063dead20SArjun P 
computeRowOptimum(Direction direction,unsigned row)13118e799588SArjun P MaybeOptimum<Fraction> Simplex::computeRowOptimum(Direction direction,
131210a898b3SArjun P                                                   unsigned row) {
131310a898b3SArjun P   // Keep trying to find a pivot for the row in the specified direction.
131410a898b3SArjun P   while (Optional<Pivot> maybePivot = findPivot(row, direction)) {
131510a898b3SArjun P     // If findPivot returns a pivot involving the row itself, then the optimum
131610a898b3SArjun P     // is unbounded, so we return None.
131710a898b3SArjun P     if (maybePivot->row == row)
13188e799588SArjun P       return OptimumKind::Unbounded;
131910a898b3SArjun P     pivot(*maybePivot);
132010a898b3SArjun P   }
132110a898b3SArjun P 
132210a898b3SArjun P   // The row has reached its optimal sample value, which we return.
132310a898b3SArjun P   // The sample value is the entry in the constant column divided by the common
132410a898b3SArjun P   // denominator for this row.
132510a898b3SArjun P   return Fraction(tableau(row, 1), tableau(row, 0));
132610a898b3SArjun P }
132710a898b3SArjun P 
132810a898b3SArjun P /// Compute the optimum of the specified expression in the specified direction,
132910a898b3SArjun P /// or None if it is unbounded.
computeOptimum(Direction direction,ArrayRef<int64_t> coeffs)13308e799588SArjun P MaybeOptimum<Fraction> Simplex::computeOptimum(Direction direction,
133110a898b3SArjun P                                                ArrayRef<int64_t> coeffs) {
13328e799588SArjun P   if (empty)
13338e799588SArjun P     return OptimumKind::Empty;
133408543a5aSArjun P 
133508543a5aSArjun P   SimplexRollbackScopeExit scopeExit(*this);
133610a898b3SArjun P   unsigned conIndex = addRow(coeffs);
133710a898b3SArjun P   unsigned row = con[conIndex].pos;
133818a06d4fSArjun P   return computeRowOptimum(direction, row);
133910a898b3SArjun P }
134010a898b3SArjun P 
computeOptimum(Direction direction,Unknown & u)13418e799588SArjun P MaybeOptimum<Fraction> Simplex::computeOptimum(Direction direction,
13428e799588SArjun P                                                Unknown &u) {
13438e799588SArjun P   if (empty)
13448e799588SArjun P     return OptimumKind::Empty;
13456ebeba88SArjun P   if (u.orientation == Orientation::Column) {
13466ebeba88SArjun P     unsigned column = u.pos;
13476ebeba88SArjun P     Optional<unsigned> pivotRow = findPivotRow({}, direction, column);
13486ebeba88SArjun P     // If no pivot is returned, the constraint is unbounded in the specified
13496ebeba88SArjun P     // direction.
13506ebeba88SArjun P     if (!pivotRow)
13518e799588SArjun P       return OptimumKind::Unbounded;
13526ebeba88SArjun P     pivot(*pivotRow, column);
13536ebeba88SArjun P   }
13546ebeba88SArjun P 
13556ebeba88SArjun P   unsigned row = u.pos;
13568e799588SArjun P   MaybeOptimum<Fraction> optimum = computeRowOptimum(direction, row);
13576ebeba88SArjun P   if (u.restricted && direction == Direction::Down &&
13588e799588SArjun P       (optimum.isUnbounded() || *optimum < Fraction(0, 1))) {
135915c8b8adSArjun P     if (failed(restoreRow(u)))
136015c8b8adSArjun P       llvm_unreachable("Could not restore row!");
136115c8b8adSArjun P   }
13626ebeba88SArjun P   return optimum;
13636ebeba88SArjun P }
13646ebeba88SArjun P 
isBoundedAlongConstraint(unsigned constraintIndex)13656ebeba88SArjun P bool Simplex::isBoundedAlongConstraint(unsigned constraintIndex) {
13666ebeba88SArjun P   assert(!empty && "It is not meaningful to ask whether a direction is bounded "
13676ebeba88SArjun P                    "in an empty set.");
13686ebeba88SArjun P   // The constraint's perpendicular is already bounded below, since it is a
13696ebeba88SArjun P   // constraint. If it is also bounded above, we can return true.
13708e799588SArjun P   return computeOptimum(Direction::Up, con[constraintIndex]).isBounded();
13716ebeba88SArjun P }
13726ebeba88SArjun P 
137333f57467SArjun P /// Redundant constraints are those that are in row orientation and lie in
137433f57467SArjun P /// rows 0 to nRedundant - 1.
isMarkedRedundant(unsigned constraintIndex) const137533f57467SArjun P bool Simplex::isMarkedRedundant(unsigned constraintIndex) const {
137633f57467SArjun P   const Unknown &u = con[constraintIndex];
137733f57467SArjun P   return u.orientation == Orientation::Row && u.pos < nRedundant;
137833f57467SArjun P }
137933f57467SArjun P 
138033f57467SArjun P /// Mark the specified row redundant.
138133f57467SArjun P ///
138233f57467SArjun P /// This is done by moving the unknown to the end of the block of redundant
138333f57467SArjun P /// rows (namely, to row nRedundant) and incrementing nRedundant to
138433f57467SArjun P /// accomodate the new redundant row.
markRowRedundant(Unknown & u)138533f57467SArjun P void Simplex::markRowRedundant(Unknown &u) {
138633f57467SArjun P   assert(u.orientation == Orientation::Row &&
138733f57467SArjun P          "Unknown should be in row position!");
13883b7b4a80SArjun P   assert(u.pos >= nRedundant && "Unknown is already marked redundant!");
138933f57467SArjun P   swapRows(u.pos, nRedundant);
139033f57467SArjun P   ++nRedundant;
139133f57467SArjun P   undoLog.emplace_back(UndoLogEntry::UnmarkLastRedundant);
139233f57467SArjun P }
139333f57467SArjun P 
139433f57467SArjun P /// Find a subset of constraints that is redundant and mark them redundant.
detectRedundant(unsigned offset,unsigned count)13954bf9cbc4SArjun P void Simplex::detectRedundant(unsigned offset, unsigned count) {
13964bf9cbc4SArjun P   assert(offset + count <= con.size() && "invalid range!");
139733f57467SArjun P   // It is not meaningful to talk about redundancy for empty sets.
139833f57467SArjun P   if (empty)
139933f57467SArjun P     return;
140033f57467SArjun P 
140133f57467SArjun P   // Iterate through the constraints and check for each one if it can attain
140233f57467SArjun P   // negative sample values. If it can, it's not redundant. Otherwise, it is.
140333f57467SArjun P   // We mark redundant constraints redundant.
140433f57467SArjun P   //
140533f57467SArjun P   // Constraints that get marked redundant in one iteration are not respected
140633f57467SArjun P   // when checking constraints in later iterations. This prevents, for example,
140733f57467SArjun P   // two identical constraints both being marked redundant since each is
140833f57467SArjun P   // redundant given the other one. In this example, only the first of the
140933f57467SArjun P   // constraints that is processed will get marked redundant, as it should be.
14104bf9cbc4SArjun P   for (unsigned i = 0; i < count; ++i) {
14114bf9cbc4SArjun P     Unknown &u = con[offset + i];
141233f57467SArjun P     if (u.orientation == Orientation::Column) {
141333f57467SArjun P       unsigned column = u.pos;
141433f57467SArjun P       Optional<unsigned> pivotRow = findPivotRow({}, Direction::Down, column);
141533f57467SArjun P       // If no downward pivot is returned, the constraint is unbounded below
141633f57467SArjun P       // and hence not redundant.
141733f57467SArjun P       if (!pivotRow)
141833f57467SArjun P         continue;
141933f57467SArjun P       pivot(*pivotRow, column);
142033f57467SArjun P     }
142133f57467SArjun P 
142233f57467SArjun P     unsigned row = u.pos;
14238e799588SArjun P     MaybeOptimum<Fraction> minimum = computeRowOptimum(Direction::Down, row);
14248e799588SArjun P     if (minimum.isUnbounded() || *minimum < Fraction(0, 1)) {
142533f57467SArjun P       // Constraint is unbounded below or can attain negative sample values and
142633f57467SArjun P       // hence is not redundant.
142715c8b8adSArjun P       if (failed(restoreRow(u)))
142815c8b8adSArjun P         llvm_unreachable("Could not restore non-redundant row!");
142933f57467SArjun P       continue;
143033f57467SArjun P     }
143133f57467SArjun P 
143233f57467SArjun P     markRowRedundant(u);
143333f57467SArjun P   }
143433f57467SArjun P }
143533f57467SArjun P 
isUnbounded()143610a898b3SArjun P bool Simplex::isUnbounded() {
143710a898b3SArjun P   if (empty)
143810a898b3SArjun P     return false;
143910a898b3SArjun P 
144010a898b3SArjun P   SmallVector<int64_t, 8> dir(var.size() + 1);
144110a898b3SArjun P   for (unsigned i = 0; i < var.size(); ++i) {
144210a898b3SArjun P     dir[i] = 1;
144310a898b3SArjun P 
14448e799588SArjun P     if (computeOptimum(Direction::Up, dir).isUnbounded())
144510a898b3SArjun P       return true;
144610a898b3SArjun P 
14478e799588SArjun P     if (computeOptimum(Direction::Down, dir).isUnbounded())
144810a898b3SArjun P       return true;
144910a898b3SArjun P 
145010a898b3SArjun P     dir[i] = 0;
145110a898b3SArjun P   }
145210a898b3SArjun P   return false;
145310a898b3SArjun P }
145410a898b3SArjun P 
145510a898b3SArjun P /// Make a tableau to represent a pair of points in the original tableau.
145610a898b3SArjun P ///
145710a898b3SArjun P /// The product constraints and variables are stored as: first A's, then B's.
145810a898b3SArjun P ///
145910a898b3SArjun P /// The product tableau has row layout:
146033f57467SArjun P ///   A's redundant rows, B's redundant rows, A's other rows, B's other rows.
146110a898b3SArjun P ///
146210a898b3SArjun P /// It has column layout:
146310a898b3SArjun P ///   denominator, constant, A's columns, B's columns.
makeProduct(const Simplex & a,const Simplex & b)146410a898b3SArjun P Simplex Simplex::makeProduct(const Simplex &a, const Simplex &b) {
146533afea54SArjun P   unsigned numVar = a.getNumVariables() + b.getNumVariables();
146633afea54SArjun P   unsigned numCon = a.getNumConstraints() + b.getNumConstraints();
146710a898b3SArjun P   Simplex result(numVar);
146810a898b3SArjun P 
14698bc2cff9SArjun P   result.tableau.reserveRows(numCon);
147010a898b3SArjun P   result.empty = a.empty || b.empty;
147110a898b3SArjun P 
147210a898b3SArjun P   auto concat = [](ArrayRef<Unknown> v, ArrayRef<Unknown> w) {
147310a898b3SArjun P     SmallVector<Unknown, 8> result;
147410a898b3SArjun P     result.reserve(v.size() + w.size());
147510a898b3SArjun P     result.insert(result.end(), v.begin(), v.end());
147610a898b3SArjun P     result.insert(result.end(), w.begin(), w.end());
147710a898b3SArjun P     return result;
147810a898b3SArjun P   };
147910a898b3SArjun P   result.con = concat(a.con, b.con);
148010a898b3SArjun P   result.var = concat(a.var, b.var);
148110a898b3SArjun P 
148210a898b3SArjun P   auto indexFromBIndex = [&](int index) {
148333afea54SArjun P     return index >= 0 ? a.getNumVariables() + index
148433afea54SArjun P                       : ~(a.getNumConstraints() + ~index);
148510a898b3SArjun P   };
148610a898b3SArjun P 
148710a898b3SArjun P   result.colUnknown.assign(2, nullIndex);
14888bc2cff9SArjun P   for (unsigned i = 2, e = a.getNumColumns(); i < e; ++i) {
148910a898b3SArjun P     result.colUnknown.push_back(a.colUnknown[i]);
149010a898b3SArjun P     result.unknownFromIndex(result.colUnknown.back()).pos =
149110a898b3SArjun P         result.colUnknown.size() - 1;
149210a898b3SArjun P   }
14938bc2cff9SArjun P   for (unsigned i = 2, e = b.getNumColumns(); i < e; ++i) {
149410a898b3SArjun P     result.colUnknown.push_back(indexFromBIndex(b.colUnknown[i]));
149510a898b3SArjun P     result.unknownFromIndex(result.colUnknown.back()).pos =
149610a898b3SArjun P         result.colUnknown.size() - 1;
149710a898b3SArjun P   }
149810a898b3SArjun P 
149910a898b3SArjun P   auto appendRowFromA = [&](unsigned row) {
15008bc2cff9SArjun P     unsigned resultRow = result.tableau.appendExtraRow();
15018bc2cff9SArjun P     for (unsigned col = 0, e = a.getNumColumns(); col < e; ++col)
15028bc2cff9SArjun P       result.tableau(resultRow, col) = a.tableau(row, col);
150310a898b3SArjun P     result.rowUnknown.push_back(a.rowUnknown[row]);
150410a898b3SArjun P     result.unknownFromIndex(result.rowUnknown.back()).pos =
150510a898b3SArjun P         result.rowUnknown.size() - 1;
150610a898b3SArjun P   };
150710a898b3SArjun P 
150810a898b3SArjun P   // Also fixes the corresponding entry in rowUnknown and var/con (as the case
150910a898b3SArjun P   // may be).
151010a898b3SArjun P   auto appendRowFromB = [&](unsigned row) {
15118bc2cff9SArjun P     unsigned resultRow = result.tableau.appendExtraRow();
15128bc2cff9SArjun P     result.tableau(resultRow, 0) = b.tableau(row, 0);
15138bc2cff9SArjun P     result.tableau(resultRow, 1) = b.tableau(row, 1);
151410a898b3SArjun P 
15158bc2cff9SArjun P     unsigned offset = a.getNumColumns() - 2;
15168bc2cff9SArjun P     for (unsigned col = 2, e = b.getNumColumns(); col < e; ++col)
15178bc2cff9SArjun P       result.tableau(resultRow, offset + col) = b.tableau(row, col);
151810a898b3SArjun P     result.rowUnknown.push_back(indexFromBIndex(b.rowUnknown[row]));
151910a898b3SArjun P     result.unknownFromIndex(result.rowUnknown.back()).pos =
152010a898b3SArjun P         result.rowUnknown.size() - 1;
152110a898b3SArjun P   };
152210a898b3SArjun P 
152333f57467SArjun P   result.nRedundant = a.nRedundant + b.nRedundant;
152433f57467SArjun P   for (unsigned row = 0; row < a.nRedundant; ++row)
152510a898b3SArjun P     appendRowFromA(row);
152633f57467SArjun P   for (unsigned row = 0; row < b.nRedundant; ++row)
152733f57467SArjun P     appendRowFromB(row);
15288bc2cff9SArjun P   for (unsigned row = a.nRedundant, e = a.getNumRows(); row < e; ++row)
152933f57467SArjun P     appendRowFromA(row);
15308bc2cff9SArjun P   for (unsigned row = b.nRedundant, e = b.getNumRows(); row < e; ++row)
153110a898b3SArjun P     appendRowFromB(row);
153210a898b3SArjun P 
153310a898b3SArjun P   return result;
153410a898b3SArjun P }
153510a898b3SArjun P 
getRationalSample() const15368e799588SArjun P Optional<SmallVector<Fraction, 8>> Simplex::getRationalSample() const {
153779be1fe0SArjun P   if (empty)
153879be1fe0SArjun P     return {};
153910a898b3SArjun P 
154014056dfbSArjun P   SmallVector<Fraction, 8> sample;
154114056dfbSArjun P   sample.reserve(var.size());
154210a898b3SArjun P   // Push the sample value for each variable into the vector.
154310a898b3SArjun P   for (const Unknown &u : var) {
154410a898b3SArjun P     if (u.orientation == Orientation::Column) {
154510a898b3SArjun P       // If the variable is in column position, its sample value is zero.
154614056dfbSArjun P       sample.emplace_back(0, 1);
154710a898b3SArjun P     } else {
15488e799588SArjun P       // If the variable is in row position, its sample value is the
15496db01958SArjun P       // entry in the constant column divided by the denominator.
15508e799588SArjun P       int64_t denom = tableau(u.pos, 0);
15516db01958SArjun P       sample.emplace_back(tableau(u.pos, 1), denom);
155210a898b3SArjun P     }
155310a898b3SArjun P   }
155410a898b3SArjun P   return sample;
155510a898b3SArjun P }
155610a898b3SArjun P 
addInequality(ArrayRef<int64_t> coeffs)1557acb378e2SArjun P void LexSimplexBase::addInequality(ArrayRef<int64_t> coeffs) {
1558acb378e2SArjun P   addRow(coeffs, /*makeRestricted=*/true);
1559acb378e2SArjun P }
1560acb378e2SArjun P 
getRationalSample() const15618e799588SArjun P MaybeOptimum<SmallVector<Fraction, 8>> LexSimplex::getRationalSample() const {
15628e799588SArjun P   if (empty)
15638e799588SArjun P     return OptimumKind::Empty;
15648e799588SArjun P 
15658e799588SArjun P   SmallVector<Fraction, 8> sample;
15668e799588SArjun P   sample.reserve(var.size());
15678e799588SArjun P   // Push the sample value for each variable into the vector.
15688e799588SArjun P   for (const Unknown &u : var) {
15698e799588SArjun P     // When the big M parameter is being used, each variable x is represented
15708e799588SArjun P     // as M + x, so its sample value is finite if and only if it is of the
15718e799588SArjun P     // form 1*M + c. If the coefficient of M is not one then the sample value
15728e799588SArjun P     // is infinite, and we return an empty optional.
15738e799588SArjun P 
15748e799588SArjun P     if (u.orientation == Orientation::Column) {
15758e799588SArjun P       // If the variable is in column position, the sample value of M + x is
15768e799588SArjun P       // zero, so x = -M which is unbounded.
15778e799588SArjun P       return OptimumKind::Unbounded;
15788e799588SArjun P     }
15798e799588SArjun P 
15808e799588SArjun P     // If the variable is in row position, its sample value is the
15818e799588SArjun P     // entry in the constant column divided by the denominator.
15828e799588SArjun P     int64_t denom = tableau(u.pos, 0);
15838e799588SArjun P     if (usingBigM)
15848e799588SArjun P       if (tableau(u.pos, 2) != denom)
15858e799588SArjun P         return OptimumKind::Unbounded;
15868e799588SArjun P     sample.emplace_back(tableau(u.pos, 1), denom);
15878e799588SArjun P   }
15888e799588SArjun P   return sample;
15898e799588SArjun P }
15908e799588SArjun P 
getSamplePointIfIntegral() const15916db01958SArjun P Optional<SmallVector<int64_t, 8>> Simplex::getSamplePointIfIntegral() const {
159214056dfbSArjun P   // If the tableau is empty, no sample point exists.
159314056dfbSArjun P   if (empty)
159414056dfbSArjun P     return {};
159579be1fe0SArjun P 
159679be1fe0SArjun P   // The value will always exist since the Simplex is non-empty.
159779be1fe0SArjun P   SmallVector<Fraction, 8> rationalSample = *getRationalSample();
159814056dfbSArjun P   SmallVector<int64_t, 8> integerSample;
159914056dfbSArjun P   integerSample.reserve(var.size());
160014056dfbSArjun P   for (const Fraction &coord : rationalSample) {
160114056dfbSArjun P     // If the sample is non-integral, return None.
160214056dfbSArjun P     if (coord.num % coord.den != 0)
160314056dfbSArjun P       return {};
160414056dfbSArjun P     integerSample.push_back(coord.num / coord.den);
160514056dfbSArjun P   }
160614056dfbSArjun P   return integerSample;
160714056dfbSArjun P }
160814056dfbSArjun P 
160910a898b3SArjun P /// Given a simplex for a polytope, construct a new simplex whose variables are
161010a898b3SArjun P /// identified with a pair of points (x, y) in the original polytope. Supports
161110a898b3SArjun P /// some operations needed for generalized basis reduction. In what follows,
161210a898b3SArjun P /// dotProduct(x, y) = x_1 * y_1 + x_2 * y_2 + ... x_n * y_n where n is the
161310a898b3SArjun P /// dimension of the original polytope.
161410a898b3SArjun P ///
161510a898b3SArjun P /// This supports adding equality constraints dotProduct(dir, x - y) == 0. It
161610a898b3SArjun P /// also supports rolling back this addition, by maintaining a snapshot stack
161710a898b3SArjun P /// that contains a snapshot of the Simplex's state for each equality, just
161810a898b3SArjun P /// before that equality was added.
16190c1f6865SGroverkss class presburger::GBRSimplex {
162010a898b3SArjun P   using Orientation = Simplex::Orientation;
162110a898b3SArjun P 
162210a898b3SArjun P public:
GBRSimplex(const Simplex & originalSimplex)162310a898b3SArjun P   GBRSimplex(const Simplex &originalSimplex)
162410a898b3SArjun P       : simplex(Simplex::makeProduct(originalSimplex, originalSimplex)),
162533afea54SArjun P         simplexConstraintOffset(simplex.getNumConstraints()) {}
162610a898b3SArjun P 
162710a898b3SArjun P   /// Add an equality dotProduct(dir, x - y) == 0.
162810a898b3SArjun P   /// First pushes a snapshot for the current simplex state to the stack so
162910a898b3SArjun P   /// that this can be rolled back later.
addEqualityForDirection(ArrayRef<int64_t> dir)163010a898b3SArjun P   void addEqualityForDirection(ArrayRef<int64_t> dir) {
1631ef6f7c4aSArjun P     assert(llvm::any_of(dir, [](int64_t x) { return x != 0; }) &&
163210a898b3SArjun P            "Direction passed is the zero vector!");
163310a898b3SArjun P     snapshotStack.push_back(simplex.getSnapshot());
163410a898b3SArjun P     simplex.addEquality(getCoeffsForDirection(dir));
163510a898b3SArjun P   }
1636d6f9bb03SArjun P   /// Compute max(dotProduct(dir, x - y)).
computeWidth(ArrayRef<int64_t> dir)1637d6f9bb03SArjun P   Fraction computeWidth(ArrayRef<int64_t> dir) {
16388e799588SArjun P     MaybeOptimum<Fraction> maybeWidth =
1639d6f9bb03SArjun P         simplex.computeOptimum(Direction::Up, getCoeffsForDirection(dir));
16408e799588SArjun P     assert(maybeWidth.isBounded() && "Width should be bounded!");
1641d6f9bb03SArjun P     return *maybeWidth;
1642d6f9bb03SArjun P   }
164310a898b3SArjun P 
164410a898b3SArjun P   /// Compute max(dotProduct(dir, x - y)) and save the dual variables for only
164510a898b3SArjun P   /// the direction equalities to `dual`.
computeWidthAndDuals(ArrayRef<int64_t> dir,SmallVectorImpl<int64_t> & dual,int64_t & dualDenom)164610a898b3SArjun P   Fraction computeWidthAndDuals(ArrayRef<int64_t> dir,
164710a898b3SArjun P                                 SmallVectorImpl<int64_t> &dual,
164810a898b3SArjun P                                 int64_t &dualDenom) {
1649d6f9bb03SArjun P     // We can't just call into computeWidth or computeOptimum since we need to
1650d6f9bb03SArjun P     // access the state of the tableau after computing the optimum, and these
1651d6f9bb03SArjun P     // functions rollback the insertion of the objective function into the
1652d6f9bb03SArjun P     // tableau before returning. We instead add a row for the objective function
1653d6f9bb03SArjun P     // ourselves, call into computeOptimum, compute the duals from the tableau
1654d6f9bb03SArjun P     // state, and finally rollback the addition of the row before returning.
165508543a5aSArjun P     SimplexRollbackScopeExit scopeExit(simplex);
165610a898b3SArjun P     unsigned conIndex = simplex.addRow(getCoeffsForDirection(dir));
165710a898b3SArjun P     unsigned row = simplex.con[conIndex].pos;
16588e799588SArjun P     MaybeOptimum<Fraction> maybeWidth =
165910a898b3SArjun P         simplex.computeRowOptimum(Simplex::Direction::Up, row);
16608e799588SArjun P     assert(maybeWidth.isBounded() && "Width should be bounded!");
166110a898b3SArjun P     dualDenom = simplex.tableau(row, 0);
166210a898b3SArjun P     dual.clear();
1663d6f9bb03SArjun P 
166410a898b3SArjun P     // The increment is i += 2 because equalities are added as two inequalities,
166510a898b3SArjun P     // one positive and one negative. Each iteration processes one equality.
166610a898b3SArjun P     for (unsigned i = simplexConstraintOffset; i < conIndex; i += 2) {
1667d6f9bb03SArjun P       // The dual variable for an inequality in column orientation is the
1668d6f9bb03SArjun P       // negative of its coefficient at the objective row. If the inequality is
1669d6f9bb03SArjun P       // in row orientation, the corresponding dual variable is zero.
167010a898b3SArjun P       //
1671d6f9bb03SArjun P       // We want the dual for the original equality, which corresponds to two
1672d6f9bb03SArjun P       // inequalities: a positive inequality, which has the same coefficients as
1673d6f9bb03SArjun P       // the equality, and a negative equality, which has negated coefficients.
167410a898b3SArjun P       //
1675d6f9bb03SArjun P       // Note that at most one of these inequalities can be in column
1676d6f9bb03SArjun P       // orientation because the column unknowns should form a basis and hence
1677d6f9bb03SArjun P       // must be linearly independent. If the positive inequality is in column
1678d6f9bb03SArjun P       // position, its dual is the dual corresponding to the equality. If the
1679d6f9bb03SArjun P       // negative inequality is in column position, the negation of its dual is
1680d6f9bb03SArjun P       // the dual corresponding to the equality. If neither is in column
1681d6f9bb03SArjun P       // position, then that means that this equality is redundant, and its dual
1682d6f9bb03SArjun P       // is zero.
168310a898b3SArjun P       //
1684d6f9bb03SArjun P       // Note that it is NOT valid to perform pivots during the computation of
1685d6f9bb03SArjun P       // the duals. This entire dual computation must be performed on the same
1686d6f9bb03SArjun P       // tableau configuration.
1687d6f9bb03SArjun P       assert(!(simplex.con[i].orientation == Orientation::Column &&
1688d6f9bb03SArjun P                simplex.con[i + 1].orientation == Orientation::Column) &&
1689d6f9bb03SArjun P              "Both inequalities for the equality cannot be in column "
1690d6f9bb03SArjun P              "orientation!");
1691d6f9bb03SArjun P       if (simplex.con[i].orientation == Orientation::Column)
169210a898b3SArjun P         dual.push_back(-simplex.tableau(row, simplex.con[i].pos));
1693d6f9bb03SArjun P       else if (simplex.con[i + 1].orientation == Orientation::Column)
169410a898b3SArjun P         dual.push_back(simplex.tableau(row, simplex.con[i + 1].pos));
1695d6f9bb03SArjun P       else
1696094ad066SArjun P         dual.emplace_back(0);
169710a898b3SArjun P     }
169810a898b3SArjun P     return *maybeWidth;
169910a898b3SArjun P   }
170010a898b3SArjun P 
170110a898b3SArjun P   /// Remove the last equality that was added through addEqualityForDirection.
170210a898b3SArjun P   ///
170310a898b3SArjun P   /// We do this by rolling back to the snapshot at the top of the stack, which
170410a898b3SArjun P   /// should be a snapshot taken just before the last equality was added.
removeLastEquality()170510a898b3SArjun P   void removeLastEquality() {
170610a898b3SArjun P     assert(!snapshotStack.empty() && "Snapshot stack is empty!");
170710a898b3SArjun P     simplex.rollback(snapshotStack.back());
170810a898b3SArjun P     snapshotStack.pop_back();
170910a898b3SArjun P   }
171010a898b3SArjun P 
171110a898b3SArjun P private:
171210a898b3SArjun P   /// Returns coefficients of the expression 'dot_product(dir, x - y)',
171310a898b3SArjun P   /// i.e.,   dir_1 * x_1 + dir_2 * x_2 + ... + dir_n * x_n
171410a898b3SArjun P   ///       - dir_1 * y_1 - dir_2 * y_2 - ... - dir_n * y_n,
171510a898b3SArjun P   /// where n is the dimension of the original polytope.
getCoeffsForDirection(ArrayRef<int64_t> dir)171610a898b3SArjun P   SmallVector<int64_t, 8> getCoeffsForDirection(ArrayRef<int64_t> dir) {
171733afea54SArjun P     assert(2 * dir.size() == simplex.getNumVariables() &&
171810a898b3SArjun P            "Direction vector has wrong dimensionality");
171910a898b3SArjun P     SmallVector<int64_t, 8> coeffs(dir.begin(), dir.end());
172010a898b3SArjun P     coeffs.reserve(2 * dir.size());
172110a898b3SArjun P     for (int64_t coeff : dir)
172210a898b3SArjun P       coeffs.push_back(-coeff);
1723094ad066SArjun P     coeffs.emplace_back(0); // constant term
172410a898b3SArjun P     return coeffs;
172510a898b3SArjun P   }
172610a898b3SArjun P 
172710a898b3SArjun P   Simplex simplex;
172810a898b3SArjun P   /// The first index of the equality constraints, the index immediately after
172910a898b3SArjun P   /// the last constraint in the initial product simplex.
173010a898b3SArjun P   unsigned simplexConstraintOffset;
173110a898b3SArjun P   /// A stack of snapshots, used for rolling back.
173210a898b3SArjun P   SmallVector<unsigned, 8> snapshotStack;
173310a898b3SArjun P };
173410a898b3SArjun P 
173510a898b3SArjun P /// Reduce the basis to try and find a direction in which the polytope is
173610a898b3SArjun P /// "thin". This only works for bounded polytopes.
173710a898b3SArjun P ///
173810a898b3SArjun P /// This is an implementation of the algorithm described in the paper
173910a898b3SArjun P /// "An Implementation of Generalized Basis Reduction for Integer Programming"
174010a898b3SArjun P /// by W. Cook, T. Rutherford, H. E. Scarf, D. Shallcross.
174110a898b3SArjun P ///
174210a898b3SArjun P /// Let b_{level}, b_{level + 1}, ... b_n be the current basis.
174310a898b3SArjun P /// Let width_i(v) = max <v, x - y> where x and y are points in the original
174410a898b3SArjun P /// polytope such that <b_j, x - y> = 0 is satisfied for all level <= j < i.
174510a898b3SArjun P ///
174610a898b3SArjun P /// In every iteration, we first replace b_{i+1} with b_{i+1} + u*b_i, where u
174710a898b3SArjun P /// is the integer such that width_i(b_{i+1} + u*b_i) is minimized. Let dual_i
174810a898b3SArjun P /// be the dual variable associated with the constraint <b_i, x - y> = 0 when
174910a898b3SArjun P /// computing width_{i+1}(b_{i+1}). It can be shown that dual_i is the
175010a898b3SArjun P /// minimizing value of u, if it were allowed to be fractional. Due to
175110a898b3SArjun P /// convexity, the minimizing integer value is either floor(dual_i) or
175210a898b3SArjun P /// ceil(dual_i), so we just need to check which of these gives a lower
175310a898b3SArjun P /// width_{i+1} value. If dual_i turned out to be an integer, then u = dual_i.
175410a898b3SArjun P ///
175510a898b3SArjun P /// Now if width_i(b_{i+1}) < 0.75 * width_i(b_i), we swap b_i and (the new)
175610a898b3SArjun P /// b_{i + 1} and decrement i (unless i = level, in which case we stay at the
175710a898b3SArjun P /// same i). Otherwise, we increment i.
175810a898b3SArjun P ///
175910a898b3SArjun P /// We keep f values and duals cached and invalidate them when necessary.
176010a898b3SArjun P /// Whenever possible, we use them instead of recomputing them. We implement the
176110a898b3SArjun P /// algorithm as follows.
176210a898b3SArjun P ///
176310a898b3SArjun P /// In an iteration at i we need to compute:
176410a898b3SArjun P ///   a) width_i(b_{i + 1})
176510a898b3SArjun P ///   b) width_i(b_i)
176610a898b3SArjun P ///   c) the integer u that minimizes width_i(b_{i + 1} + u*b_i)
176710a898b3SArjun P ///
176810a898b3SArjun P /// If width_i(b_i) is not already cached, we compute it.
176910a898b3SArjun P ///
177010a898b3SArjun P /// If the duals are not already cached, we compute width_{i+1}(b_{i+1}) and
177110a898b3SArjun P /// store the duals from this computation.
177210a898b3SArjun P ///
177310a898b3SArjun P /// We call updateBasisWithUAndGetFCandidate, which finds the minimizing value
177410a898b3SArjun P /// of u as explained before, caches the duals from this computation, sets
177510a898b3SArjun P /// b_{i+1} to b_{i+1} + u*b_i, and returns the new value of width_i(b_{i+1}).
177610a898b3SArjun P ///
177710a898b3SArjun P /// Now if width_i(b_{i+1}) < 0.75 * width_i(b_i), we swap b_i and b_{i+1} and
177810a898b3SArjun P /// decrement i, resulting in the basis
177910a898b3SArjun P /// ... b_{i - 1}, b_{i + 1} + u*b_i, b_i, b_{i+2}, ...
178010a898b3SArjun P /// with corresponding f values
178110a898b3SArjun P /// ... width_{i-1}(b_{i-1}), width_i(b_{i+1} + u*b_i), width_{i+1}(b_i), ...
178210a898b3SArjun P /// The values up to i - 1 remain unchanged. We have just gotten the middle
178310a898b3SArjun P /// value from updateBasisWithUAndGetFCandidate, so we can update that in the
178410a898b3SArjun P /// cache. The value at width_{i+1}(b_i) is unknown, so we evict this value from
178510a898b3SArjun P /// the cache. The iteration after decrementing needs exactly the duals from the
178610a898b3SArjun P /// computation of width_i(b_{i + 1} + u*b_i), so we keep these in the cache.
178710a898b3SArjun P ///
178810a898b3SArjun P /// When incrementing i, no cached f values get invalidated. However, the cached
178910a898b3SArjun P /// duals do get invalidated as the duals for the higher levels are different.
reduceBasis(Matrix & basis,unsigned level)179010a898b3SArjun P void Simplex::reduceBasis(Matrix &basis, unsigned level) {
179110a898b3SArjun P   const Fraction epsilon(3, 4);
179210a898b3SArjun P 
179310a898b3SArjun P   if (level == basis.getNumRows() - 1)
179410a898b3SArjun P     return;
179510a898b3SArjun P 
179610a898b3SArjun P   GBRSimplex gbrSimplex(*this);
179710a898b3SArjun P   SmallVector<Fraction, 8> width;
179810a898b3SArjun P   SmallVector<int64_t, 8> dual;
179910a898b3SArjun P   int64_t dualDenom;
180010a898b3SArjun P 
180110a898b3SArjun P   // Finds the value of u that minimizes width_i(b_{i+1} + u*b_i), caches the
180210a898b3SArjun P   // duals from this computation, sets b_{i+1} to b_{i+1} + u*b_i, and returns
180310a898b3SArjun P   // the new value of width_i(b_{i+1}).
180410a898b3SArjun P   //
180510a898b3SArjun P   // If dual_i is not an integer, the minimizing value must be either
180610a898b3SArjun P   // floor(dual_i) or ceil(dual_i). We compute the expression for both and
180710a898b3SArjun P   // choose the minimizing value.
180810a898b3SArjun P   //
180910a898b3SArjun P   // If dual_i is an integer, we don't need to perform these computations. We
181010a898b3SArjun P   // know that in this case,
181110a898b3SArjun P   //   a) u = dual_i.
181210a898b3SArjun P   //   b) one can show that dual_j for j < i are the same duals we would have
181310a898b3SArjun P   //      gotten from computing width_i(b_{i + 1} + u*b_i), so the correct duals
181410a898b3SArjun P   //      are the ones already in the cache.
181510a898b3SArjun P   //   c) width_i(b_{i+1} + u*b_i) = min_{alpha} width_i(b_{i+1} + alpha * b_i),
181610a898b3SArjun P   //   which
181710a898b3SArjun P   //      one can show is equal to width_{i+1}(b_{i+1}). The latter value must
181810a898b3SArjun P   //      be in the cache, so we get it from there and return it.
181910a898b3SArjun P   auto updateBasisWithUAndGetFCandidate = [&](unsigned i) -> Fraction {
182010a898b3SArjun P     assert(i < level + dual.size() && "dual_i is not known!");
182110a898b3SArjun P 
182210a898b3SArjun P     int64_t u = floorDiv(dual[i - level], dualDenom);
182310a898b3SArjun P     basis.addToRow(i, i + 1, u);
182410a898b3SArjun P     if (dual[i - level] % dualDenom != 0) {
182510a898b3SArjun P       SmallVector<int64_t, 8> candidateDual[2];
182610a898b3SArjun P       int64_t candidateDualDenom[2];
182710a898b3SArjun P       Fraction widthI[2];
182810a898b3SArjun P 
182910a898b3SArjun P       // Initially u is floor(dual) and basis reflects this.
183010a898b3SArjun P       widthI[0] = gbrSimplex.computeWidthAndDuals(
183110a898b3SArjun P           basis.getRow(i + 1), candidateDual[0], candidateDualDenom[0]);
183210a898b3SArjun P 
183310a898b3SArjun P       // Now try ceil(dual), i.e. floor(dual) + 1.
183410a898b3SArjun P       ++u;
183510a898b3SArjun P       basis.addToRow(i, i + 1, 1);
183610a898b3SArjun P       widthI[1] = gbrSimplex.computeWidthAndDuals(
183710a898b3SArjun P           basis.getRow(i + 1), candidateDual[1], candidateDualDenom[1]);
183810a898b3SArjun P 
183910a898b3SArjun P       unsigned j = widthI[0] < widthI[1] ? 0 : 1;
184010a898b3SArjun P       if (j == 0)
184110a898b3SArjun P         // Subtract 1 to go from u = ceil(dual) back to floor(dual).
184210a898b3SArjun P         basis.addToRow(i, i + 1, -1);
1843d6f9bb03SArjun P 
1844d6f9bb03SArjun P       // width_i(b{i+1} + u*b_i) should be minimized at our value of u.
1845d6f9bb03SArjun P       // We assert that this holds by checking that the values of width_i at
1846d6f9bb03SArjun P       // u - 1 and u + 1 are greater than or equal to the value at u. If the
1847d6f9bb03SArjun P       // width is lesser at either of the adjacent values, then our computed
1848d6f9bb03SArjun P       // value of u is clearly not the minimizer. Otherwise by convexity the
1849d6f9bb03SArjun P       // computed value of u is really the minimizer.
1850d6f9bb03SArjun P 
1851d6f9bb03SArjun P       // Check the value at u - 1.
1852497f87bbSStella Laurenzo       assert(gbrSimplex.computeWidth(scaleAndAddForAssert(
1853d6f9bb03SArjun P                  basis.getRow(i + 1), -1, basis.getRow(i))) >= widthI[j] &&
1854d6f9bb03SArjun P              "Computed u value does not minimize the width!");
1855d6f9bb03SArjun P       // Check the value at u + 1.
1856497f87bbSStella Laurenzo       assert(gbrSimplex.computeWidth(scaleAndAddForAssert(
1857d6f9bb03SArjun P                  basis.getRow(i + 1), +1, basis.getRow(i))) >= widthI[j] &&
1858d6f9bb03SArjun P              "Computed u value does not minimize the width!");
1859d6f9bb03SArjun P 
186010a898b3SArjun P       dual = std::move(candidateDual[j]);
186110a898b3SArjun P       dualDenom = candidateDualDenom[j];
186210a898b3SArjun P       return widthI[j];
186310a898b3SArjun P     }
1864d6f9bb03SArjun P 
186510a898b3SArjun P     assert(i + 1 - level < width.size() && "width_{i+1} wasn't saved");
1866d6f9bb03SArjun P     // f_i(b_{i+1} + dual*b_i) == width_{i+1}(b_{i+1}) when `dual` minimizes the
1867d6f9bb03SArjun P     // LHS. (note: the basis has already been updated, so b_{i+1} + dual*b_i in
1868d6f9bb03SArjun P     // the above expression is equal to basis.getRow(i+1) below.)
1869d6f9bb03SArjun P     assert(gbrSimplex.computeWidth(basis.getRow(i + 1)) ==
1870d6f9bb03SArjun P            width[i + 1 - level]);
187110a898b3SArjun P     return width[i + 1 - level];
187210a898b3SArjun P   };
187310a898b3SArjun P 
187410a898b3SArjun P   // In the ith iteration of the loop, gbrSimplex has constraints for directions
187510a898b3SArjun P   // from `level` to i - 1.
187610a898b3SArjun P   unsigned i = level;
187710a898b3SArjun P   while (i < basis.getNumRows() - 1) {
187810a898b3SArjun P     if (i >= level + width.size()) {
187910a898b3SArjun P       // We don't even know the value of f_i(b_i), so let's find that first.
188010a898b3SArjun P       // We have to do this first since later we assume that width already
188110a898b3SArjun P       // contains values up to and including i.
188210a898b3SArjun P 
188310a898b3SArjun P       assert((i == 0 || i - 1 < level + width.size()) &&
188410a898b3SArjun P              "We are at level i but we don't know the value of width_{i-1}");
188510a898b3SArjun P 
188610a898b3SArjun P       // We don't actually use these duals at all, but it doesn't matter
188710a898b3SArjun P       // because this case should only occur when i is level, and there are no
188810a898b3SArjun P       // duals in that case anyway.
188910a898b3SArjun P       assert(i == level && "This case should only occur when i == level");
189010a898b3SArjun P       width.push_back(
189110a898b3SArjun P           gbrSimplex.computeWidthAndDuals(basis.getRow(i), dual, dualDenom));
189210a898b3SArjun P     }
189310a898b3SArjun P 
189410a898b3SArjun P     if (i >= level + dual.size()) {
189510a898b3SArjun P       assert(i + 1 >= level + width.size() &&
189610a898b3SArjun P              "We don't know dual_i but we know width_{i+1}");
189710a898b3SArjun P       // We don't know dual for our level, so let's find it.
189810a898b3SArjun P       gbrSimplex.addEqualityForDirection(basis.getRow(i));
189910a898b3SArjun P       width.push_back(gbrSimplex.computeWidthAndDuals(basis.getRow(i + 1), dual,
190010a898b3SArjun P                                                       dualDenom));
190110a898b3SArjun P       gbrSimplex.removeLastEquality();
190210a898b3SArjun P     }
190310a898b3SArjun P 
190410a898b3SArjun P     // This variable stores width_i(b_{i+1} + u*b_i).
190510a898b3SArjun P     Fraction widthICandidate = updateBasisWithUAndGetFCandidate(i);
190610a898b3SArjun P     if (widthICandidate < epsilon * width[i - level]) {
190710a898b3SArjun P       basis.swapRows(i, i + 1);
190810a898b3SArjun P       width[i - level] = widthICandidate;
190910a898b3SArjun P       // The values of width_{i+1}(b_{i+1}) and higher may change after the
191010a898b3SArjun P       // swap, so we remove the cached values here.
191110a898b3SArjun P       width.resize(i - level + 1);
191210a898b3SArjun P       if (i == level) {
191310a898b3SArjun P         dual.clear();
191410a898b3SArjun P         continue;
191510a898b3SArjun P       }
191610a898b3SArjun P 
191710a898b3SArjun P       gbrSimplex.removeLastEquality();
191810a898b3SArjun P       i--;
191910a898b3SArjun P       continue;
192010a898b3SArjun P     }
192110a898b3SArjun P 
192210a898b3SArjun P     // Invalidate duals since the higher level needs to recompute its own duals.
192310a898b3SArjun P     dual.clear();
192410a898b3SArjun P     gbrSimplex.addEqualityForDirection(basis.getRow(i));
192510a898b3SArjun P     i++;
192610a898b3SArjun P   }
192710a898b3SArjun P }
192810a898b3SArjun P 
192910a898b3SArjun P /// Search for an integer sample point using a branch and bound algorithm.
193010a898b3SArjun P ///
193110a898b3SArjun P /// Each row in the basis matrix is a vector, and the set of basis vectors
193210a898b3SArjun P /// should span the space. Initially this is the identity matrix,
193310a898b3SArjun P /// i.e., the basis vectors are just the variables.
193410a898b3SArjun P ///
193510a898b3SArjun P /// In every level, a value is assigned to the level-th basis vector, as
193610a898b3SArjun P /// follows. Compute the minimum and maximum rational values of this direction.
193710a898b3SArjun P /// If only one integer point lies in this range, constrain the variable to
193810a898b3SArjun P /// have this value and recurse to the next variable.
193910a898b3SArjun P ///
194010a898b3SArjun P /// If the range has multiple values, perform generalized basis reduction via
194110a898b3SArjun P /// reduceBasis and then compute the bounds again. Now we try constraining
194210a898b3SArjun P /// this direction in the first value in this range and "recurse" to the next
194310a898b3SArjun P /// level. If we fail to find a sample, we try assigning the direction the next
194410a898b3SArjun P /// value in this range, and so on.
194510a898b3SArjun P ///
194610a898b3SArjun P /// If no integer sample is found from any of the assignments, or if the range
194710a898b3SArjun P /// contains no integer value, then of course the polytope is empty for the
194810a898b3SArjun P /// current assignment of the values in previous levels, so we return to
194910a898b3SArjun P /// the previous level.
195010a898b3SArjun P ///
195110a898b3SArjun P /// If we reach the last level where all the variables have been assigned values
195210a898b3SArjun P /// already, then we simply return the current sample point if it is integral,
195310a898b3SArjun P /// and go back to the previous level otherwise.
195410a898b3SArjun P ///
195510a898b3SArjun P /// To avoid potentially arbitrarily large recursion depths leading to stack
195610a898b3SArjun P /// overflows, this algorithm is implemented iteratively.
findIntegerSample()195710a898b3SArjun P Optional<SmallVector<int64_t, 8>> Simplex::findIntegerSample() {
195810a898b3SArjun P   if (empty)
195910a898b3SArjun P     return {};
196010a898b3SArjun P 
196110a898b3SArjun P   unsigned nDims = var.size();
196210a898b3SArjun P   Matrix basis = Matrix::identity(nDims);
196310a898b3SArjun P 
196410a898b3SArjun P   unsigned level = 0;
196510a898b3SArjun P   // The snapshot just before constraining a direction to a value at each level.
196610a898b3SArjun P   SmallVector<unsigned, 8> snapshotStack;
196710a898b3SArjun P   // The maximum value in the range of the direction for each level.
196810a898b3SArjun P   SmallVector<int64_t, 8> upperBoundStack;
196910a898b3SArjun P   // The next value to try constraining the basis vector to at each level.
197010a898b3SArjun P   SmallVector<int64_t, 8> nextValueStack;
197110a898b3SArjun P 
197210a898b3SArjun P   snapshotStack.reserve(basis.getNumRows());
197310a898b3SArjun P   upperBoundStack.reserve(basis.getNumRows());
197410a898b3SArjun P   nextValueStack.reserve(basis.getNumRows());
197510a898b3SArjun P   while (level != -1u) {
197610a898b3SArjun P     if (level == basis.getNumRows()) {
197710a898b3SArjun P       // We've assigned values to all variables. Return if we have a sample,
197810a898b3SArjun P       // or go back up to the previous level otherwise.
197910a898b3SArjun P       if (auto maybeSample = getSamplePointIfIntegral())
198010a898b3SArjun P         return maybeSample;
198110a898b3SArjun P       level--;
198210a898b3SArjun P       continue;
198310a898b3SArjun P     }
198410a898b3SArjun P 
198510a898b3SArjun P     if (level >= upperBoundStack.size()) {
198610a898b3SArjun P       // We haven't populated the stack values for this level yet, so we have
198710a898b3SArjun P       // just come down a level ("recursed"). Find the lower and upper bounds.
198810a898b3SArjun P       // If there is more than one integer point in the range, perform
198910a898b3SArjun P       // generalized basis reduction.
199010a898b3SArjun P       SmallVector<int64_t, 8> basisCoeffs =
199110a898b3SArjun P           llvm::to_vector<8>(basis.getRow(level));
1992094ad066SArjun P       basisCoeffs.emplace_back(0);
199310a898b3SArjun P 
19948e799588SArjun P       MaybeOptimum<int64_t> minRoundedUp, maxRoundedDown;
199510a898b3SArjun P       std::tie(minRoundedUp, maxRoundedDown) =
199610a898b3SArjun P           computeIntegerBounds(basisCoeffs);
199710a898b3SArjun P 
19988e799588SArjun P       // We don't have any integer values in the range.
19998e799588SArjun P       // Pop the stack and return up a level.
20008e799588SArjun P       if (minRoundedUp.isEmpty() || maxRoundedDown.isEmpty()) {
20018e799588SArjun P         assert((minRoundedUp.isEmpty() && maxRoundedDown.isEmpty()) &&
20028e799588SArjun P                "If one bound is empty, both should be.");
20038e799588SArjun P         snapshotStack.pop_back();
20048e799588SArjun P         nextValueStack.pop_back();
20058e799588SArjun P         upperBoundStack.pop_back();
20068e799588SArjun P         level--;
20078e799588SArjun P         continue;
20088e799588SArjun P       }
20098e799588SArjun P 
20108e799588SArjun P       // We already checked the empty case above.
20118e799588SArjun P       assert((minRoundedUp.isBounded() && maxRoundedDown.isBounded()) &&
20128e799588SArjun P              "Polyhedron should be bounded!");
20138e799588SArjun P 
201410a898b3SArjun P       // Heuristic: if the sample point is integral at this point, just return
201510a898b3SArjun P       // it.
201610a898b3SArjun P       if (auto maybeSample = getSamplePointIfIntegral())
201710a898b3SArjun P         return *maybeSample;
201810a898b3SArjun P 
20198e799588SArjun P       if (*minRoundedUp < *maxRoundedDown) {
202010a898b3SArjun P         reduceBasis(basis, level);
202110a898b3SArjun P         basisCoeffs = llvm::to_vector<8>(basis.getRow(level));
2022094ad066SArjun P         basisCoeffs.emplace_back(0);
202310a898b3SArjun P         std::tie(minRoundedUp, maxRoundedDown) =
202410a898b3SArjun P             computeIntegerBounds(basisCoeffs);
202510a898b3SArjun P       }
202610a898b3SArjun P 
202710a898b3SArjun P       snapshotStack.push_back(getSnapshot());
202810a898b3SArjun P       // The smallest value in the range is the next value to try.
2029738c738bSArjun P       // The values in the optionals are guaranteed to exist since we know the
2030738c738bSArjun P       // polytope is bounded.
2031738c738bSArjun P       nextValueStack.push_back(*minRoundedUp);
2032738c738bSArjun P       upperBoundStack.push_back(*maxRoundedDown);
203310a898b3SArjun P     }
203410a898b3SArjun P 
203510a898b3SArjun P     assert((snapshotStack.size() - 1 == level &&
203610a898b3SArjun P             nextValueStack.size() - 1 == level &&
203710a898b3SArjun P             upperBoundStack.size() - 1 == level) &&
203810a898b3SArjun P            "Mismatched variable stack sizes!");
203910a898b3SArjun P 
204010a898b3SArjun P     // Whether we "recursed" or "returned" from a lower level, we rollback
204110a898b3SArjun P     // to the snapshot of the starting state at this level. (in the "recursed"
204210a898b3SArjun P     // case this has no effect)
204310a898b3SArjun P     rollback(snapshotStack.back());
204410a898b3SArjun P     int64_t nextValue = nextValueStack.back();
2045ef95a6e8SArjun P     ++nextValueStack.back();
204610a898b3SArjun P     if (nextValue > upperBoundStack.back()) {
204710a898b3SArjun P       // We have exhausted the range and found no solution. Pop the stack and
204810a898b3SArjun P       // return up a level.
204910a898b3SArjun P       snapshotStack.pop_back();
205010a898b3SArjun P       nextValueStack.pop_back();
205110a898b3SArjun P       upperBoundStack.pop_back();
205210a898b3SArjun P       level--;
205310a898b3SArjun P       continue;
205410a898b3SArjun P     }
205510a898b3SArjun P 
205610a898b3SArjun P     // Try the next value in the range and "recurse" into the next level.
205710a898b3SArjun P     SmallVector<int64_t, 8> basisCoeffs(basis.getRow(level).begin(),
205810a898b3SArjun P                                         basis.getRow(level).end());
205910a898b3SArjun P     basisCoeffs.push_back(-nextValue);
206010a898b3SArjun P     addEquality(basisCoeffs);
206110a898b3SArjun P     level++;
206210a898b3SArjun P   }
206310a898b3SArjun P 
206410a898b3SArjun P   return {};
206510a898b3SArjun P }
206610a898b3SArjun P 
206710a898b3SArjun P /// Compute the minimum and maximum integer values the expression can take. We
206810a898b3SArjun P /// compute each separately.
20698e799588SArjun P std::pair<MaybeOptimum<int64_t>, MaybeOptimum<int64_t>>
computeIntegerBounds(ArrayRef<int64_t> coeffs)207010a898b3SArjun P Simplex::computeIntegerBounds(ArrayRef<int64_t> coeffs) {
20718e799588SArjun P   MaybeOptimum<int64_t> minRoundedUp(
20728e799588SArjun P       computeOptimum(Simplex::Direction::Down, coeffs).map(ceil));
20738e799588SArjun P   MaybeOptimum<int64_t> maxRoundedDown(
20748e799588SArjun P       computeOptimum(Simplex::Direction::Up, coeffs).map(floor));
207510a898b3SArjun P   return {minRoundedUp, maxRoundedDown};
207610a898b3SArjun P }
207710a898b3SArjun P 
print(raw_ostream & os) const20784fa96b7eSArjun P void SimplexBase::print(raw_ostream &os) const {
20798bc2cff9SArjun P   os << "rows = " << getNumRows() << ", columns = " << getNumColumns() << "\n";
208010a898b3SArjun P   if (empty)
208110a898b3SArjun P     os << "Simplex marked empty!\n";
208210a898b3SArjun P   os << "var: ";
208310a898b3SArjun P   for (unsigned i = 0; i < var.size(); ++i) {
208410a898b3SArjun P     if (i > 0)
208510a898b3SArjun P       os << ", ";
208610a898b3SArjun P     var[i].print(os);
208710a898b3SArjun P   }
208810a898b3SArjun P   os << "\ncon: ";
208910a898b3SArjun P   for (unsigned i = 0; i < con.size(); ++i) {
209010a898b3SArjun P     if (i > 0)
209110a898b3SArjun P       os << ", ";
209210a898b3SArjun P     con[i].print(os);
209310a898b3SArjun P   }
209410a898b3SArjun P   os << '\n';
20958bc2cff9SArjun P   for (unsigned row = 0, e = getNumRows(); row < e; ++row) {
209610a898b3SArjun P     if (row > 0)
209710a898b3SArjun P       os << ", ";
209810a898b3SArjun P     os << "r" << row << ": " << rowUnknown[row];
209910a898b3SArjun P   }
210010a898b3SArjun P   os << '\n';
210110a898b3SArjun P   os << "c0: denom, c1: const";
21028bc2cff9SArjun P   for (unsigned col = 2, e = getNumColumns(); col < e; ++col)
210310a898b3SArjun P     os << ", c" << col << ": " << colUnknown[col];
210410a898b3SArjun P   os << '\n';
21058bc2cff9SArjun P   for (unsigned row = 0, numRows = getNumRows(); row < numRows; ++row) {
21068bc2cff9SArjun P     for (unsigned col = 0, numCols = getNumColumns(); col < numCols; ++col)
210710a898b3SArjun P       os << tableau(row, col) << '\t';
210810a898b3SArjun P     os << '\n';
210910a898b3SArjun P   }
211010a898b3SArjun P   os << '\n';
211110a898b3SArjun P }
211210a898b3SArjun P 
dump() const21134fa96b7eSArjun P void SimplexBase::dump() const { print(llvm::errs()); }
211410a898b3SArjun P 
isRationalSubsetOf(const IntegerRelation & rel)2115bb901355SGroverkss bool Simplex::isRationalSubsetOf(const IntegerRelation &rel) {
211645ea542dSMichel Weber   if (isEmpty())
211745ea542dSMichel Weber     return true;
211845ea542dSMichel Weber 
2119bb901355SGroverkss   for (unsigned i = 0, e = rel.getNumInequalities(); i < e; ++i)
2120bb901355SGroverkss     if (findIneqType(rel.getInequality(i)) != IneqType::Redundant)
212145ea542dSMichel Weber       return false;
212245ea542dSMichel Weber 
2123bb901355SGroverkss   for (unsigned i = 0, e = rel.getNumEqualities(); i < e; ++i)
2124bb901355SGroverkss     if (!isRedundantEquality(rel.getEquality(i)))
212545ea542dSMichel Weber       return false;
212645ea542dSMichel Weber 
212745ea542dSMichel Weber   return true;
212845ea542dSMichel Weber }
212945ea542dSMichel Weber 
213056bc8732SMichel Weber /// Returns the type of the inequality with coefficients `coeffs`.
213156bc8732SMichel Weber /// Possible types are:
213256bc8732SMichel Weber /// Redundant   The inequality is satisfied by all points in the polytope
213356bc8732SMichel Weber /// Cut         The inequality is satisfied by some points, but not by others
213456bc8732SMichel Weber /// Separate    The inequality is not satisfied by any point
213556bc8732SMichel Weber ///
213656bc8732SMichel Weber /// Internally, this computes the minimum and the maximum the inequality with
213756bc8732SMichel Weber /// coefficients `coeffs` can take. If the minimum is >= 0, the inequality holds
213856bc8732SMichel Weber /// for all points in the polytope, so it is redundant.  If the minimum is <= 0
213956bc8732SMichel Weber /// and the maximum is >= 0, the points in between the minimum and the
214056bc8732SMichel Weber /// inequality do not satisfy it, the points in between the inequality and the
214156bc8732SMichel Weber /// maximum satisfy it. Hence, it is a cut inequality. If both are < 0, no
214256bc8732SMichel Weber /// points of the polytope satisfy the inequality, which means it is a separate
214356bc8732SMichel Weber /// inequality.
findIneqType(ArrayRef<int64_t> coeffs)214456bc8732SMichel Weber Simplex::IneqType Simplex::findIneqType(ArrayRef<int64_t> coeffs) {
214556bc8732SMichel Weber   MaybeOptimum<Fraction> minimum = computeOptimum(Direction::Down, coeffs);
214656bc8732SMichel Weber   if (minimum.isBounded() && *minimum >= Fraction(0, 1)) {
214756bc8732SMichel Weber     return IneqType::Redundant;
214856bc8732SMichel Weber   }
214956bc8732SMichel Weber   MaybeOptimum<Fraction> maximum = computeOptimum(Direction::Up, coeffs);
215056bc8732SMichel Weber   if ((!minimum.isBounded() || *minimum <= Fraction(0, 1)) &&
215156bc8732SMichel Weber       (!maximum.isBounded() || *maximum >= Fraction(0, 1))) {
215256bc8732SMichel Weber     return IneqType::Cut;
215356bc8732SMichel Weber   }
215456bc8732SMichel Weber   return IneqType::Separate;
215556bc8732SMichel Weber }
215656bc8732SMichel Weber 
215756bc8732SMichel Weber /// Checks whether the type of the inequality with coefficients `coeffs`
215856bc8732SMichel Weber /// is Redundant.
isRedundantInequality(ArrayRef<int64_t> coeffs)215945ea542dSMichel Weber bool Simplex::isRedundantInequality(ArrayRef<int64_t> coeffs) {
21608e799588SArjun P   assert(!empty &&
21618e799588SArjun P          "It is not meaningful to ask about redundancy in an empty set!");
216256bc8732SMichel Weber   return findIneqType(coeffs) == IneqType::Redundant;
216345ea542dSMichel Weber }
216445ea542dSMichel Weber 
216545ea542dSMichel Weber /// Check whether the equality given by `coeffs == 0` is redundant given
216645ea542dSMichel Weber /// the existing constraints. This is redundant when `coeffs` is already
216745ea542dSMichel Weber /// always zero under the existing constraints. `coeffs` is always zero
216845ea542dSMichel Weber /// when the minimum and maximum value that `coeffs` can take are both zero.
isRedundantEquality(ArrayRef<int64_t> coeffs)216945ea542dSMichel Weber bool Simplex::isRedundantEquality(ArrayRef<int64_t> coeffs) {
21708e799588SArjun P   assert(!empty &&
21718e799588SArjun P          "It is not meaningful to ask about redundancy in an empty set!");
21728e799588SArjun P   MaybeOptimum<Fraction> minimum = computeOptimum(Direction::Down, coeffs);
21738e799588SArjun P   MaybeOptimum<Fraction> maximum = computeOptimum(Direction::Up, coeffs);
21748e799588SArjun P   assert((!minimum.isEmpty() && !maximum.isEmpty()) &&
21758e799588SArjun P          "Optima should be non-empty for a non-empty set");
21768e799588SArjun P   return minimum.isBounded() && maximum.isBounded() &&
21778e799588SArjun P          *maximum == Fraction(0, 1) && *minimum == Fraction(0, 1);
217845ea542dSMichel Weber }
2179