MLIR  21.0.0git
IntegerRelation.h
Go to the documentation of this file.
1 //===- IntegerRelation.h - MLIR IntegerRelation Class ---------*- C++ -*---===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // A class to represent a relation over integer tuples. A relation is
10 // represented as a constraint system over a space of tuples of integer valued
11 // variables supporting symbolic variables and existential quantification.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef MLIR_ANALYSIS_PRESBURGER_INTEGERRELATION_H
16 #define MLIR_ANALYSIS_PRESBURGER_INTEGERRELATION_H
17 
22 #include "llvm/ADT/DynamicAPInt.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/Support/LogicalResult.h"
25 #include <optional>
26 
27 namespace mlir {
28 namespace presburger {
29 using llvm::DynamicAPInt;
30 using llvm::failure;
31 using llvm::int64fromDynamicAPInt;
32 using llvm::LogicalResult;
34 using llvm::success;
35 
36 class IntegerRelation;
37 class IntegerPolyhedron;
38 class PresburgerSet;
39 class PresburgerRelation;
40 struct SymbolicLexOpt;
41 
42 /// The type of bound: equal, lower bound or upper bound.
43 enum class BoundType { EQ, LB, UB };
44 
45 /// An IntegerRelation represents the set of points from a PresburgerSpace that
46 /// satisfy a list of affine constraints. Affine constraints can be inequalities
47 /// or equalities in the form:
48 ///
49 /// Inequality: c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} + c_n >= 0
50 /// Equality : c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} + c_n == 0
51 ///
52 /// where c_0, c_1, ..., c_n are integers and n is the total number of
53 /// variables in the space.
54 ///
55 /// Such a relation corresponds to the set of integer points lying in a convex
56 /// polyhedron. For example, consider the relation:
57 /// (x) -> (y) : (1 <= x <= 7, x = 2y)
58 /// These can be thought of as points in the polyhedron:
59 /// (x, y) : (1 <= x <= 7, x = 2y)
60 /// This relation contains the pairs (2, 1), (4, 2), and (6, 3).
61 ///
62 /// Since IntegerRelation makes a distinction between dimensions, VarKind::Range
63 /// and VarKind::Domain should be used to refer to dimension variables.
65 public:
66  /// All derived classes of IntegerRelation.
67  enum class Kind {
74  };
75 
76  /// Constructs a relation reserving memory for the specified number
77  /// of constraints and variables.
78  IntegerRelation(unsigned numReservedInequalities,
79  unsigned numReservedEqualities, unsigned numReservedCols,
80  const PresburgerSpace &space)
81  : space(space), equalities(0, space.getNumVars() + 1,
82  numReservedEqualities, numReservedCols),
83  inequalities(0, space.getNumVars() + 1, numReservedInequalities,
84  numReservedCols) {
85  assert(numReservedCols >= space.getNumVars() + 1);
86  }
87 
88  /// Constructs a relation with the specified number of dimensions and symbols.
90  : IntegerRelation(/*numReservedInequalities=*/0,
91  /*numReservedEqualities=*/0,
92  /*numReservedCols=*/space.getNumVars() + 1, space) {}
93 
94  virtual ~IntegerRelation() = default;
95 
96  /// Return a system with no constraints, i.e., one which is satisfied by all
97  /// points.
99  return IntegerRelation(space);
100  }
101 
102  /// Return an empty system containing an invalid equation 0 = 1.
104  IntegerRelation result(0, 1, space.getNumVars() + 1, space);
105  SmallVector<int64_t> invalidEq(space.getNumVars() + 1, 0);
106  invalidEq.back() = 1;
107  result.addEquality(invalidEq);
108  return result;
109  }
110 
111  /// Return the kind of this IntegerRelation.
112  virtual Kind getKind() const { return Kind::IntegerRelation; }
113 
114  static bool classof(const IntegerRelation *cst) { return true; }
115 
116  // Clones this object.
117  std::unique_ptr<IntegerRelation> clone() const;
118 
119  /// Returns a reference to the underlying space.
120  const PresburgerSpace &getSpace() const { return space; }
121 
122  /// Set the space to `oSpace`, which should have the same number of ids as
123  /// the current space.
124  void setSpace(const PresburgerSpace &oSpace);
125 
126  /// Set the space to `oSpace`, which should not have any local ids.
127  /// `oSpace` can have fewer ids than the current space; in that case, the
128  /// the extra ids in `this` that are not accounted for by `oSpace` will be
129  /// considered as local ids. `oSpace` should not have more ids than the
130  /// current space; this will result in an assert failure.
131  void setSpaceExceptLocals(const PresburgerSpace &oSpace);
132 
133  /// Set the identifier for the ith variable of the specified kind of the
134  /// IntegerRelation's PresburgerSpace. The index is relative to the kind of
135  /// the variable.
136  void setId(VarKind kind, unsigned i, Identifier id);
137 
138  void resetIds() { space.resetIds(); }
139 
140  /// Get the identifiers for the variables of specified varKind. Calls resetIds
141  /// on the relations space if identifiers are not enabled.
143 
144  /// Returns a copy of the space without locals.
149  }
150 
151  /// Appends constraints from `other` into `this`. This is equivalent to an
152  /// intersection with no simplification of any sort attempted.
153  void append(const IntegerRelation &other);
154 
155  /// Finds an equality that equates the specified variable to a constant.
156  /// Returns the position of the equality row. If 'symbolic' is set to true,
157  /// symbols are also treated like a constant, i.e., an affine function of the
158  /// symbols is also treated like a constant. Returns -1 if such an equality
159  /// could not be found.
160  int findEqualityToConstant(unsigned pos, bool symbolic = false) const;
161 
162  /// Return the intersection of the two relations.
163  /// If there are locals, they will be merged.
165 
166  /// Return whether `this` and `other` are equal. This is integer-exact
167  /// and somewhat expensive, since it uses the integer emptiness check
168  /// (see IntegerRelation::findIntegerSample()).
169  bool isEqual(const IntegerRelation &other) const;
170 
171  /// Perform a quick equality check on `this` and `other`. The relations are
172  /// equal if the check return true, but may or may not be equal if the check
173  /// returns false. The equality check is performed in a plain manner, by
174  /// comparing if all the equalities and inequalities in `this` and `other`
175  /// are the same.
176  bool isObviouslyEqual(const IntegerRelation &other) const;
177 
178  /// Return whether this is a subset of the given IntegerRelation. This is
179  /// integer-exact and somewhat expensive, since it uses the integer emptiness
180  /// check (see IntegerRelation::findIntegerSample()).
181  bool isSubsetOf(const IntegerRelation &other) const;
182 
183  /// Returns the value at the specified equality row and column.
184  inline DynamicAPInt atEq(unsigned i, unsigned j) const {
185  return equalities(i, j);
186  }
187  /// The same, but casts to int64_t. This is unsafe and will assert-fail if the
188  /// value does not fit in an int64_t.
189  inline int64_t atEq64(unsigned i, unsigned j) const {
190  return int64_t(equalities(i, j));
191  }
192  inline DynamicAPInt &atEq(unsigned i, unsigned j) { return equalities(i, j); }
193 
194  /// Returns the value at the specified inequality row and column.
195  inline DynamicAPInt atIneq(unsigned i, unsigned j) const {
196  return inequalities(i, j);
197  }
198  /// The same, but casts to int64_t. This is unsafe and will assert-fail if the
199  /// value does not fit in an int64_t.
200  inline int64_t atIneq64(unsigned i, unsigned j) const {
201  return int64_t(inequalities(i, j));
202  }
203  inline DynamicAPInt &atIneq(unsigned i, unsigned j) {
204  return inequalities(i, j);
205  }
206 
207  unsigned getNumConstraints() const {
209  }
210 
211  unsigned getNumDomainVars() const { return space.getNumDomainVars(); }
212  unsigned getNumRangeVars() const { return space.getNumRangeVars(); }
213  unsigned getNumSymbolVars() const { return space.getNumSymbolVars(); }
214  unsigned getNumLocalVars() const { return space.getNumLocalVars(); }
215 
216  unsigned getNumDimVars() const { return space.getNumDimVars(); }
217  unsigned getNumDimAndSymbolVars() const {
218  return space.getNumDimAndSymbolVars();
219  }
220  unsigned getNumVars() const { return space.getNumVars(); }
221 
222  /// Returns the number of columns in the constraint system.
223  inline unsigned getNumCols() const { return space.getNumVars() + 1; }
224 
225  inline unsigned getNumEqualities() const { return equalities.getNumRows(); }
226 
227  inline unsigned getNumInequalities() const {
228  return inequalities.getNumRows();
229  }
230 
231  inline unsigned getNumReservedEqualities() const {
233  }
234 
235  inline unsigned getNumReservedInequalities() const {
237  }
238 
239  inline ArrayRef<DynamicAPInt> getEquality(unsigned idx) const {
240  return equalities.getRow(idx);
241  }
242  inline ArrayRef<DynamicAPInt> getInequality(unsigned idx) const {
243  return inequalities.getRow(idx);
244  }
245  /// The same, but casts to int64_t. This is unsafe and will assert-fail if the
246  /// value does not fit in an int64_t.
247  inline SmallVector<int64_t, 8> getEquality64(unsigned idx) const {
248  return getInt64Vec(equalities.getRow(idx));
249  }
250  inline SmallVector<int64_t, 8> getInequality64(unsigned idx) const {
251  return getInt64Vec(inequalities.getRow(idx));
252  }
253 
254  inline IntMatrix getInequalities() const { return inequalities; }
255 
256  /// Get the number of vars of the specified kind.
257  unsigned getNumVarKind(VarKind kind) const {
258  return space.getNumVarKind(kind);
259  }
260 
261  /// Return the index at which the specified kind of vars starts.
262  unsigned getVarKindOffset(VarKind kind) const {
263  return space.getVarKindOffset(kind);
264  }
265 
266  /// Return the index at Which the specified kind of vars ends.
267  unsigned getVarKindEnd(VarKind kind) const {
268  return space.getVarKindEnd(kind);
269  }
270 
271  /// Get the number of elements of the specified kind in the range
272  /// [varStart, varLimit).
273  unsigned getVarKindOverlap(VarKind kind, unsigned varStart,
274  unsigned varLimit) const {
275  return space.getVarKindOverlap(kind, varStart, varLimit);
276  }
277 
278  /// Return the VarKind of the var at the specified position.
279  VarKind getVarKindAt(unsigned pos) const { return space.getVarKindAt(pos); }
280 
281  /// The struct CountsSnapshot stores the count of each VarKind, and also of
282  /// each constraint type. getCounts() returns a CountsSnapshot object
283  /// describing the current state of the IntegerRelation. truncate() truncates
284  /// all vars of each VarKind and all constraints of both kinds beyond the
285  /// counts in the specified CountsSnapshot object. This can be used to achieve
286  /// rudimentary rollback support. As long as none of the existing constraints
287  /// or vars are disturbed, and only additional vars or constraints are added,
288  /// this addition can be rolled back using truncate.
289  struct CountsSnapshot {
290  public:
291  CountsSnapshot(const PresburgerSpace &space, unsigned numIneqs,
292  unsigned numEqs)
293  : space(space), numIneqs(numIneqs), numEqs(numEqs) {}
294  const PresburgerSpace &getSpace() const { return space; };
295  unsigned getNumIneqs() const { return numIneqs; }
296  unsigned getNumEqs() const { return numEqs; }
297 
298  private:
299  PresburgerSpace space;
300  unsigned numIneqs, numEqs;
301  };
302  CountsSnapshot getCounts() const;
303  void truncate(const CountsSnapshot &counts);
304 
305  /// Insert `num` variables of the specified kind at position `pos`.
306  /// Positions are relative to the kind of variable. The coefficient columns
307  /// corresponding to the added variables are initialized to zero. Return the
308  /// absolute column position (i.e., not relative to the kind of variable)
309  /// of the first added variable.
310  virtual unsigned insertVar(VarKind kind, unsigned pos, unsigned num = 1);
311 
312  /// Append `num` variables of the specified kind after the last variable
313  /// of that kind. The coefficient columns corresponding to the added variables
314  /// are initialized to zero. Return the absolute column position (i.e., not
315  /// relative to the kind of variable) of the first appended variable.
316  unsigned appendVar(VarKind kind, unsigned num = 1);
317 
318  /// Adds an inequality (>= 0) from the coefficients specified in `inEq`.
322  }
323  /// Adds an equality from the coefficients specified in `eq`.
327  }
328 
329  /// Eliminate the `posB^th` local variable, replacing every instance of it
330  /// with the `posA^th` local variable. This should be used when the two
331  /// local variables are known to always take the same values.
332  virtual void eliminateRedundantLocalVar(unsigned posA, unsigned posB);
333 
334  /// Removes variables of the specified kind with the specified pos (or
335  /// within the specified range) from the system. The specified location is
336  /// relative to the first variable of the specified kind.
337  void removeVar(VarKind kind, unsigned pos);
338  virtual void removeVarRange(VarKind kind, unsigned varStart,
339  unsigned varLimit);
340 
341  /// Removes the specified variable from the system.
342  void removeVar(unsigned pos);
343 
344  void removeEquality(unsigned pos);
345  void removeInequality(unsigned pos);
346 
347  /// Remove the (in)equalities at positions [start, end).
348  void removeEqualityRange(unsigned start, unsigned end);
349  void removeInequalityRange(unsigned start, unsigned end);
350 
351  /// Get the lexicographically minimum rational point satisfying the
352  /// constraints. Returns an empty optional if the relation is empty or if
353  /// the lexmin is unbounded. Symbols are not supported and will result in
354  /// assert-failure. Note that Domain is minimized first, then range.
356 
357  /// Same as above, but returns lexicographically minimal integer point.
358  /// Note: this should be used only when the lexmin is really required.
359  /// For a generic integer sampling operation, findIntegerSample is more
360  /// robust and should be preferred. Note that Domain is minimized first, then
361  /// range.
363 
364  /// Swap the posA^th variable with the posB^th variable.
365  virtual void swapVar(unsigned posA, unsigned posB);
366 
367  /// Removes all equalities and inequalities.
368  void clearConstraints();
369 
370  /// Sets the `values.size()` variables starting at `po`s to the specified
371  /// values and removes them.
372  void setAndEliminate(unsigned pos, ArrayRef<DynamicAPInt> values);
373  void setAndEliminate(unsigned pos, ArrayRef<int64_t> values) {
374  setAndEliminate(pos, getDynamicAPIntVec(values));
375  }
376 
377  /// Replaces the contents of this IntegerRelation with `other`.
378  virtual void clearAndCopyFrom(const IntegerRelation &other);
379 
380  /// Gather positions of all lower and upper bounds of the variable at `pos`,
381  /// and optionally any equalities on it. In addition, the bounds are to be
382  /// independent of variables in position range [`offset`, `offset` + `num`).
383  void
384  getLowerAndUpperBoundIndices(unsigned pos,
385  SmallVectorImpl<unsigned> *lbIndices,
386  SmallVectorImpl<unsigned> *ubIndices,
387  SmallVectorImpl<unsigned> *eqIndices = nullptr,
388  unsigned offset = 0, unsigned num = 0) const;
389 
390  /// Checks for emptiness by performing variable elimination on all
391  /// variables, running the GCD test on each equality constraint, and
392  /// checking for invalid constraints. Returns true if the GCD test fails for
393  /// any equality, or if any invalid constraints are discovered on any row.
394  /// Returns false otherwise.
395  bool isEmpty() const;
396 
397  /// Performs GCD checks and invalid constraint checks.
398  bool isObviouslyEmpty() const;
399 
400  /// Runs the GCD test on all equality constraints. Returns true if this test
401  /// fails on any equality. Returns false otherwise.
402  /// This test can be used to disprove the existence of a solution. If it
403  /// returns true, no integer solution to the equality constraints can exist.
404  bool isEmptyByGCDTest() const;
405 
406  /// Returns true if the set of constraints is found to have no solution,
407  /// false if a solution exists. Uses the same algorithm as
408  /// `findIntegerSample`.
409  bool isIntegerEmpty() const;
410 
411  /// Returns a matrix where each row is a vector along which the polytope is
412  /// bounded. The span of the returned vectors is guaranteed to contain all
413  /// such vectors. The returned vectors are NOT guaranteed to be linearly
414  /// independent. This function should not be called on empty sets.
416 
417  /// Find an integer sample point satisfying the constraints using a
418  /// branch and bound algorithm with generalized basis reduction, with some
419  /// additional processing using Simplex for unbounded sets.
420  ///
421  /// Returns an integer sample point if one exists, or an empty Optional
422  /// otherwise. The returned value also includes values of local ids.
423  std::optional<SmallVector<DynamicAPInt, 8>> findIntegerSample() const;
424 
425  /// Compute an overapproximation of the number of integer points in the
426  /// relation. Symbol vars currently not supported. If the computed
427  /// overapproximation is infinite, an empty optional is returned.
428  std::optional<DynamicAPInt> computeVolume() const;
429 
430  /// Returns true if the given point satisfies the constraints, or false
431  /// otherwise. Takes the values of all vars including locals.
432  bool containsPoint(ArrayRef<DynamicAPInt> point) const;
433  bool containsPoint(ArrayRef<int64_t> point) const {
434  return containsPoint(getDynamicAPIntVec(point));
435  }
436  /// Given the values of non-local vars, return a satisfying assignment to the
437  /// local if one exists, or an empty optional otherwise.
438  std::optional<SmallVector<DynamicAPInt, 8>>
440  std::optional<SmallVector<DynamicAPInt, 8>>
443  }
444 
445  /// Returns a `DivisonRepr` representing the division representation of local
446  /// variables in the constraint system.
447  ///
448  /// If `repr` is not `nullptr`, the equality and pairs of inequality
449  /// constraints identified by their position indices using which an explicit
450  /// representation for each local variable can be computed are set in `repr`
451  /// in the form of a `MaybeLocalRepr` struct. If no such inequality
452  /// pair/equality can be found, the kind attribute in `MaybeLocalRepr` is set
453  /// to None.
454  DivisionRepr getLocalReprs(std::vector<MaybeLocalRepr> *repr = nullptr) const;
455 
456  /// Adds a constant bound for the specified variable.
457  void addBound(BoundType type, unsigned pos, const DynamicAPInt &value);
458  void addBound(BoundType type, unsigned pos, int64_t value) {
459  addBound(type, pos, DynamicAPInt(value));
460  }
461 
462  /// Adds a constant bound for the specified expression.
463  void addBound(BoundType type, ArrayRef<DynamicAPInt> expr,
464  const DynamicAPInt &value);
465  void addBound(BoundType type, ArrayRef<int64_t> expr, int64_t value) {
466  addBound(type, getDynamicAPIntVec(expr), DynamicAPInt(value));
467  }
468 
469  /// Adds a new local variable as the floordiv of an affine function of other
470  /// variables, the coefficients of which are provided in `dividend` and with
471  /// respect to a positive constant `divisor`. Two constraints are added to the
472  /// system to capture equivalence with the floordiv:
473  /// q = dividend floordiv c <=> c*q <= dividend <= c*q + c - 1.
475  const DynamicAPInt &divisor);
476  void addLocalFloorDiv(ArrayRef<int64_t> dividend, int64_t divisor) {
477  addLocalFloorDiv(getDynamicAPIntVec(dividend), DynamicAPInt(divisor));
478  }
479 
480  /// Projects out (aka eliminates) `num` variables starting at position
481  /// `pos`. The resulting constraint system is the shadow along the dimensions
482  /// that still exist. This method may not always be integer exact.
483  // TODO: deal with integer exactness when necessary - can return a value to
484  // mark exactness for example.
485  void projectOut(unsigned pos, unsigned num);
486  inline void projectOut(unsigned pos) { return projectOut(pos, 1); }
487 
488  /// Tries to fold the specified variable to a constant using a trivial
489  /// equality detection; if successful, the constant is substituted for the
490  /// variable everywhere in the constraint system and then removed from the
491  /// system.
492  LogicalResult constantFoldVar(unsigned pos);
493 
494  /// This method calls `constantFoldVar` for the specified range of variables,
495  /// `num` variables starting at position `pos`.
496  void constantFoldVarRange(unsigned pos, unsigned num);
497 
498  /// Updates the constraints to be the smallest bounding (enclosing) box that
499  /// contains the points of `this` set and that of `other`, with the symbols
500  /// being treated specially. For each of the dimensions, the min of the lower
501  /// bounds (symbolic) and the max of the upper bounds (symbolic) is computed
502  /// to determine such a bounding box. `other` is expected to have the same
503  /// dimensional variables as this constraint system (in the same order).
504  ///
505  /// E.g.:
506  /// 1) this = {0 <= d0 <= 127},
507  /// other = {16 <= d0 <= 192},
508  /// output = {0 <= d0 <= 192}
509  /// 2) this = {s0 + 5 <= d0 <= s0 + 20},
510  /// other = {s0 + 1 <= d0 <= s0 + 9},
511  /// output = {s0 + 1 <= d0 <= s0 + 20}
512  /// 3) this = {0 <= d0 <= 5, 1 <= d1 <= 9}
513  /// other = {2 <= d0 <= 6, 5 <= d1 <= 15},
514  /// output = {0 <= d0 <= 6, 1 <= d1 <= 15}
515  LogicalResult unionBoundingBox(const IntegerRelation &other);
516 
517  /// Returns the smallest known constant bound for the extent of the specified
518  /// variable (pos^th), i.e., the smallest known constant that is greater
519  /// than or equal to 'exclusive upper bound' - 'lower bound' of the
520  /// variable. This constant bound is guaranteed to be non-negative. Returns
521  /// std::nullopt if it's not a constant. This method employs trivial (low
522  /// complexity / cost) checks and detection. Symbolic variables are treated
523  /// specially, i.e., it looks for constant differences between affine
524  /// expressions involving only the symbolic variables. `lb` and `ub` (along
525  /// with the `boundFloorDivisor`) are set to represent the lower and upper
526  /// bound associated with the constant difference: `lb`, `ub` have the
527  /// coefficients, and `boundFloorDivisor`, their divisor. `minLbPos` and
528  /// `minUbPos` if non-null are set to the position of the constant lower bound
529  /// and upper bound respectively (to the same if they are from an
530  /// equality). Ex: if the lower bound is [(s0 + s2 - 1) floordiv 32] for a
531  /// system with three symbolic variables, *lb = [1, 0, 1], lbDivisor = 32. See
532  /// comments at function definition for examples.
533  std::optional<DynamicAPInt> getConstantBoundOnDimSize(
534  unsigned pos, SmallVectorImpl<DynamicAPInt> *lb = nullptr,
535  DynamicAPInt *boundFloorDivisor = nullptr,
536  SmallVectorImpl<DynamicAPInt> *ub = nullptr, unsigned *minLbPos = nullptr,
537  unsigned *minUbPos = nullptr) const;
538  /// The same, but casts to int64_t. This is unsafe and will assert-fail if the
539  /// value does not fit in an int64_t.
540  std::optional<int64_t> getConstantBoundOnDimSize64(
541  unsigned pos, SmallVectorImpl<int64_t> *lb = nullptr,
542  int64_t *boundFloorDivisor = nullptr,
543  SmallVectorImpl<int64_t> *ub = nullptr, unsigned *minLbPos = nullptr,
544  unsigned *minUbPos = nullptr) const {
545  SmallVector<DynamicAPInt, 8> ubDynamicAPInt, lbDynamicAPInt;
546  DynamicAPInt boundFloorDivisorDynamicAPInt;
547  std::optional<DynamicAPInt> result = getConstantBoundOnDimSize(
548  pos, &lbDynamicAPInt, &boundFloorDivisorDynamicAPInt, &ubDynamicAPInt,
549  minLbPos, minUbPos);
550  if (lb)
551  *lb = getInt64Vec(lbDynamicAPInt);
552  if (ub)
553  *ub = getInt64Vec(ubDynamicAPInt);
554  if (boundFloorDivisor)
555  *boundFloorDivisor = static_cast<int64_t>(boundFloorDivisorDynamicAPInt);
556  return llvm::transformOptional(result, int64fromDynamicAPInt);
557  }
558 
559  /// Returns the constant bound for the pos^th variable if there is one;
560  /// std::nullopt otherwise.
561  std::optional<DynamicAPInt> getConstantBound(BoundType type,
562  unsigned pos) const;
563  /// The same, but casts to int64_t. This is unsafe and will assert-fail if the
564  /// value does not fit in an int64_t.
565  std::optional<int64_t> getConstantBound64(BoundType type,
566  unsigned pos) const {
567  return llvm::transformOptional(getConstantBound(type, pos),
568  int64fromDynamicAPInt);
569  }
570 
571  /// Removes constraints that are independent of (i.e., do not have a
572  /// coefficient) variables in the range [pos, pos + num).
573  void removeIndependentConstraints(unsigned pos, unsigned num);
574 
575  /// Returns true if the set can be trivially detected as being
576  /// hyper-rectangular on the specified contiguous set of variables.
577  bool isHyperRectangular(unsigned pos, unsigned num) const;
578 
579  /// Removes duplicate constraints, trivially true constraints, and constraints
580  /// that can be detected as redundant as a result of differing only in their
581  /// constant term part. A constraint of the form <non-negative constant> >= 0
582  /// is considered trivially true. This method is a linear time method on the
583  /// constraints, does a single scan, and updates in place. It also normalizes
584  /// constraints by their GCD and performs GCD tightening on inequalities.
586 
587  /// A more expensive check than `removeTrivialRedundancy` to detect redundant
588  /// inequalities.
590 
591  /// Removes redundant constraints using Simplex. Although the algorithm can
592  /// theoretically take exponential time in the worst case (rare), it is known
593  /// to perform much better in the average case. If V is the number of vertices
594  /// in the polytope and C is the number of constraints, the algorithm takes
595  /// O(VC) time.
597 
598  void removeDuplicateDivs();
599 
600  /// Simplify the constraint system by removing canonicalizing constraints and
601  /// removing redundant constraints.
602  void simplify();
603 
604  /// Converts variables of kind srcKind in the range [varStart, varLimit) to
605  /// variables of kind dstKind. If `pos` is given, the variables are placed at
606  /// position `pos` of dstKind, otherwise they are placed after all the other
607  /// variables of kind dstKind. The internal ordering among the moved variables
608  /// is preserved.
609  void convertVarKind(VarKind srcKind, unsigned varStart, unsigned varLimit,
610  VarKind dstKind, unsigned pos);
611  void convertVarKind(VarKind srcKind, unsigned varStart, unsigned varLimit,
612  VarKind dstKind) {
613  convertVarKind(srcKind, varStart, varLimit, dstKind,
614  getNumVarKind(dstKind));
615  }
616  void convertToLocal(VarKind kind, unsigned varStart, unsigned varLimit) {
617  convertVarKind(kind, varStart, varLimit, VarKind::Local);
618  }
619 
620  /// Merge and align symbol variables of `this` and `other` with respect to
621  /// identifiers. After this operation the symbol variables of both relations
622  /// have the same identifiers in the same order.
624 
625  /// Adds additional local vars to the sets such that they both have the union
626  /// of the local vars in each set, without changing the set of points that
627  /// lie in `this` and `other`.
628  ///
629  /// While taking union, if a local var in `other` has a division
630  /// representation which is a duplicate of division representation, of another
631  /// local var, it is not added to the final union of local vars and is instead
632  /// merged. The new ordering of local vars is:
633  ///
634  /// [Local vars of `this`] [Non-merged local vars of `other`]
635  ///
636  /// The relative ordering of local vars is same as before.
637  ///
638  /// After merging, if the `i^th` local variable in one set has a known
639  /// division representation, then the `i^th` local variable in the other set
640  /// either has the same division representation or no known division
641  /// representation.
642  ///
643  /// The spaces of both relations should be compatible.
644  ///
645  /// Returns the number of non-merged local vars of `other`, i.e. the number of
646  /// locals that have been added to `this`.
647  unsigned mergeLocalVars(IntegerRelation &other);
648 
649  /// Check whether all local ids have a division representation.
650  bool hasOnlyDivLocals() const;
651 
652  /// Changes the partition between dimensions and symbols. Depending on the new
653  /// symbol count, either a chunk of dimensional variables immediately before
654  /// the split become symbols, or some of the symbols immediately after the
655  /// split become dimensions.
656  void setDimSymbolSeparation(unsigned newSymbolCount) {
657  space.setVarSymbolSeparation(newSymbolCount);
658  }
659 
660  /// Return a set corresponding to all points in the domain of the relation.
662 
663  /// Return a set corresponding to all points in the range of the relation.
665 
666  /// Intersect the given `poly` with the domain in-place.
667  ///
668  /// Formally, let the relation `this` be R: A -> B and poly is C, then this
669  /// operation modifies R to be (A intersection C) -> B.
670  void intersectDomain(const IntegerPolyhedron &poly);
671 
672  /// Intersect the given `poly` with the range in-place.
673  ///
674  /// Formally, let the relation `this` be R: A -> B and poly is C, then this
675  /// operation modifies R to be A -> (B intersection C).
676  void intersectRange(const IntegerPolyhedron &poly);
677 
678  /// Invert the relation i.e., swap its domain and range.
679  ///
680  /// Formally, let the relation `this` be R: A -> B, then this operation
681  /// modifies R to be B -> A.
682  void inverse();
683 
684  /// Let the relation `this` be R1, and the relation `rel` be R2. Modifies R1
685  /// to be the composition of R1 and R2: R1;R2.
686  ///
687  /// Formally, if R1: A -> B, and R2: B -> C, then this function returns a
688  /// relation R3: A -> C such that a point (a, c) belongs to R3 iff there
689  /// exists b such that (a, b) is in R1 and, (b, c) is in R2.
690  void compose(const IntegerRelation &rel);
691 
692  /// Given a relation `rel`, apply the relation to the domain of this relation.
693  ///
694  /// R1: i -> j : (0 <= i < 2, j = i)
695  /// R2: i -> k : (k = i floordiv 2)
696  /// R3: k -> j : (0 <= k < 1, 2k <= j <= 2k + 1)
697  ///
698  /// R1 = {(0, 0), (1, 1)}. R2 maps both 0 and 1 to 0.
699  /// So R3 = {(0, 0), (0, 1)}.
700  ///
701  /// Formally, R1.applyDomain(R2) = R2.inverse().compose(R1).
702  void applyDomain(const IntegerRelation &rel);
703 
704  /// Given a relation `rel`, apply the relation to the range of this relation.
705  ///
706  /// Formally, R1.applyRange(R2) is the same as R1.compose(R2) but we provide
707  /// this for uniformity with `applyDomain`.
708  void applyRange(const IntegerRelation &rel);
709 
710  /// Given a relation `other: (A -> B)`, this operation merges the symbol and
711  /// local variables and then takes the composition of `other` on `this: (B ->
712  /// C)`. The resulting relation represents tuples of the form: `A -> C`.
713  void mergeAndCompose(const IntegerRelation &other);
714 
715  /// Compute an equivalent representation of the same set, such that all local
716  /// vars in all disjuncts have division representations. This representation
717  /// may involve local vars that correspond to divisions, and may also be a
718  /// union of convex disjuncts.
720 
721  /// Compute the symbolic integer lexmin of the relation.
722  ///
723  /// This finds, for every assignment to the symbols and domain,
724  /// the lexicographically minimum value attained by the range.
725  ///
726  /// For example, the symbolic lexmin of the set
727  ///
728  /// (x, y)[a, b, c] : (a <= x, b <= x, x <= c)
729  ///
730  /// can be written as
731  ///
732  /// x = a if b <= a, a <= c
733  /// x = b if a < b, b <= c
734  ///
735  /// This function is stored in the `lexopt` function in the result.
736  /// Some assignments to the symbols might make the set empty.
737  /// Such points are not part of the function's domain.
738  /// In the above example, this happens when max(a, b) > c.
739  ///
740  /// For some values of the symbols, the lexmin may be unbounded.
741  /// `SymbolicLexOpt` stores these parts of the symbolic domain in a separate
742  /// `PresburgerSet`, `unboundedDomain`.
744 
745  /// Same as findSymbolicIntegerLexMin but produces lexmax instead of lexmin
747 
748  /// Finds a constraint with a non-zero coefficient at `colIdx` in equality
749  /// (isEq=true) or inequality (isEq=false) constraints. Returns the position
750  /// of the row if it was found or none otherwise.
751  std::optional<unsigned> findConstraintWithNonZeroAt(unsigned colIdx,
752  bool isEq) const;
753 
754  /// Return the set difference of this set and the given set, i.e.,
755  /// return `this \ set`.
757 
758  // Remove equalities which have only zero coefficients.
760 
761  // Verify whether the relation is full-dimensional, i.e.,
762  // no equality holds for the relation.
763  //
764  // If there are no variables, it always returns true.
765  // If there is at least one variable and the relation is empty, it returns
766  // false.
767  bool isFullDim();
768 
769  void print(raw_ostream &os) const;
770  void dump() const;
771 
772 protected:
773  /// Checks all rows of equality/inequality constraints for trivial
774  /// contradictions (for example: 1 == 0, 0 >= 1), which may have surfaced
775  /// after elimination. Returns true if an invalid constraint is found;
776  /// false otherwise.
777  bool hasInvalidConstraint() const;
778 
779  /// Returns the constant lower bound if isLower is true, and the upper
780  /// bound if isLower is false.
781  template <bool isLower>
782  std::optional<DynamicAPInt> computeConstantLowerOrUpperBound(unsigned pos);
783  /// The same, but casts to int64_t. This is unsafe and will assert-fail if the
784  /// value does not fit in an int64_t.
785  template <bool isLower>
786  std::optional<int64_t> computeConstantLowerOrUpperBound64(unsigned pos) {
787  return computeConstantLowerOrUpperBound<isLower>(pos).map(
788  int64fromDynamicAPInt);
789  }
790 
791  /// Eliminates a single variable at `position` from equality and inequality
792  /// constraints. Returns `success` if the variable was eliminated, and
793  /// `failure` otherwise.
794  inline LogicalResult gaussianEliminateVar(unsigned position) {
795  return success(gaussianEliminateVars(position, position + 1) == 1);
796  }
797 
798  /// Removes local variables using equalities. Each equality is checked if it
799  /// can be reduced to the form: `e = affine-expr`, where `e` is a local
800  /// variable and `affine-expr` is an affine expression not containing `e`.
801  /// If an equality satisfies this form, the local variable is replaced in
802  /// each constraint and then removed. The equality used to replace this local
803  /// variable is also removed.
805 
806  /// Eliminates variables from equality and inequality constraints
807  /// in column range [posStart, posLimit).
808  /// Returns the number of variables eliminated.
809  unsigned gaussianEliminateVars(unsigned posStart, unsigned posLimit);
810 
811  /// Perform a Gaussian elimination operation to reduce all equations to
812  /// standard form. Returns whether the constraint system was modified.
813  bool gaussianEliminate();
814 
815  /// Eliminates the variable at the specified position using Fourier-Motzkin
816  /// variable elimination, but uses Gaussian elimination if there is an
817  /// equality involving that variable. If the result of the elimination is
818  /// integer exact, `*isResultIntegerExact` is set to true. If `darkShadow` is
819  /// set to true, a potential under approximation (subset) of the rational
820  /// shadow / exact integer shadow is computed.
821  // See implementation comments for more details.
822  virtual void fourierMotzkinEliminate(unsigned pos, bool darkShadow = false,
823  bool *isResultIntegerExact = nullptr);
824 
825  /// Tightens inequalities given that we are dealing with integer spaces. This
826  /// is similar to the GCD test but applied to inequalities. The constant term
827  /// can be reduced to the preceding multiple of the GCD of the coefficients,
828  /// i.e.,
829  /// 64*i - 100 >= 0 => 64*i - 128 >= 0 (since 'i' is an integer). This is a
830  /// fast method (linear in the number of coefficients).
831  void gcdTightenInequalities();
832 
833  /// Normalized each constraints by the GCD of its coefficients.
835 
836  /// Returns true if the pos^th column is all zero for both inequalities and
837  /// equalities.
838  bool isColZero(unsigned pos) const;
839 
840  /// Checks for identical inequalities and eliminates redundant inequalities.
841  /// Returns whether the constraint system was modified.
843 
844  /// Returns false if the fields corresponding to various variable counts, or
845  /// equality/inequality buffer sizes aren't consistent; true otherwise. This
846  /// is meant to be used within an assert internally.
847  virtual bool hasConsistentState() const;
848 
849  /// Prints the number of constraints, dimensions, symbols and locals in the
850  /// IntegerRelation.
851  virtual void printSpace(raw_ostream &os) const;
852 
853  /// Removes variables in the column range [varStart, varLimit), and copies any
854  /// remaining valid data into place, updates member variables, and resizes
855  /// arrays as needed.
856  void removeVarRange(unsigned varStart, unsigned varLimit);
857 
858  /// Truncate the vars of the specified kind to the specified number by
859  /// dropping some vars at the end. `num` must be less than the current number.
860  void truncateVarKind(VarKind kind, unsigned num);
861 
862  /// Truncate the vars to the number in the space of the specified
863  /// CountsSnapshot.
864  void truncateVarKind(VarKind kind, const CountsSnapshot &counts);
865 
866  /// A parameter that controls detection of an unrealistic number of
867  /// constraints. If the number of constraints is this many times the number of
868  /// variables, we consider such a system out of line with the intended use
869  /// case of IntegerRelation.
870  // The rationale for 32 is that in the typical simplest of cases, an
871  // variable is expected to have one lower bound and one upper bound
872  // constraint. With a level of tiling or a connection to another variable
873  // through a div or mod, an extra pair of bounds gets added. As a limit, we
874  // don't expect a variable to have more than 32 lower/upper/equality
875  // constraints. This is conservatively set low and can be raised if needed.
876  constexpr static unsigned kExplosionFactor = 32;
877 
879 
880  /// Coefficients of affine equalities (in == 0 form).
882 
883  /// Coefficients of affine inequalities (in >= 0 form).
885 };
886 
887 /// An IntegerPolyhedron represents the set of points from a PresburgerSpace
888 /// that satisfy a list of affine constraints. Affine constraints can be
889 /// inequalities or equalities in the form:
890 ///
891 /// Inequality: c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} + c_n >= 0
892 /// Equality : c_0*x_0 + c_1*x_1 + .... + c_{n-1}*x_{n-1} + c_n == 0
893 ///
894 /// where c_0, c_1, ..., c_n are integers and n is the total number of
895 /// variables in the space.
896 ///
897 /// An IntegerPolyhedron is similar to an IntegerRelation but it does not make a
898 /// distinction between Domain and Range variables. Internally,
899 /// IntegerPolyhedron is implemented as a IntegerRelation with zero domain vars.
900 ///
901 /// Since IntegerPolyhedron does not make a distinction between kinds of
902 /// dimensions, VarKind::SetDim should be used to refer to dimension
903 /// variables.
905 public:
906  /// Constructs a set reserving memory for the specified number
907  /// of constraints and variables.
908  IntegerPolyhedron(unsigned numReservedInequalities,
909  unsigned numReservedEqualities, unsigned numReservedCols,
910  const PresburgerSpace &space)
911  : IntegerRelation(numReservedInequalities, numReservedEqualities,
912  numReservedCols, space) {
913  assert(space.getNumDomainVars() == 0 &&
914  "Number of domain vars should be zero in Set kind space.");
915  }
916 
917  /// Constructs a relation with the specified number of dimensions and
918  /// symbols.
920  : IntegerPolyhedron(/*numReservedInequalities=*/0,
921  /*numReservedEqualities=*/0,
922  /*numReservedCols=*/space.getNumVars() + 1, space) {}
923 
924  /// Constructs a relation with the specified number of dimensions and symbols
925  /// and adds the given inequalities.
927  const IntMatrix &inequalities)
929  for (unsigned i = 0, e = inequalities.getNumRows(); i < e; i++)
931  }
932 
933  /// Constructs a relation with the specified number of dimensions and symbols
934  /// and adds the given inequalities, after normalizing row-wise to integer
935  /// values.
937  const FracMatrix &inequalities)
939  IntMatrix ineqsNormalized = inequalities.normalizeRows();
940  for (unsigned i = 0, e = inequalities.getNumRows(); i < e; i++)
941  addInequality(ineqsNormalized.getRow(i));
942  }
943 
944  /// Construct a set from an IntegerRelation. The relation should have
945  /// no domain vars.
946  explicit IntegerPolyhedron(const IntegerRelation &rel)
947  : IntegerRelation(rel) {
948  assert(space.getNumDomainVars() == 0 &&
949  "Number of domain vars should be zero in Set kind space.");
950  }
951 
952  /// Construct a set from an IntegerRelation, but instead of creating a copy,
953  /// use move constructor. The relation should have no domain vars.
955  assert(space.getNumDomainVars() == 0 &&
956  "Number of domain vars should be zero in Set kind space.");
957  }
958 
959  /// Return a system with no constraints, i.e., one which is satisfied by all
960  /// points.
962  return IntegerPolyhedron(space);
963  }
964 
965  /// Return the kind of this IntegerRelation.
966  Kind getKind() const override { return Kind::IntegerPolyhedron; }
967 
968  static bool classof(const IntegerRelation *cst) {
969  return cst->getKind() >= Kind::IntegerPolyhedron &&
971  }
972 
973  // Clones this object.
974  std::unique_ptr<IntegerPolyhedron> clone() const;
975 
976  /// Insert `num` variables of the specified kind at position `pos`.
977  /// Positions are relative to the kind of variable. Return the absolute
978  /// column position (i.e., not relative to the kind of variable) of the
979  /// first added variable.
980  unsigned insertVar(VarKind kind, unsigned pos, unsigned num = 1) override;
981 
982  /// Return the intersection of the two relations.
983  /// If there are locals, they will be merged.
984  IntegerPolyhedron intersect(const IntegerPolyhedron &other) const;
985 
986  /// Return the set difference of this set and the given set, i.e.,
987  /// return `this \ set`.
988  PresburgerSet subtract(const PresburgerSet &other) const;
989 };
990 
991 } // namespace presburger
992 } // namespace mlir
993 
994 #endif // MLIR_ANALYSIS_PRESBURGER_INTEGERRELATION_H
union mlir::linalg::@1183::ArityGroupAndKind::Kind kind
Class storing division representation of local variables of a constraint system.
Definition: Utils.h:117
An Identifier stores a pointer to an object, such as a Value or an Operation.
An IntegerPolyhedron represents the set of points from a PresburgerSpace that satisfy a list of affin...
IntegerPolyhedron(IntegerRelation &&rel)
Construct a set from an IntegerRelation, but instead of creating a copy, use move constructor.
IntegerPolyhedron(const IntegerRelation &rel)
Construct a set from an IntegerRelation.
static bool classof(const IntegerRelation *cst)
IntegerPolyhedron(const PresburgerSpace &space, const FracMatrix &inequalities)
Constructs a relation with the specified number of dimensions and symbols and adds the given inequali...
IntegerPolyhedron intersect(const IntegerPolyhedron &other) const
Return the intersection of the two relations.
IntegerPolyhedron(const PresburgerSpace &space, const IntMatrix &inequalities)
Constructs a relation with the specified number of dimensions and symbols and adds the given inequali...
Kind getKind() const override
Return the kind of this IntegerRelation.
unsigned insertVar(VarKind kind, unsigned pos, unsigned num=1) override
Insert num variables of the specified kind at position pos.
PresburgerSet subtract(const PresburgerSet &other) const
Return the set difference of this set and the given set, i.e., return this \ set.
IntegerPolyhedron(const PresburgerSpace &space)
Constructs a relation with the specified number of dimensions and symbols.
IntegerPolyhedron(unsigned numReservedInequalities, unsigned numReservedEqualities, unsigned numReservedCols, const PresburgerSpace &space)
Constructs a set reserving memory for the specified number of constraints and variables.
std::unique_ptr< IntegerPolyhedron > clone() const
static IntegerPolyhedron getUniverse(const PresburgerSpace &space)
Return a system with no constraints, i.e., one which is satisfied by all points.
An IntegerRelation represents the set of points from a PresburgerSpace that satisfy a list of affine ...
Kind
All derived classes of IntegerRelation.
std::optional< DynamicAPInt > getConstantBoundOnDimSize(unsigned pos, SmallVectorImpl< DynamicAPInt > *lb=nullptr, DynamicAPInt *boundFloorDivisor=nullptr, SmallVectorImpl< DynamicAPInt > *ub=nullptr, unsigned *minLbPos=nullptr, unsigned *minUbPos=nullptr) const
Returns the smallest known constant bound for the extent of the specified variable (pos^th),...
void setId(VarKind kind, unsigned i, Identifier id)
Set the identifier for the ith variable of the specified kind of the IntegerRelation's PresburgerSpac...
void addInequality(ArrayRef< int64_t > inEq)
virtual void swapVar(unsigned posA, unsigned posB)
Swap the posA^th variable with the posB^th variable.
void setAndEliminate(unsigned pos, ArrayRef< int64_t > values)
void removeIndependentConstraints(unsigned pos, unsigned num)
Removes constraints that are independent of (i.e., do not have a coefficient) variables in the range ...
void compose(const IntegerRelation &rel)
Let the relation this be R1, and the relation rel be R2.
int64_t atEq64(unsigned i, unsigned j) const
The same, but casts to int64_t.
void applyRange(const IntegerRelation &rel)
Given a relation rel, apply the relation to the range of this relation.
unsigned getVarKindEnd(VarKind kind) const
Return the index at Which the specified kind of vars ends.
ArrayRef< Identifier > getIds(VarKind kind)
Get the identifiers for the variables of specified varKind.
PresburgerSpace getSpaceWithoutLocals() const
Returns a copy of the space without locals.
void removeTrivialRedundancy()
Removes duplicate constraints, trivially true constraints, and constraints that can be detected as re...
static IntegerRelation getEmpty(const PresburgerSpace &space)
Return an empty system containing an invalid equation 0 = 1.
void addBound(BoundType type, unsigned pos, int64_t value)
std::optional< unsigned > findConstraintWithNonZeroAt(unsigned colIdx, bool isEq) const
Finds a constraint with a non-zero coefficient at colIdx in equality (isEq=true) or inequality (isEq=...
void removeInequalityRange(unsigned start, unsigned end)
void convertVarKind(VarKind srcKind, unsigned varStart, unsigned varLimit, VarKind dstKind)
std::optional< int64_t > getConstantBoundOnDimSize64(unsigned pos, SmallVectorImpl< int64_t > *lb=nullptr, int64_t *boundFloorDivisor=nullptr, SmallVectorImpl< int64_t > *ub=nullptr, unsigned *minLbPos=nullptr, unsigned *minUbPos=nullptr) const
The same, but casts to int64_t.
void normalizeConstraintsByGCD()
Normalized each constraints by the GCD of its coefficients.
static bool classof(const IntegerRelation *cst)
void truncate(const CountsSnapshot &counts)
virtual void eliminateRedundantLocalVar(unsigned posA, unsigned posB)
Eliminate the posB^th local variable, replacing every instance of it with the posA^th local variable.
std::optional< DynamicAPInt > computeConstantLowerOrUpperBound(unsigned pos)
Returns the constant lower bound if isLower is true, and the upper bound if isLower is false.
SmallVector< int64_t, 8 > getEquality64(unsigned idx) const
The same, but casts to int64_t.
void removeEqualityRange(unsigned start, unsigned end)
Remove the (in)equalities at positions [start, end).
LogicalResult constantFoldVar(unsigned pos)
Tries to fold the specified variable to a constant using a trivial equality detection; if successful,...
std::optional< int64_t > getConstantBound64(BoundType type, unsigned pos) const
The same, but casts to int64_t.
bool isObviouslyEqual(const IntegerRelation &other) const
Perform a quick equality check on this and other.
IntegerPolyhedron getRangeSet() const
Return a set corresponding to all points in the range of the relation.
std::optional< SmallVector< DynamicAPInt, 8 > > containsPointNoLocal(ArrayRef< DynamicAPInt > point) const
Given the values of non-local vars, return a satisfying assignment to the local if one exists,...
ArrayRef< DynamicAPInt > getInequality(unsigned idx) const
unsigned getNumVarKind(VarKind kind) const
Get the number of vars of the specified kind.
bool isEmptyByGCDTest() const
Runs the GCD test on all equality constraints.
void simplify()
Simplify the constraint system by removing canonicalizing constraints and removing redundant constrai...
void convertVarKind(VarKind srcKind, unsigned varStart, unsigned varLimit, VarKind dstKind, unsigned pos)
Converts variables of kind srcKind in the range [varStart, varLimit) to variables of kind dstKind.
void addBound(BoundType type, unsigned pos, const DynamicAPInt &value)
Adds a constant bound for the specified variable.
unsigned appendVar(VarKind kind, unsigned num=1)
Append num variables of the specified kind after the last variable of that kind.
void intersectRange(const IntegerPolyhedron &poly)
Intersect the given poly with the range in-place.
void addLocalFloorDiv(ArrayRef< DynamicAPInt > dividend, const DynamicAPInt &divisor)
Adds a new local variable as the floordiv of an affine function of other variables,...
void print(raw_ostream &os) const
bool isIntegerEmpty() const
Returns true if the set of constraints is found to have no solution, false if a solution exists.
DynamicAPInt & atEq(unsigned i, unsigned j)
VarKind getVarKindAt(unsigned pos) const
Return the VarKind of the var at the specified position.
void addEquality(ArrayRef< int64_t > eq)
DynamicAPInt atIneq(unsigned i, unsigned j) const
Returns the value at the specified inequality row and column.
virtual unsigned insertVar(VarKind kind, unsigned pos, unsigned num=1)
Insert num variables of the specified kind at position pos.
bool containsPoint(ArrayRef< DynamicAPInt > point) const
Returns true if the given point satisfies the constraints, or false otherwise.
std::optional< SmallVector< DynamicAPInt, 8 > > findIntegerSample() const
Find an integer sample point satisfying the constraints using a branch and bound algorithm with gener...
bool hasInvalidConstraint() const
Checks all rows of equality/inequality constraints for trivial contradictions (for example: 1 == 0,...
LogicalResult unionBoundingBox(const IntegerRelation &other)
Updates the constraints to be the smallest bounding (enclosing) box that contains the points of this ...
IntegerRelation(unsigned numReservedInequalities, unsigned numReservedEqualities, unsigned numReservedCols, const PresburgerSpace &space)
Constructs a relation reserving memory for the specified number of constraints and variables.
bool containsPoint(ArrayRef< int64_t > point) const
bool isHyperRectangular(unsigned pos, unsigned num) const
Returns true if the set can be trivially detected as being hyper-rectangular on the specified contigu...
void convertToLocal(VarKind kind, unsigned varStart, unsigned varLimit)
IntMatrix getBoundedDirections() const
Returns a matrix where each row is a vector along which the polytope is bounded.
LogicalResult gaussianEliminateVar(unsigned position)
Eliminates a single variable at position from equality and inequality constraints.
void clearConstraints()
Removes all equalities and inequalities.
DynamicAPInt atEq(unsigned i, unsigned j) const
Returns the value at the specified equality row and column.
IntegerRelation intersect(IntegerRelation other) const
Return the intersection of the two relations.
std::optional< DynamicAPInt > computeVolume() const
Compute an overapproximation of the number of integer points in the relation.
MaybeOptimum< SmallVector< DynamicAPInt, 8 > > findIntegerLexMin() const
Same as above, but returns lexicographically minimal integer point.
SymbolicLexOpt findSymbolicIntegerLexMin() const
Compute the symbolic integer lexmin of the relation.
void setSpace(const PresburgerSpace &oSpace)
Set the space to oSpace, which should have the same number of ids as the current space.
int findEqualityToConstant(unsigned pos, bool symbolic=false) const
Finds an equality that equates the specified variable to a constant.
static IntegerRelation getUniverse(const PresburgerSpace &space)
Return a system with no constraints, i.e., one which is satisfied by all points.
void inverse()
Invert the relation i.e., swap its domain and range.
void append(const IntegerRelation &other)
Appends constraints from other into this.
void applyDomain(const IntegerRelation &rel)
Given a relation rel, apply the relation to the domain of this relation.
void intersectDomain(const IntegerPolyhedron &poly)
Intersect the given poly with the domain in-place.
PresburgerRelation subtract(const PresburgerRelation &set) const
Return the set difference of this set and the given set, i.e., return this \ set.
bool isEqual(const IntegerRelation &other) const
Return whether this and other are equal.
virtual void printSpace(raw_ostream &os) const
Prints the number of constraints, dimensions, symbols and locals in the IntegerRelation.
void addEquality(ArrayRef< DynamicAPInt > eq)
Adds an equality from the coefficients specified in eq.
void setDimSymbolSeparation(unsigned newSymbolCount)
Changes the partition between dimensions and symbols.
unsigned getNumReservedInequalities() const
void removeRedundantConstraints()
Removes redundant constraints using Simplex.
PresburgerRelation computeReprWithOnlyDivLocals() const
Compute an equivalent representation of the same set, such that all local vars in all disjuncts have ...
void removeRedundantInequalities()
A more expensive check than removeTrivialRedundancy to detect redundant inequalities.
bool isObviouslyEmpty() const
Performs GCD checks and invalid constraint checks.
IntMatrix equalities
Coefficients of affine equalities (in == 0 form).
SymbolicLexOpt findSymbolicIntegerLexMax() const
Same as findSymbolicIntegerLexMin but produces lexmax instead of lexmin.
bool gaussianEliminate()
Perform a Gaussian elimination operation to reduce all equations to standard form.
void addLocalFloorDiv(ArrayRef< int64_t > dividend, int64_t divisor)
void truncateVarKind(VarKind kind, unsigned num)
Truncate the vars of the specified kind to the specified number by dropping some vars at the end.
virtual Kind getKind() const
Return the kind of this IntegerRelation.
void constantFoldVarRange(unsigned pos, unsigned num)
This method calls constantFoldVar for the specified range of variables, num variables starting at pos...
bool isEmpty() const
Checks for emptiness by performing variable elimination on all variables, running the GCD test on eac...
unsigned getNumCols() const
Returns the number of columns in the constraint system.
IntegerRelation(const PresburgerSpace &space)
Constructs a relation with the specified number of dimensions and symbols.
void getLowerAndUpperBoundIndices(unsigned pos, SmallVectorImpl< unsigned > *lbIndices, SmallVectorImpl< unsigned > *ubIndices, SmallVectorImpl< unsigned > *eqIndices=nullptr, unsigned offset=0, unsigned num=0) const
Gather positions of all lower and upper bounds of the variable at pos, and optionally any equalities ...
void gcdTightenInequalities()
Tightens inequalities given that we are dealing with integer spaces.
std::optional< int64_t > computeConstantLowerOrUpperBound64(unsigned pos)
The same, but casts to int64_t.
void removeVar(VarKind kind, unsigned pos)
Removes variables of the specified kind with the specified pos (or within the specified range) from t...
void setSpaceExceptLocals(const PresburgerSpace &oSpace)
Set the space to oSpace, which should not have any local ids.
unsigned gaussianEliminateVars(unsigned posStart, unsigned posLimit)
Eliminates variables from equality and inequality constraints in column range [posStart,...
void mergeAndCompose(const IntegerRelation &other)
Given a relation other: (A -> B), this operation merges the symbol and local variables and then takes...
IntegerPolyhedron getDomainSet() const
Return a set corresponding to all points in the domain of the relation.
void addBound(BoundType type, ArrayRef< int64_t > expr, int64_t value)
DivisionRepr getLocalReprs(std::vector< MaybeLocalRepr > *repr=nullptr) const
Returns a DivisonRepr representing the division representation of local variables in the constraint s...
bool hasOnlyDivLocals() const
Check whether all local ids have a division representation.
constexpr static unsigned kExplosionFactor
A parameter that controls detection of an unrealistic number of constraints.
std::optional< DynamicAPInt > getConstantBound(BoundType type, unsigned pos) const
Returns the constant bound for the pos^th variable if there is one; std::nullopt otherwise.
virtual void clearAndCopyFrom(const IntegerRelation &other)
Replaces the contents of this IntegerRelation with other.
void projectOut(unsigned pos, unsigned num)
Projects out (aka eliminates) num variables starting at position pos.
void addInequality(ArrayRef< DynamicAPInt > inEq)
Adds an inequality (>= 0) from the coefficients specified in inEq.
unsigned getVarKindOverlap(VarKind kind, unsigned varStart, unsigned varLimit) const
Get the number of elements of the specified kind in the range [varStart, varLimit).
void mergeAndAlignSymbols(IntegerRelation &other)
Merge and align symbol variables of this and other with respect to identifiers.
std::optional< SmallVector< DynamicAPInt, 8 > > containsPointNoLocal(ArrayRef< int64_t > point) const
void removeRedundantLocalVars()
Removes local variables using equalities.
unsigned mergeLocalVars(IntegerRelation &other)
Adds additional local vars to the sets such that they both have the union of the local vars in each s...
virtual ~IntegerRelation()=default
MaybeOptimum< SmallVector< Fraction, 8 > > findRationalLexMin() const
Get the lexicographically minimum rational point satisfying the constraints.
IntMatrix inequalities
Coefficients of affine inequalities (in >= 0 form).
virtual bool hasConsistentState() const
Returns false if the fields corresponding to various variable counts, or equality/inequality buffer s...
ArrayRef< DynamicAPInt > getEquality(unsigned idx) const
SmallVector< int64_t, 8 > getInequality64(unsigned idx) const
bool isSubsetOf(const IntegerRelation &other) const
Return whether this is a subset of the given IntegerRelation.
std::unique_ptr< IntegerRelation > clone() const
const PresburgerSpace & getSpace() const
Returns a reference to the underlying space.
DynamicAPInt & atIneq(unsigned i, unsigned j)
void setAndEliminate(unsigned pos, ArrayRef< DynamicAPInt > values)
Sets the values.size() variables starting at pos to the specified values and removes them.
bool isColZero(unsigned pos) const
Returns true if the pos^th column is all zero for both inequalities and equalities.
unsigned getVarKindOffset(VarKind kind) const
Return the index at which the specified kind of vars starts.
int64_t atIneq64(unsigned i, unsigned j) const
The same, but casts to int64_t.
virtual void removeVarRange(VarKind kind, unsigned varStart, unsigned varLimit)
virtual void fourierMotzkinEliminate(unsigned pos, bool darkShadow=false, bool *isResultIntegerExact=nullptr)
Eliminates the variable at the specified position using Fourier-Motzkin variable elimination,...
bool removeDuplicateConstraints()
Checks for identical inequalities and eliminates redundant inequalities.
unsigned getNumRows() const
Definition: Matrix.h:86
MutableArrayRef< T > getRow(unsigned row)
Get a [Mutable]ArrayRef corresponding to the specified row.
Definition: Matrix.cpp:130
unsigned getNumReservedRows() const
Return the maximum number of rows/columns that can be added without incurring a reallocation.
Definition: Matrix.cpp:55
A PresburgerRelation represents a union of IntegerRelations that live in the same PresburgerSpace wit...
PresburgerSpace is the space of all possible values of a tuple of integer valued variables/variables.
unsigned getNumVarKind(VarKind kind) const
Get the number of vars of the specified kind.
void resetIds()
Reset the stored identifiers in the space.
unsigned getVarKindOffset(VarKind kind) const
Return the index at which the specified kind of var starts.
unsigned getVarKindEnd(VarKind kind) const
Return the index at Which the specified kind of var ends.
VarKind getVarKindAt(unsigned pos) const
Return the VarKind of the var at the specified position.
unsigned getVarKindOverlap(VarKind kind, unsigned varStart, unsigned varLimit) const
Get the number of elements of the specified kind in the range [varStart, varLimit).
void setVarSymbolSeparation(unsigned newSymbolCount)
Changes the partition between dimensions and symbols.
static PresburgerSpace getRelationSpace(unsigned numDomain=0, unsigned numRange=0, unsigned numSymbols=0, unsigned numLocals=0)
BoundType
The type of bound: equal, lower bound or upper bound.
VarKind
Kind of variable.
SmallVector< DynamicAPInt, 8 > getDynamicAPIntVec(ArrayRef< int64_t > range)
Check if the pos^th variable can be expressed as a floordiv of an affine function of other variables ...
Definition: Utils.cpp:524
SmallVector< int64_t, 8 > getInt64Vec(ArrayRef< DynamicAPInt > range)
Return the given array as an array of int64_t.
Definition: Utils.cpp:531
Include the generated interface declarations.
The struct CountsSnapshot stores the count of each VarKind, and also of each constraint type.
CountsSnapshot(const PresburgerSpace &space, unsigned numIneqs, unsigned numEqs)
Represents the result of a symbolic lexicographic optimization computation.
Definition: Simplex.h:529
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.