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