llvm/mlir/lib/Analysis/Presburger/Simplex.cpp

//===- Simplex.cpp - MLIR Simplex Class -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "mlir/Analysis/Presburger/Simplex.h"
#include "mlir/Analysis/Presburger/Fraction.h"
#include "mlir/Analysis/Presburger/IntegerRelation.h"
#include "mlir/Analysis/Presburger/Matrix.h"
#include "mlir/Analysis/Presburger/PresburgerSpace.h"
#include "mlir/Analysis/Presburger/Utils.h"
#include "llvm/ADT/DynamicAPInt.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LogicalResult.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <functional>
#include <limits>
#include <optional>
#include <tuple>
#include <utility>

usingnamespacemlir;
usingnamespacepresburger;

Direction;

const int nullIndex =;

// Return a + scale*b;
LLVM_ATTRIBUTE_UNUSED
static SmallVector<DynamicAPInt, 8>
scaleAndAddForAssert(ArrayRef<DynamicAPInt> a, const DynamicAPInt &scale,
                     ArrayRef<DynamicAPInt> b) {}

SimplexBase::SimplexBase(unsigned nVar, bool mustUseBigM)
    :{}

SimplexBase::SimplexBase(unsigned nVar, bool mustUseBigM,
                         const llvm::SmallBitVector &isSymbol)
    :{}

const Simplex::Unknown &SimplexBase::unknownFromIndex(int index) const {}

const Simplex::Unknown &SimplexBase::unknownFromColumn(unsigned col) const {}

const Simplex::Unknown &SimplexBase::unknownFromRow(unsigned row) const {}

Simplex::Unknown &SimplexBase::unknownFromIndex(int index) {}

Simplex::Unknown &SimplexBase::unknownFromColumn(unsigned col) {}

Simplex::Unknown &SimplexBase::unknownFromRow(unsigned row) {}

unsigned SimplexBase::addZeroRow(bool makeRestricted) {}

/// Add a new row to the tableau corresponding to the given constant term and
/// list of coefficients. The coefficients are specified as a vector of
/// (variable index, coefficient) pairs.
unsigned SimplexBase::addRow(ArrayRef<DynamicAPInt> coeffs,
                             bool makeRestricted) {}

namespace {
bool signMatchesDirection(const DynamicAPInt &elem, Direction direction) {}

Direction flippedDirection(Direction direction) {}
} // namespace

/// We simply make the tableau consistent while maintaining a lexicopositive
/// basis transform, and then return the sample value. If the tableau becomes
/// empty, we return empty.
///
/// Let the variables be x = (x_1, ... x_n).
/// Let the basis unknowns be y = (y_1, ... y_n).
/// We have that x = A*y + b for some n x n matrix A and n x 1 column vector b.
///
/// As we will show below, A*y is either zero or lexicopositive.
/// Adding a lexicopositive vector to b will make it lexicographically
/// greater, so A*y + b is always equal to or lexicographically greater than b.
/// Thus, since we can attain x = b, that is the lexicographic minimum.
///
/// We have that every column in A is lexicopositive, i.e., has at least
/// one non-zero element, with the first such element being positive. Since for
/// the tableau to be consistent we must have non-negative sample values not
/// only for the constraints but also for the variables, we also have x >= 0 and
/// y >= 0, by which we mean every element in these vectors is non-negative.
///
/// Proof that if every column in A is lexicopositive, and y >= 0, then
/// A*y is zero or lexicopositive. Begin by considering A_1, the first row of A.
/// If this row is all zeros, then (A*y)_1 = (A_1)*y = 0; proceed to the next
/// row. If we run out of rows, A*y is zero and we are done; otherwise, we
/// encounter some row A_i that has a non-zero element. Every column is
/// lexicopositive and so has some positive element before any negative elements
/// occur, so the element in this row for any column, if non-zero, must be
/// positive. Consider (A*y)_i = (A_i)*y. All the elements in both vectors are
/// non-negative, so if this is non-zero then it must be positive. Then the
/// first non-zero element of A*y is positive so A*y is lexicopositive.
///
/// Otherwise, if (A_i)*y is zero, then for every column j that had a non-zero
/// element in A_i, y_j is zero. Thus these columns have no contribution to A*y
/// and we can completely ignore these columns of A. We now continue downwards,
/// looking for rows of A that have a non-zero element other than in the ignored
/// columns. If we find one, say A_k, once again these elements must be positive
/// since they are the first non-zero element in each of these columns, so if
/// (A_k)*y is not zero then we have that A*y is lexicopositive and if not we
/// add these to the set of ignored columns and continue to the next row. If we
/// run out of rows, then A*y is zero and we are done.
MaybeOptimum<SmallVector<Fraction, 8>> LexSimplex::findRationalLexMin() {}

/// Given a row that has a non-integer sample value, add an inequality such
/// that this fractional sample value is cut away from the polytope. The added
/// inequality will be such that no integer points are removed. i.e., the
/// integer lexmin, if it exists, is the same with and without this constraint.
///
/// Let the row be
/// (c + coeffM*M + a_1*s_1 + ... + a_m*s_m + b_1*y_1 + ... + b_n*y_n)/d,
/// where s_1, ... s_m are the symbols and
///       y_1, ... y_n are the other basis unknowns.
///
/// For this to be an integer, we want
/// coeffM*M + a_1*s_1 + ... + a_m*s_m + b_1*y_1 + ... + b_n*y_n = -c (mod d)
/// Note that this constraint must always hold, independent of the basis,
/// becuse the row unknown's value always equals this expression, even if *we*
/// later compute the sample value from a different expression based on a
/// different basis.
///
/// Let us assume that M has a factor of d in it. Imposing this constraint on M
/// does not in any way hinder us from finding a value of M that is big enough.
/// Moreover, this function is only called when the symbolic part of the sample,
/// a_1*s_1 + ... + a_m*s_m, is known to be an integer.
///
/// Also, we can safely reduce the coefficients modulo d, so we have:
///
/// (b_1%d)y_1 + ... + (b_n%d)y_n = (-c%d) + k*d for some integer `k`
///
/// Note that all coefficient modulos here are non-negative. Also, all the
/// unknowns are non-negative here as both constraints and variables are
/// non-negative in LexSimplexBase. (We used the big M trick to make the
/// variables non-negative). Therefore, the LHS here is non-negative.
/// Since 0 <= (-c%d) < d, k is the quotient of dividing the LHS by d and
/// is therefore non-negative as well.
///
/// So we have
/// ((b_1%d)y_1 + ... + (b_n%d)y_n - (-c%d))/d >= 0.
///
/// The constraint is violated when added (it would be useless otherwise)
/// so we immediately try to move it to a column.
LogicalResult LexSimplexBase::addCut(unsigned row) {}

std::optional<unsigned> LexSimplex::maybeGetNonIntegralVarRow() const {}

MaybeOptimum<SmallVector<DynamicAPInt, 8>> LexSimplex::findIntegerLexMin() {}

bool LexSimplex::isSeparateInequality(ArrayRef<DynamicAPInt> coeffs) {}

bool LexSimplex::isRedundantInequality(ArrayRef<DynamicAPInt> coeffs) {}

SmallVector<DynamicAPInt, 8>
SymbolicLexSimplex::getSymbolicSampleNumerator(unsigned row) const {}

SmallVector<DynamicAPInt, 8>
SymbolicLexSimplex::getSymbolicSampleIneq(unsigned row) const {}

void LexSimplexBase::appendSymbol() {}

static bool isRangeDivisibleBy(ArrayRef<DynamicAPInt> range,
                               const DynamicAPInt &divisor) {}

bool SymbolicLexSimplex::isSymbolicSampleIntegral(unsigned row) const {}

/// This proceeds similarly to LexSimplexBase::addCut(). We are given a row that
/// has a symbolic sample value with fractional coefficients.
///
/// Let the row be
/// (c + coeffM*M + sum_i a_i*s_i + sum_j b_j*y_j)/d,
/// where s_1, ... s_m are the symbols and
///       y_1, ... y_n are the other basis unknowns.
///
/// As in LexSimplex::addCut, for this to be an integer, we want
///
/// coeffM*M + sum_j b_j*y_j = -c + sum_i (-a_i*s_i) (mod d)
///
/// This time, a_1*s_1 + ... + a_m*s_m may not be an integer. We find that
///
/// sum_i (b_i%d)y_i = ((-c%d) + sum_i (-a_i%d)s_i)%d + k*d for some integer k
///
/// where we take a modulo of the whole symbolic expression on the right to
/// bring it into the range [0, d - 1]. Therefore, as in addCut(),
/// k is the quotient on dividing the LHS by d, and since LHS >= 0, we have
/// k >= 0 as well. If all the a_i are divisible by d, then we can add the
/// constraint directly.  Otherwise, we realize the modulo of the symbolic
/// expression by adding a division variable
///
/// q = ((-c%d) + sum_i (-a_i%d)s_i)/d
///
/// to the symbol domain, so the equality becomes
///
/// sum_i (b_i%d)y_i = (-c%d) + sum_i (-a_i%d)s_i - q*d + k*d for some integer k
///
/// So the cut is
/// (sum_i (b_i%d)y_i - (-c%d) - sum_i (-a_i%d)s_i + q*d)/d >= 0
/// This constraint is violated when added so we immediately try to move it to a
/// column.
LogicalResult SymbolicLexSimplex::addSymbolicCut(unsigned row) {}

void SymbolicLexSimplex::recordOutput(SymbolicLexOpt &result) const {}

std::optional<unsigned> SymbolicLexSimplex::maybeGetAlwaysViolatedRow() {}

std::optional<unsigned> SymbolicLexSimplex::maybeGetNonIntegralVarRow() {}

/// The non-branching pivots are just the ones moving the rows
/// that are always violated in the symbol domain.
LogicalResult SymbolicLexSimplex::doNonBranchingPivots() {}

SymbolicLexOpt SymbolicLexSimplex::computeSymbolicIntegerLexMin() {}

bool LexSimplex::rowIsViolated(unsigned row) const {}

std::optional<unsigned> LexSimplex::maybeGetViolatedRow() const {}

/// We simply look for violated rows and keep trying to move them to column
/// orientation, which always succeeds unless the constraints have no solution
/// in which case we just give up and return.
LogicalResult LexSimplex::restoreRationalConsistency() {}

// Move the row unknown to column orientation while preserving lexicopositivity
// of the basis transform. The sample value of the row must be non-positive.
//
// We only consider pivots where the pivot element is positive. Suppose no such
// pivot exists, i.e., some violated row has no positive coefficient for any
// basis unknown. The row can be represented as (s + c_1*u_1 + ... + c_n*u_n)/d,
// where d is the denominator, s is the sample value and the c_i are the basis
// coefficients. If s != 0, then since any feasible assignment of the basis
// satisfies u_i >= 0 for all i, and we have s < 0 as well as c_i < 0 for all i,
// any feasible assignment would violate this row and therefore the constraints
// have no solution.
//
// We can preserve lexicopositivity by picking the pivot column with positive
// pivot element that makes the lexicographically smallest change to the sample
// point.
//
// Proof. Let
// x = (x_1, ... x_n) be the variables,
// z = (z_1, ... z_m) be the constraints,
// y = (y_1, ... y_n) be the current basis, and
// define w = (x_1, ... x_n, z_1, ... z_m) = B*y + s.
// B is basically the simplex tableau of our implementation except that instead
// of only describing the transform to get back the non-basis unknowns, it
// defines the values of all the unknowns in terms of the basis unknowns.
// Similarly, s is the column for the sample value.
//
// Our goal is to show that each column in B, restricted to the first n
// rows, is lexicopositive after the pivot if it is so before. This is
// equivalent to saying the columns in the whole matrix are lexicopositive;
// there must be some non-zero element in every column in the first n rows since
// the n variables cannot be spanned without using all the n basis unknowns.
//
// Consider a pivot where z_i replaces y_j in the basis. Recall the pivot
// transform for the tableau derived for SimplexBase::pivot:
//
//            pivot col    other col                   pivot col    other col
// pivot row     a             b       ->   pivot row     1/a         -b/a
// other row     c             d            other row     c/a        d - bc/a
//
// Similarly, a pivot results in B changing to B' and c to c'; the difference
// between the tableau and these matrices B and B' is that there is no special
// case for the pivot row, since it continues to represent the same unknown. The
// same formula applies for all rows:
//
// B'.col(j) = B.col(j) / B(i,j)
// B'.col(k) = B.col(k) - B(i,k) * B.col(j) / B(i,j) for k != j
// and similarly, s' = s - s_i * B.col(j) / B(i,j).
//
// If s_i == 0, then the sample value remains unchanged. Otherwise, if s_i < 0,
// the change in sample value when pivoting with column a is lexicographically
// smaller than that when pivoting with column b iff B.col(a) / B(i, a) is
// lexicographically smaller than B.col(b) / B(i, b).
//
// Since B(i, j) > 0, column j remains lexicopositive.
//
// For the other columns, suppose C.col(k) is not lexicopositive.
// This means that for some p, for all t < p,
// C(t,k) = 0 => B(t,k) = B(t,j) * B(i,k) / B(i,j) and
// C(t,k) < 0 => B(p,k) < B(t,j) * B(i,k) / B(i,j),
// which is in contradiction to the fact that B.col(j) / B(i,j) must be
// lexicographically smaller than B.col(k) / B(i,k), since it lexicographically
// minimizes the change in sample value.
LogicalResult LexSimplexBase::moveRowUnknownToColumn(unsigned row) {}

unsigned LexSimplexBase::getLexMinPivotColumn(unsigned row, unsigned colA,
                                              unsigned colB) const {}

/// Find a pivot to change the sample value of the row in the specified
/// direction. The returned pivot row will involve `row` if and only if the
/// unknown is unbounded in the specified direction.
///
/// To increase (resp. decrease) the value of a row, we need to find a live
/// column with a non-zero coefficient. If the coefficient is positive, we need
/// to increase (decrease) the value of the column, and if the coefficient is
/// negative, we need to decrease (increase) the value of the column. Also,
/// we cannot decrease the sample value of restricted columns.
///
/// If multiple columns are valid, we break ties by considering a lexicographic
/// ordering where we prefer unknowns with lower index.
std::optional<SimplexBase::Pivot>
Simplex::findPivot(int row, Direction direction) const {}

/// Swap the associated unknowns for the row and the column.
///
/// First we swap the index associated with the row and column. Then we update
/// the unknowns to reflect their new position and orientation.
void SimplexBase::swapRowWithCol(unsigned row, unsigned col) {}

void SimplexBase::pivot(Pivot pair) {}

/// Pivot pivotRow and pivotCol.
///
/// Let R be the pivot row unknown and let C be the pivot col unknown.
/// Since initially R = a*C + sum b_i * X_i
/// (where the sum is over the other column's unknowns, x_i)
/// C = (R - (sum b_i * X_i))/a
///
/// Let u be some other row unknown.
/// u = c*C + sum d_i * X_i
/// So u = c*(R - sum b_i * X_i)/a + sum d_i * X_i
///
/// This results in the following transform:
///            pivot col    other col                   pivot col    other col
/// pivot row     a             b       ->   pivot row     1/a         -b/a
/// other row     c             d            other row     c/a        d - bc/a
///
/// Taking into account the common denominators p and q:
///
///            pivot col    other col                    pivot col   other col
/// pivot row     a/p          b/p     ->   pivot row      p/a         -b/a
/// other row     c/q          d/q          other row     cp/aq    (da - bc)/aq
///
/// The pivot row transform is accomplished be swapping a with the pivot row's
/// common denominator and negating the pivot row except for the pivot column
/// element.
void SimplexBase::pivot(unsigned pivotRow, unsigned pivotCol) {}

/// Perform pivots until the unknown has a non-negative sample value or until
/// no more upward pivots can be performed. Return success if we were able to
/// bring the row to a non-negative sample value, and failure otherwise.
LogicalResult Simplex::restoreRow(Unknown &u) {}

/// Find a row that can be used to pivot the column in the specified direction.
/// This returns an empty optional if and only if the column is unbounded in the
/// specified direction (ignoring skipRow, if skipRow is set).
///
/// If skipRow is set, this row is not considered, and (if it is restricted) its
/// restriction may be violated by the returned pivot. Usually, skipRow is set
/// because we don't want to move it to column position unless it is unbounded,
/// and we are either trying to increase the value of skipRow or explicitly
/// trying to make skipRow negative, so we are not concerned about this.
///
/// If the direction is up (resp. down) and a restricted row has a negative
/// (positive) coefficient for the column, then this row imposes a bound on how
/// much the sample value of the column can change. Such a row with constant
/// term c and coefficient f for the column imposes a bound of c/|f| on the
/// change in sample value (in the specified direction). (note that c is
/// non-negative here since the row is restricted and the tableau is consistent)
///
/// We iterate through the rows and pick the row which imposes the most
/// stringent bound, since pivoting with a row changes the row's sample value to
/// 0 and hence saturates the bound it imposes. We break ties between rows that
/// impose the same bound by considering a lexicographic ordering where we
/// prefer unknowns with lower index value.
std::optional<unsigned> Simplex::findPivotRow(std::optional<unsigned> skipRow,
                                              Direction direction,
                                              unsigned col) const {}

bool SimplexBase::isEmpty() const {}

void SimplexBase::swapRows(unsigned i, unsigned j) {}

void SimplexBase::swapColumns(unsigned i, unsigned j) {}

/// Mark this tableau empty and push an entry to the undo stack.
void SimplexBase::markEmpty() {}

/// Add an inequality to the tableau. If coeffs is c_0, c_1, ... c_n, where n
/// is the current number of variables, then the corresponding inequality is
/// c_n + c_0*x_0 + c_1*x_1 + ... + c_{n-1}*x_{n-1} >= 0.
///
/// We add the inequality and mark it as restricted. We then try to make its
/// sample value non-negative. If this is not possible, the tableau has become
/// empty and we mark it as such.
void Simplex::addInequality(ArrayRef<DynamicAPInt> coeffs) {}

/// Add an equality to the tableau. If coeffs is c_0, c_1, ... c_n, where n
/// is the current number of variables, then the corresponding equality is
/// c_n + c_0*x_0 + c_1*x_1 + ... + c_{n-1}*x_{n-1} == 0.
///
/// We simply add two opposing inequalities, which force the expression to
/// be zero.
void SimplexBase::addEquality(ArrayRef<DynamicAPInt> coeffs) {}

unsigned SimplexBase::getNumVariables() const {}
unsigned SimplexBase::getNumConstraints() const {}

/// Return a snapshot of the current state. This is just the current size of the
/// undo log.
unsigned SimplexBase::getSnapshot() const {}

unsigned SimplexBase::getSnapshotBasis() {}

void SimplexBase::removeLastConstraintRowOrientation() {}

// This doesn't find a pivot row only if the column has zero
// coefficients for every row.
//
// If the unknown is a constraint, this can't happen, since it was added
// initially as a row. Such a row could never have been pivoted to a column. So
// a pivot row will always be found if we have a constraint.
//
// If we have a variable, then the column has zero coefficients for every row
// iff no constraints have been added with a non-zero coefficient for this row.
std::optional<unsigned> SimplexBase::findAnyPivotRow(unsigned col) {}

// It's not valid to remove the constraint by deleting the column since this
// would result in an invalid basis.
void Simplex::undoLastConstraint() {}

// It's not valid to remove the constraint by deleting the column since this
// would result in an invalid basis.
void LexSimplexBase::undoLastConstraint() {}

void SimplexBase::undo(UndoLogEntry entry) {}

/// Rollback to the specified snapshot.
///
/// We undo all the log entries until the log size when the snapshot was taken
/// is reached.
void SimplexBase::rollback(unsigned snapshot) {}

/// We add the usual floor division constraints:
/// `0 <= coeffs - denom*q <= denom - 1`, where `q` is the new division
/// variable.
///
/// This constrains the remainder `coeffs - denom*q` to be in the
/// range `[0, denom - 1]`, which fixes the integer value of the quotient `q`.
void SimplexBase::addDivisionVariable(ArrayRef<DynamicAPInt> coeffs,
                                      const DynamicAPInt &denom) {}

void SimplexBase::appendVariable(unsigned count) {}

/// Add all the constraints from the given IntegerRelation.
void SimplexBase::intersectIntegerRelation(const IntegerRelation &rel) {}

MaybeOptimum<Fraction> Simplex::computeRowOptimum(Direction direction,
                                                  unsigned row) {}

/// Compute the optimum of the specified expression in the specified direction,
/// or std::nullopt if it is unbounded.
MaybeOptimum<Fraction> Simplex::computeOptimum(Direction direction,
                                               ArrayRef<DynamicAPInt> coeffs) {}

MaybeOptimum<Fraction> Simplex::computeOptimum(Direction direction,
                                               Unknown &u) {}

bool Simplex::isBoundedAlongConstraint(unsigned constraintIndex) {}

/// Redundant constraints are those that are in row orientation and lie in
/// rows 0 to nRedundant - 1.
bool Simplex::isMarkedRedundant(unsigned constraintIndex) const {}

/// Mark the specified row redundant.
///
/// This is done by moving the unknown to the end of the block of redundant
/// rows (namely, to row nRedundant) and incrementing nRedundant to
/// accomodate the new redundant row.
void Simplex::markRowRedundant(Unknown &u) {}

/// Find a subset of constraints that is redundant and mark them redundant.
void Simplex::detectRedundant(unsigned offset, unsigned count) {}

bool Simplex::isUnbounded() {}

/// Make a tableau to represent a pair of points in the original tableau.
///
/// The product constraints and variables are stored as: first A's, then B's.
///
/// The product tableau has row layout:
///   A's redundant rows, B's redundant rows, A's other rows, B's other rows.
///
/// It has column layout:
///   denominator, constant, A's columns, B's columns.
Simplex Simplex::makeProduct(const Simplex &a, const Simplex &b) {}

std::optional<SmallVector<Fraction, 8>> Simplex::getRationalSample() const {}

void LexSimplexBase::addInequality(ArrayRef<DynamicAPInt> coeffs) {}

MaybeOptimum<SmallVector<Fraction, 8>> LexSimplex::getRationalSample() const {}

std::optional<SmallVector<DynamicAPInt, 8>>
Simplex::getSamplePointIfIntegral() const {}

/// Given a simplex for a polytope, construct a new simplex whose variables are
/// identified with a pair of points (x, y) in the original polytope. Supports
/// some operations needed for generalized basis reduction. In what follows,
/// dotProduct(x, y) = x_1 * y_1 + x_2 * y_2 + ... x_n * y_n where n is the
/// dimension of the original polytope.
///
/// This supports adding equality constraints dotProduct(dir, x - y) == 0. It
/// also supports rolling back this addition, by maintaining a snapshot stack
/// that contains a snapshot of the Simplex's state for each equality, just
/// before that equality was added.
class presburger::GBRSimplex {};

/// Reduce the basis to try and find a direction in which the polytope is
/// "thin". This only works for bounded polytopes.
///
/// This is an implementation of the algorithm described in the paper
/// "An Implementation of Generalized Basis Reduction for Integer Programming"
/// by W. Cook, T. Rutherford, H. E. Scarf, D. Shallcross.
///
/// Let b_{level}, b_{level + 1}, ... b_n be the current basis.
/// Let width_i(v) = max <v, x - y> where x and y are points in the original
/// polytope such that <b_j, x - y> = 0 is satisfied for all level <= j < i.
///
/// In every iteration, we first replace b_{i+1} with b_{i+1} + u*b_i, where u
/// is the integer such that width_i(b_{i+1} + u*b_i) is minimized. Let dual_i
/// be the dual variable associated with the constraint <b_i, x - y> = 0 when
/// computing width_{i+1}(b_{i+1}). It can be shown that dual_i is the
/// minimizing value of u, if it were allowed to be fractional. Due to
/// convexity, the minimizing integer value is either floor(dual_i) or
/// ceil(dual_i), so we just need to check which of these gives a lower
/// width_{i+1} value. If dual_i turned out to be an integer, then u = dual_i.
///
/// Now if width_i(b_{i+1}) < 0.75 * width_i(b_i), we swap b_i and (the new)
/// b_{i + 1} and decrement i (unless i = level, in which case we stay at the
/// same i). Otherwise, we increment i.
///
/// We keep f values and duals cached and invalidate them when necessary.
/// Whenever possible, we use them instead of recomputing them. We implement the
/// algorithm as follows.
///
/// In an iteration at i we need to compute:
///   a) width_i(b_{i + 1})
///   b) width_i(b_i)
///   c) the integer u that minimizes width_i(b_{i + 1} + u*b_i)
///
/// If width_i(b_i) is not already cached, we compute it.
///
/// If the duals are not already cached, we compute width_{i+1}(b_{i+1}) and
/// store the duals from this computation.
///
/// We call updateBasisWithUAndGetFCandidate, which finds the minimizing value
/// of u as explained before, caches the duals from this computation, sets
/// b_{i+1} to b_{i+1} + u*b_i, and returns the new value of width_i(b_{i+1}).
///
/// Now if width_i(b_{i+1}) < 0.75 * width_i(b_i), we swap b_i and b_{i+1} and
/// decrement i, resulting in the basis
/// ... b_{i - 1}, b_{i + 1} + u*b_i, b_i, b_{i+2}, ...
/// with corresponding f values
/// ... width_{i-1}(b_{i-1}), width_i(b_{i+1} + u*b_i), width_{i+1}(b_i), ...
/// The values up to i - 1 remain unchanged. We have just gotten the middle
/// value from updateBasisWithUAndGetFCandidate, so we can update that in the
/// cache. The value at width_{i+1}(b_i) is unknown, so we evict this value from
/// the cache. The iteration after decrementing needs exactly the duals from the
/// computation of width_i(b_{i + 1} + u*b_i), so we keep these in the cache.
///
/// When incrementing i, no cached f values get invalidated. However, the cached
/// duals do get invalidated as the duals for the higher levels are different.
void Simplex::reduceBasis(IntMatrix &basis, unsigned level) {}

/// Search for an integer sample point using a branch and bound algorithm.
///
/// Each row in the basis matrix is a vector, and the set of basis vectors
/// should span the space. Initially this is the identity matrix,
/// i.e., the basis vectors are just the variables.
///
/// In every level, a value is assigned to the level-th basis vector, as
/// follows. Compute the minimum and maximum rational values of this direction.
/// If only one integer point lies in this range, constrain the variable to
/// have this value and recurse to the next variable.
///
/// If the range has multiple values, perform generalized basis reduction via
/// reduceBasis and then compute the bounds again. Now we try constraining
/// this direction in the first value in this range and "recurse" to the next
/// level. If we fail to find a sample, we try assigning the direction the next
/// value in this range, and so on.
///
/// If no integer sample is found from any of the assignments, or if the range
/// contains no integer value, then of course the polytope is empty for the
/// current assignment of the values in previous levels, so we return to
/// the previous level.
///
/// If we reach the last level where all the variables have been assigned values
/// already, then we simply return the current sample point if it is integral,
/// and go back to the previous level otherwise.
///
/// To avoid potentially arbitrarily large recursion depths leading to stack
/// overflows, this algorithm is implemented iteratively.
std::optional<SmallVector<DynamicAPInt, 8>> Simplex::findIntegerSample() {}

/// Compute the minimum and maximum integer values the expression can take. We
/// compute each separately.
std::pair<MaybeOptimum<DynamicAPInt>, MaybeOptimum<DynamicAPInt>>
Simplex::computeIntegerBounds(ArrayRef<DynamicAPInt> coeffs) {}

bool Simplex::isFlatAlong(ArrayRef<DynamicAPInt> coeffs) {}

void SimplexBase::print(raw_ostream &os) const {}

void SimplexBase::dump() const {}

bool Simplex::isRationalSubsetOf(const IntegerRelation &rel) {}

/// Returns the type of the inequality with coefficients `coeffs`.
/// Possible types are:
/// Redundant   The inequality is satisfied by all points in the polytope
/// Cut         The inequality is satisfied by some points, but not by others
/// Separate    The inequality is not satisfied by any point
///
/// Internally, this computes the minimum and the maximum the inequality with
/// coefficients `coeffs` can take. If the minimum is >= 0, the inequality holds
/// for all points in the polytope, so it is redundant.  If the minimum is <= 0
/// and the maximum is >= 0, the points in between the minimum and the
/// inequality do not satisfy it, the points in between the inequality and the
/// maximum satisfy it. Hence, it is a cut inequality. If both are < 0, no
/// points of the polytope satisfy the inequality, which means it is a separate
/// inequality.
Simplex::IneqType Simplex::findIneqType(ArrayRef<DynamicAPInt> coeffs) {}

/// Checks whether the type of the inequality with coefficients `coeffs`
/// is Redundant.
bool Simplex::isRedundantInequality(ArrayRef<DynamicAPInt> coeffs) {}

/// Check whether the equality given by `coeffs == 0` is redundant given
/// the existing constraints. This is redundant when `coeffs` is already
/// always zero under the existing constraints. `coeffs` is always zero
/// when the minimum and maximum value that `coeffs` can take are both zero.
bool Simplex::isRedundantEquality(ArrayRef<DynamicAPInt> coeffs) {}