1 //===- IntegerRelation.cpp - MLIR IntegerRelation Class ---------------===// 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 an 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 #include "mlir/Analysis/Presburger/IntegerRelation.h" 16 #include "mlir/Analysis/Presburger/Fraction.h" 17 #include "mlir/Analysis/Presburger/LinearTransform.h" 18 #include "mlir/Analysis/Presburger/PWMAFunction.h" 19 #include "mlir/Analysis/Presburger/PresburgerRelation.h" 20 #include "mlir/Analysis/Presburger/PresburgerSpace.h" 21 #include "mlir/Analysis/Presburger/Simplex.h" 22 #include "mlir/Analysis/Presburger/Utils.h" 23 #include "llvm/ADT/DenseMap.h" 24 #include "llvm/ADT/DenseSet.h" 25 #include "llvm/ADT/STLExtras.h" 26 #include "llvm/ADT/Sequence.h" 27 #include "llvm/ADT/SmallBitVector.h" 28 #include "llvm/Support/Debug.h" 29 #include "llvm/Support/LogicalResult.h" 30 #include "llvm/Support/raw_ostream.h" 31 #include <algorithm> 32 #include <cassert> 33 #include <functional> 34 #include <memory> 35 #include <numeric> 36 #include <optional> 37 #include <sstream> 38 #include <string> 39 #include <utility> 40 #include <vector> 41 42 #define DEBUG_TYPE "presburger" 43 44 using namespace mlir; 45 using namespace presburger; 46 47 using llvm::SmallDenseMap; 48 using llvm::SmallDenseSet; 49 50 std::unique_ptr<IntegerRelation> IntegerRelation::clone() const { 51 return std::make_unique<IntegerRelation>(*this); 52 } 53 54 std::unique_ptr<IntegerPolyhedron> IntegerPolyhedron::clone() const { 55 return std::make_unique<IntegerPolyhedron>(*this); 56 } 57 58 void IntegerRelation::setSpace(const PresburgerSpace &oSpace) { 59 assert(space.getNumVars() == oSpace.getNumVars() && "invalid space!"); 60 space = oSpace; 61 } 62 63 void IntegerRelation::setSpaceExceptLocals(const PresburgerSpace &oSpace) { 64 assert(oSpace.getNumLocalVars() == 0 && "no locals should be present!"); 65 assert(oSpace.getNumVars() <= getNumVars() && "invalid space!"); 66 unsigned newNumLocals = getNumVars() - oSpace.getNumVars(); 67 space = oSpace; 68 space.insertVar(VarKind::Local, 0, newNumLocals); 69 } 70 71 void IntegerRelation::setId(VarKind kind, unsigned i, Identifier id) { 72 assert(space.isUsingIds() && 73 "space must be using identifiers to set an identifier"); 74 assert(kind != VarKind::Local && "local variables cannot have identifiers"); 75 assert(i < space.getNumVarKind(kind) && "invalid variable index"); 76 space.setId(kind, i, id); 77 } 78 79 ArrayRef<Identifier> IntegerRelation::getIds(VarKind kind) { 80 if (!space.isUsingIds()) 81 space.resetIds(); 82 return space.getIds(kind); 83 } 84 85 void IntegerRelation::append(const IntegerRelation &other) { 86 assert(space.isEqual(other.getSpace()) && "Spaces must be equal."); 87 88 inequalities.reserveRows(inequalities.getNumRows() + 89 other.getNumInequalities()); 90 equalities.reserveRows(equalities.getNumRows() + other.getNumEqualities()); 91 92 for (unsigned r = 0, e = other.getNumInequalities(); r < e; r++) { 93 addInequality(other.getInequality(r)); 94 } 95 for (unsigned r = 0, e = other.getNumEqualities(); r < e; r++) { 96 addEquality(other.getEquality(r)); 97 } 98 } 99 100 IntegerRelation IntegerRelation::intersect(IntegerRelation other) const { 101 IntegerRelation result = *this; 102 result.mergeLocalVars(other); 103 result.append(other); 104 return result; 105 } 106 107 bool IntegerRelation::isEqual(const IntegerRelation &other) const { 108 assert(space.isCompatible(other.getSpace()) && "Spaces must be compatible."); 109 return PresburgerRelation(*this).isEqual(PresburgerRelation(other)); 110 } 111 112 bool IntegerRelation::isObviouslyEqual(const IntegerRelation &other) const { 113 if (!space.isEqual(other.getSpace())) 114 return false; 115 if (getNumEqualities() != other.getNumEqualities()) 116 return false; 117 if (getNumInequalities() != other.getNumInequalities()) 118 return false; 119 120 unsigned cols = getNumCols(); 121 for (unsigned i = 0, eqs = getNumEqualities(); i < eqs; ++i) { 122 for (unsigned j = 0; j < cols; ++j) { 123 if (atEq(i, j) != other.atEq(i, j)) 124 return false; 125 } 126 } 127 for (unsigned i = 0, ineqs = getNumInequalities(); i < ineqs; ++i) { 128 for (unsigned j = 0; j < cols; ++j) { 129 if (atIneq(i, j) != other.atIneq(i, j)) 130 return false; 131 } 132 } 133 return true; 134 } 135 136 bool IntegerRelation::isSubsetOf(const IntegerRelation &other) const { 137 assert(space.isCompatible(other.getSpace()) && "Spaces must be compatible."); 138 return PresburgerRelation(*this).isSubsetOf(PresburgerRelation(other)); 139 } 140 141 MaybeOptimum<SmallVector<Fraction, 8>> 142 IntegerRelation::findRationalLexMin() const { 143 assert(getNumSymbolVars() == 0 && "Symbols are not supported!"); 144 MaybeOptimum<SmallVector<Fraction, 8>> maybeLexMin = 145 LexSimplex(*this).findRationalLexMin(); 146 147 if (!maybeLexMin.isBounded()) 148 return maybeLexMin; 149 150 // The Simplex returns the lexmin over all the variables including locals. But 151 // locals are not actually part of the space and should not be returned in the 152 // result. Since the locals are placed last in the list of variables, they 153 // will be minimized last in the lexmin. So simply truncating out the locals 154 // from the end of the answer gives the desired lexmin over the dimensions. 155 assert(maybeLexMin->size() == getNumVars() && 156 "Incorrect number of vars in lexMin!"); 157 maybeLexMin->resize(getNumDimAndSymbolVars()); 158 return maybeLexMin; 159 } 160 161 MaybeOptimum<SmallVector<DynamicAPInt, 8>> 162 IntegerRelation::findIntegerLexMin() const { 163 assert(getNumSymbolVars() == 0 && "Symbols are not supported!"); 164 MaybeOptimum<SmallVector<DynamicAPInt, 8>> maybeLexMin = 165 LexSimplex(*this).findIntegerLexMin(); 166 167 if (!maybeLexMin.isBounded()) 168 return maybeLexMin.getKind(); 169 170 // The Simplex returns the lexmin over all the variables including locals. But 171 // locals are not actually part of the space and should not be returned in the 172 // result. Since the locals are placed last in the list of variables, they 173 // will be minimized last in the lexmin. So simply truncating out the locals 174 // from the end of the answer gives the desired lexmin over the dimensions. 175 assert(maybeLexMin->size() == getNumVars() && 176 "Incorrect number of vars in lexMin!"); 177 maybeLexMin->resize(getNumDimAndSymbolVars()); 178 return maybeLexMin; 179 } 180 181 static bool rangeIsZero(ArrayRef<DynamicAPInt> range) { 182 return llvm::all_of(range, [](const DynamicAPInt &x) { return x == 0; }); 183 } 184 185 static void removeConstraintsInvolvingVarRange(IntegerRelation &poly, 186 unsigned begin, unsigned count) { 187 // We loop until i > 0 and index into i - 1 to avoid sign issues. 188 // 189 // We iterate backwards so that whether we remove constraint i - 1 or not, the 190 // next constraint to be tested is always i - 2. 191 for (unsigned i = poly.getNumEqualities(); i > 0; i--) 192 if (!rangeIsZero(poly.getEquality(i - 1).slice(begin, count))) 193 poly.removeEquality(i - 1); 194 for (unsigned i = poly.getNumInequalities(); i > 0; i--) 195 if (!rangeIsZero(poly.getInequality(i - 1).slice(begin, count))) 196 poly.removeInequality(i - 1); 197 } 198 199 IntegerRelation::CountsSnapshot IntegerRelation::getCounts() const { 200 return {getSpace(), getNumInequalities(), getNumEqualities()}; 201 } 202 203 void IntegerRelation::truncateVarKind(VarKind kind, unsigned num) { 204 unsigned curNum = getNumVarKind(kind); 205 assert(num <= curNum && "Can't truncate to more vars!"); 206 removeVarRange(kind, num, curNum); 207 } 208 209 void IntegerRelation::truncateVarKind(VarKind kind, 210 const CountsSnapshot &counts) { 211 truncateVarKind(kind, counts.getSpace().getNumVarKind(kind)); 212 } 213 214 void IntegerRelation::truncate(const CountsSnapshot &counts) { 215 truncateVarKind(VarKind::Domain, counts); 216 truncateVarKind(VarKind::Range, counts); 217 truncateVarKind(VarKind::Symbol, counts); 218 truncateVarKind(VarKind::Local, counts); 219 removeInequalityRange(counts.getNumIneqs(), getNumInequalities()); 220 removeEqualityRange(counts.getNumEqs(), getNumEqualities()); 221 } 222 223 PresburgerRelation IntegerRelation::computeReprWithOnlyDivLocals() const { 224 // If there are no locals, we're done. 225 if (getNumLocalVars() == 0) 226 return PresburgerRelation(*this); 227 228 // Move all the non-div locals to the end, as the current API to 229 // SymbolicLexOpt requires these to form a contiguous range. 230 // 231 // Take a copy so we can perform mutations. 232 IntegerRelation copy = *this; 233 std::vector<MaybeLocalRepr> reprs(getNumLocalVars()); 234 copy.getLocalReprs(&reprs); 235 236 // Iterate through all the locals. The last `numNonDivLocals` are the locals 237 // that have been scanned already and do not have division representations. 238 unsigned numNonDivLocals = 0; 239 unsigned offset = copy.getVarKindOffset(VarKind::Local); 240 for (unsigned i = 0, e = copy.getNumLocalVars(); i < e - numNonDivLocals;) { 241 if (!reprs[i]) { 242 // Whenever we come across a local that does not have a division 243 // representation, we swap it to the `numNonDivLocals`-th last position 244 // and increment `numNonDivLocal`s. `reprs` also needs to be swapped. 245 copy.swapVar(offset + i, offset + e - numNonDivLocals - 1); 246 std::swap(reprs[i], reprs[e - numNonDivLocals - 1]); 247 ++numNonDivLocals; 248 continue; 249 } 250 ++i; 251 } 252 253 // If there are no non-div locals, we're done. 254 if (numNonDivLocals == 0) 255 return PresburgerRelation(*this); 256 257 // We computeSymbolicIntegerLexMin by considering the non-div locals as 258 // "non-symbols" and considering everything else as "symbols". This will 259 // compute a function mapping assignments to "symbols" to the 260 // lexicographically minimal valid assignment of "non-symbols", when a 261 // satisfying assignment exists. It separately returns the set of assignments 262 // to the "symbols" such that a satisfying assignment to the "non-symbols" 263 // exists but the lexmin is unbounded. We basically want to find the set of 264 // values of the "symbols" such that an assignment to the "non-symbols" 265 // exists, which is the union of the domain of the returned lexmin function 266 // and the returned set of assignments to the "symbols" that makes the lexmin 267 // unbounded. 268 SymbolicLexOpt lexminResult = 269 SymbolicLexSimplex(copy, /*symbolOffset*/ 0, 270 IntegerPolyhedron(PresburgerSpace::getSetSpace( 271 /*numDims=*/copy.getNumVars() - numNonDivLocals))) 272 .computeSymbolicIntegerLexMin(); 273 PresburgerRelation result = 274 lexminResult.lexopt.getDomain().unionSet(lexminResult.unboundedDomain); 275 276 // The result set might lie in the wrong space -- all its ids are dims. 277 // Set it to the desired space and return. 278 PresburgerSpace space = getSpace(); 279 space.removeVarRange(VarKind::Local, 0, getNumLocalVars()); 280 result.setSpace(space); 281 return result; 282 } 283 284 SymbolicLexOpt IntegerRelation::findSymbolicIntegerLexMin() const { 285 // Symbol and Domain vars will be used as symbols for symbolic lexmin. 286 // In other words, for every value of the symbols and domain, return the 287 // lexmin value of the (range, locals). 288 llvm::SmallBitVector isSymbol(getNumVars(), false); 289 isSymbol.set(getVarKindOffset(VarKind::Symbol), 290 getVarKindEnd(VarKind::Symbol)); 291 isSymbol.set(getVarKindOffset(VarKind::Domain), 292 getVarKindEnd(VarKind::Domain)); 293 // Compute the symbolic lexmin of the dims and locals, with the symbols being 294 // the actual symbols of this set. 295 // The resultant space of lexmin is the space of the relation itself. 296 SymbolicLexOpt result = 297 SymbolicLexSimplex(*this, 298 IntegerPolyhedron(PresburgerSpace::getSetSpace( 299 /*numDims=*/getNumDomainVars(), 300 /*numSymbols=*/getNumSymbolVars())), 301 isSymbol) 302 .computeSymbolicIntegerLexMin(); 303 304 // We want to return only the lexmin over the dims, so strip the locals from 305 // the computed lexmin. 306 result.lexopt.removeOutputs(result.lexopt.getNumOutputs() - getNumLocalVars(), 307 result.lexopt.getNumOutputs()); 308 return result; 309 } 310 311 /// findSymbolicIntegerLexMax is implemented using findSymbolicIntegerLexMin as 312 /// follows: 313 /// 1. A new relation is created which is `this` relation with the sign of 314 /// each dimension variable in range flipped; 315 /// 2. findSymbolicIntegerLexMin is called on the range negated relation to 316 /// compute the negated lexmax of `this` relation; 317 /// 3. The sign of the negated lexmax is flipped and returned. 318 SymbolicLexOpt IntegerRelation::findSymbolicIntegerLexMax() const { 319 IntegerRelation flippedRel = *this; 320 // Flip range sign by flipping the sign of range variables in all constraints. 321 for (unsigned j = getNumDomainVars(), 322 b = getNumDomainVars() + getNumRangeVars(); 323 j < b; j++) { 324 for (unsigned i = 0, a = getNumEqualities(); i < a; i++) 325 flippedRel.atEq(i, j) = -1 * atEq(i, j); 326 for (unsigned i = 0, a = getNumInequalities(); i < a; i++) 327 flippedRel.atIneq(i, j) = -1 * atIneq(i, j); 328 } 329 // Compute negated lexmax by computing lexmin. 330 SymbolicLexOpt flippedSymbolicIntegerLexMax = 331 flippedRel.findSymbolicIntegerLexMin(), 332 symbolicIntegerLexMax( 333 flippedSymbolicIntegerLexMax.lexopt.getSpace()); 334 // Get lexmax by flipping range sign in the PWMA constraints. 335 for (auto &flippedPiece : 336 flippedSymbolicIntegerLexMax.lexopt.getAllPieces()) { 337 IntMatrix mat = flippedPiece.output.getOutputMatrix(); 338 for (unsigned i = 0, e = mat.getNumRows(); i < e; i++) 339 mat.negateRow(i); 340 MultiAffineFunction maf(flippedPiece.output.getSpace(), mat); 341 PWMAFunction::Piece piece = {flippedPiece.domain, maf}; 342 symbolicIntegerLexMax.lexopt.addPiece(piece); 343 } 344 symbolicIntegerLexMax.unboundedDomain = 345 flippedSymbolicIntegerLexMax.unboundedDomain; 346 return symbolicIntegerLexMax; 347 } 348 349 PresburgerRelation 350 IntegerRelation::subtract(const PresburgerRelation &set) const { 351 return PresburgerRelation(*this).subtract(set); 352 } 353 354 unsigned IntegerRelation::insertVar(VarKind kind, unsigned pos, unsigned num) { 355 assert(pos <= getNumVarKind(kind)); 356 357 unsigned insertPos = space.insertVar(kind, pos, num); 358 inequalities.insertColumns(insertPos, num); 359 equalities.insertColumns(insertPos, num); 360 return insertPos; 361 } 362 363 unsigned IntegerRelation::appendVar(VarKind kind, unsigned num) { 364 unsigned pos = getNumVarKind(kind); 365 return insertVar(kind, pos, num); 366 } 367 368 void IntegerRelation::addEquality(ArrayRef<DynamicAPInt> eq) { 369 assert(eq.size() == getNumCols()); 370 unsigned row = equalities.appendExtraRow(); 371 for (unsigned i = 0, e = eq.size(); i < e; ++i) 372 equalities(row, i) = eq[i]; 373 } 374 375 void IntegerRelation::addInequality(ArrayRef<DynamicAPInt> inEq) { 376 assert(inEq.size() == getNumCols()); 377 unsigned row = inequalities.appendExtraRow(); 378 for (unsigned i = 0, e = inEq.size(); i < e; ++i) 379 inequalities(row, i) = inEq[i]; 380 } 381 382 void IntegerRelation::removeVar(VarKind kind, unsigned pos) { 383 removeVarRange(kind, pos, pos + 1); 384 } 385 386 void IntegerRelation::removeVar(unsigned pos) { removeVarRange(pos, pos + 1); } 387 388 void IntegerRelation::removeVarRange(VarKind kind, unsigned varStart, 389 unsigned varLimit) { 390 assert(varLimit <= getNumVarKind(kind)); 391 392 if (varStart >= varLimit) 393 return; 394 395 // Remove eliminated variables from the constraints. 396 unsigned offset = getVarKindOffset(kind); 397 equalities.removeColumns(offset + varStart, varLimit - varStart); 398 inequalities.removeColumns(offset + varStart, varLimit - varStart); 399 400 // Remove eliminated variables from the space. 401 space.removeVarRange(kind, varStart, varLimit); 402 } 403 404 void IntegerRelation::removeVarRange(unsigned varStart, unsigned varLimit) { 405 assert(varLimit <= getNumVars()); 406 407 if (varStart >= varLimit) 408 return; 409 410 // Helper function to remove vars of the specified kind in the given range 411 // [start, limit), The range is absolute (i.e. it is not relative to the kind 412 // of variable). Also updates `limit` to reflect the deleted variables. 413 auto removeVarKindInRange = [this](VarKind kind, unsigned &start, 414 unsigned &limit) { 415 if (start >= limit) 416 return; 417 418 unsigned offset = getVarKindOffset(kind); 419 unsigned num = getNumVarKind(kind); 420 421 // Get `start`, `limit` relative to the specified kind. 422 unsigned relativeStart = 423 start <= offset ? 0 : std::min(num, start - offset); 424 unsigned relativeLimit = 425 limit <= offset ? 0 : std::min(num, limit - offset); 426 427 // Remove vars of the specified kind in the relative range. 428 removeVarRange(kind, relativeStart, relativeLimit); 429 430 // Update `limit` to reflect deleted variables. 431 // `start` does not need to be updated because any variables that are 432 // deleted are after position `start`. 433 limit -= relativeLimit - relativeStart; 434 }; 435 436 removeVarKindInRange(VarKind::Domain, varStart, varLimit); 437 removeVarKindInRange(VarKind::Range, varStart, varLimit); 438 removeVarKindInRange(VarKind::Symbol, varStart, varLimit); 439 removeVarKindInRange(VarKind::Local, varStart, varLimit); 440 } 441 442 void IntegerRelation::removeEquality(unsigned pos) { 443 equalities.removeRow(pos); 444 } 445 446 void IntegerRelation::removeInequality(unsigned pos) { 447 inequalities.removeRow(pos); 448 } 449 450 void IntegerRelation::removeEqualityRange(unsigned start, unsigned end) { 451 if (start >= end) 452 return; 453 equalities.removeRows(start, end - start); 454 } 455 456 void IntegerRelation::removeInequalityRange(unsigned start, unsigned end) { 457 if (start >= end) 458 return; 459 inequalities.removeRows(start, end - start); 460 } 461 462 void IntegerRelation::swapVar(unsigned posA, unsigned posB) { 463 assert(posA < getNumVars() && "invalid position A"); 464 assert(posB < getNumVars() && "invalid position B"); 465 466 if (posA == posB) 467 return; 468 469 VarKind kindA = space.getVarKindAt(posA); 470 VarKind kindB = space.getVarKindAt(posB); 471 unsigned relativePosA = posA - getVarKindOffset(kindA); 472 unsigned relativePosB = posB - getVarKindOffset(kindB); 473 space.swapVar(kindA, kindB, relativePosA, relativePosB); 474 475 inequalities.swapColumns(posA, posB); 476 equalities.swapColumns(posA, posB); 477 } 478 479 void IntegerRelation::clearConstraints() { 480 equalities.resizeVertically(0); 481 inequalities.resizeVertically(0); 482 } 483 484 /// Gather all lower and upper bounds of the variable at `pos`, and 485 /// optionally any equalities on it. In addition, the bounds are to be 486 /// independent of variables in position range [`offset`, `offset` + `num`). 487 void IntegerRelation::getLowerAndUpperBoundIndices( 488 unsigned pos, SmallVectorImpl<unsigned> *lbIndices, 489 SmallVectorImpl<unsigned> *ubIndices, SmallVectorImpl<unsigned> *eqIndices, 490 unsigned offset, unsigned num) const { 491 assert(pos < getNumVars() && "invalid position"); 492 assert(offset + num < getNumCols() && "invalid range"); 493 494 // Checks for a constraint that has a non-zero coeff for the variables in 495 // the position range [offset, offset + num) while ignoring `pos`. 496 auto containsConstraintDependentOnRange = [&](unsigned r, bool isEq) { 497 unsigned c, f; 498 auto cst = isEq ? getEquality(r) : getInequality(r); 499 for (c = offset, f = offset + num; c < f; ++c) { 500 if (c == pos) 501 continue; 502 if (cst[c] != 0) 503 break; 504 } 505 return c < f; 506 }; 507 508 // Gather all lower bounds and upper bounds of the variable. Since the 509 // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower 510 // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1. 511 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 512 // The bounds are to be independent of [offset, offset + num) columns. 513 if (containsConstraintDependentOnRange(r, /*isEq=*/false)) 514 continue; 515 if (atIneq(r, pos) >= 1) { 516 // Lower bound. 517 lbIndices->emplace_back(r); 518 } else if (atIneq(r, pos) <= -1) { 519 // Upper bound. 520 ubIndices->emplace_back(r); 521 } 522 } 523 524 // An equality is both a lower and upper bound. Record any equalities 525 // involving the pos^th variable. 526 if (!eqIndices) 527 return; 528 529 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 530 if (atEq(r, pos) == 0) 531 continue; 532 if (containsConstraintDependentOnRange(r, /*isEq=*/true)) 533 continue; 534 eqIndices->emplace_back(r); 535 } 536 } 537 538 bool IntegerRelation::hasConsistentState() const { 539 if (!inequalities.hasConsistentState()) 540 return false; 541 if (!equalities.hasConsistentState()) 542 return false; 543 return true; 544 } 545 546 void IntegerRelation::setAndEliminate(unsigned pos, 547 ArrayRef<DynamicAPInt> values) { 548 if (values.empty()) 549 return; 550 assert(pos + values.size() <= getNumVars() && 551 "invalid position or too many values"); 552 // Setting x_j = p in sum_i a_i x_i + c is equivalent to adding p*a_j to the 553 // constant term and removing the var x_j. We do this for all the vars 554 // pos, pos + 1, ... pos + values.size() - 1. 555 unsigned constantColPos = getNumCols() - 1; 556 for (unsigned i = 0, numVals = values.size(); i < numVals; ++i) 557 inequalities.addToColumn(i + pos, constantColPos, values[i]); 558 for (unsigned i = 0, numVals = values.size(); i < numVals; ++i) 559 equalities.addToColumn(i + pos, constantColPos, values[i]); 560 removeVarRange(pos, pos + values.size()); 561 } 562 563 void IntegerRelation::clearAndCopyFrom(const IntegerRelation &other) { 564 *this = other; 565 } 566 567 // Searches for a constraint with a non-zero coefficient at `colIdx` in 568 // equality (isEq=true) or inequality (isEq=false) constraints. 569 // Returns true and sets row found in search in `rowIdx`, false otherwise. 570 bool IntegerRelation::findConstraintWithNonZeroAt(unsigned colIdx, bool isEq, 571 unsigned *rowIdx) const { 572 assert(colIdx < getNumCols() && "position out of bounds"); 573 auto at = [&](unsigned rowIdx) -> DynamicAPInt { 574 return isEq ? atEq(rowIdx, colIdx) : atIneq(rowIdx, colIdx); 575 }; 576 unsigned e = isEq ? getNumEqualities() : getNumInequalities(); 577 for (*rowIdx = 0; *rowIdx < e; ++(*rowIdx)) { 578 if (at(*rowIdx) != 0) { 579 return true; 580 } 581 } 582 return false; 583 } 584 585 void IntegerRelation::normalizeConstraintsByGCD() { 586 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) 587 equalities.normalizeRow(i); 588 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) 589 inequalities.normalizeRow(i); 590 } 591 592 bool IntegerRelation::hasInvalidConstraint() const { 593 assert(hasConsistentState()); 594 auto check = [&](bool isEq) -> bool { 595 unsigned numCols = getNumCols(); 596 unsigned numRows = isEq ? getNumEqualities() : getNumInequalities(); 597 for (unsigned i = 0, e = numRows; i < e; ++i) { 598 unsigned j; 599 for (j = 0; j < numCols - 1; ++j) { 600 DynamicAPInt v = isEq ? atEq(i, j) : atIneq(i, j); 601 // Skip rows with non-zero variable coefficients. 602 if (v != 0) 603 break; 604 } 605 if (j < numCols - 1) { 606 continue; 607 } 608 // Check validity of constant term at 'numCols - 1' w.r.t 'isEq'. 609 // Example invalid constraints include: '1 == 0' or '-1 >= 0' 610 DynamicAPInt v = isEq ? atEq(i, numCols - 1) : atIneq(i, numCols - 1); 611 if ((isEq && v != 0) || (!isEq && v < 0)) { 612 return true; 613 } 614 } 615 return false; 616 }; 617 if (check(/*isEq=*/true)) 618 return true; 619 return check(/*isEq=*/false); 620 } 621 622 /// Eliminate variable from constraint at `rowIdx` based on coefficient at 623 /// pivotRow, pivotCol. Columns in range [elimColStart, pivotCol) will not be 624 /// updated as they have already been eliminated. 625 static void eliminateFromConstraint(IntegerRelation *constraints, 626 unsigned rowIdx, unsigned pivotRow, 627 unsigned pivotCol, unsigned elimColStart, 628 bool isEq) { 629 // Skip if equality 'rowIdx' if same as 'pivotRow'. 630 if (isEq && rowIdx == pivotRow) 631 return; 632 auto at = [&](unsigned i, unsigned j) -> DynamicAPInt { 633 return isEq ? constraints->atEq(i, j) : constraints->atIneq(i, j); 634 }; 635 DynamicAPInt leadCoeff = at(rowIdx, pivotCol); 636 // Skip if leading coefficient at 'rowIdx' is already zero. 637 if (leadCoeff == 0) 638 return; 639 DynamicAPInt pivotCoeff = constraints->atEq(pivotRow, pivotCol); 640 int sign = (leadCoeff * pivotCoeff > 0) ? -1 : 1; 641 DynamicAPInt lcm = llvm::lcm(pivotCoeff, leadCoeff); 642 DynamicAPInt pivotMultiplier = sign * (lcm / abs(pivotCoeff)); 643 DynamicAPInt rowMultiplier = lcm / abs(leadCoeff); 644 645 unsigned numCols = constraints->getNumCols(); 646 for (unsigned j = 0; j < numCols; ++j) { 647 // Skip updating column 'j' if it was just eliminated. 648 if (j >= elimColStart && j < pivotCol) 649 continue; 650 DynamicAPInt v = pivotMultiplier * constraints->atEq(pivotRow, j) + 651 rowMultiplier * at(rowIdx, j); 652 isEq ? constraints->atEq(rowIdx, j) = v 653 : constraints->atIneq(rowIdx, j) = v; 654 } 655 } 656 657 /// Returns the position of the variable that has the minimum <number of lower 658 /// bounds> times <number of upper bounds> from the specified range of 659 /// variables [start, end). It is often best to eliminate in the increasing 660 /// order of these counts when doing Fourier-Motzkin elimination since FM adds 661 /// that many new constraints. 662 static unsigned getBestVarToEliminate(const IntegerRelation &cst, 663 unsigned start, unsigned end) { 664 assert(start < cst.getNumVars() && end < cst.getNumVars() + 1); 665 666 auto getProductOfNumLowerUpperBounds = [&](unsigned pos) { 667 unsigned numLb = 0; 668 unsigned numUb = 0; 669 for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) { 670 if (cst.atIneq(r, pos) > 0) { 671 ++numLb; 672 } else if (cst.atIneq(r, pos) < 0) { 673 ++numUb; 674 } 675 } 676 return numLb * numUb; 677 }; 678 679 unsigned minLoc = start; 680 unsigned min = getProductOfNumLowerUpperBounds(start); 681 for (unsigned c = start + 1; c < end; c++) { 682 unsigned numLbUbProduct = getProductOfNumLowerUpperBounds(c); 683 if (numLbUbProduct < min) { 684 min = numLbUbProduct; 685 minLoc = c; 686 } 687 } 688 return minLoc; 689 } 690 691 // Checks for emptiness of the set by eliminating variables successively and 692 // using the GCD test (on all equality constraints) and checking for trivially 693 // invalid constraints. Returns 'true' if the constraint system is found to be 694 // empty; false otherwise. 695 bool IntegerRelation::isEmpty() const { 696 if (isEmptyByGCDTest() || hasInvalidConstraint()) 697 return true; 698 699 IntegerRelation tmpCst(*this); 700 701 // First, eliminate as many local variables as possible using equalities. 702 tmpCst.removeRedundantLocalVars(); 703 if (tmpCst.isEmptyByGCDTest() || tmpCst.hasInvalidConstraint()) 704 return true; 705 706 // Eliminate as many variables as possible using Gaussian elimination. 707 unsigned currentPos = 0; 708 while (currentPos < tmpCst.getNumVars()) { 709 tmpCst.gaussianEliminateVars(currentPos, tmpCst.getNumVars()); 710 ++currentPos; 711 // We check emptiness through trivial checks after eliminating each ID to 712 // detect emptiness early. Since the checks isEmptyByGCDTest() and 713 // hasInvalidConstraint() are linear time and single sweep on the constraint 714 // buffer, this appears reasonable - but can optimize in the future. 715 if (tmpCst.hasInvalidConstraint() || tmpCst.isEmptyByGCDTest()) 716 return true; 717 } 718 719 // Eliminate the remaining using FM. 720 for (unsigned i = 0, e = tmpCst.getNumVars(); i < e; i++) { 721 tmpCst.fourierMotzkinEliminate( 722 getBestVarToEliminate(tmpCst, 0, tmpCst.getNumVars())); 723 // Check for a constraint explosion. This rarely happens in practice, but 724 // this check exists as a safeguard against improperly constructed 725 // constraint systems or artificially created arbitrarily complex systems 726 // that aren't the intended use case for IntegerRelation. This is 727 // needed since FM has a worst case exponential complexity in theory. 728 if (tmpCst.getNumConstraints() >= kExplosionFactor * getNumVars()) { 729 LLVM_DEBUG(llvm::dbgs() << "FM constraint explosion detected\n"); 730 return false; 731 } 732 733 // FM wouldn't have modified the equalities in any way. So no need to again 734 // run GCD test. Check for trivial invalid constraints. 735 if (tmpCst.hasInvalidConstraint()) 736 return true; 737 } 738 return false; 739 } 740 741 bool IntegerRelation::isObviouslyEmpty() const { 742 return isEmptyByGCDTest() || hasInvalidConstraint(); 743 } 744 745 // Runs the GCD test on all equality constraints. Returns 'true' if this test 746 // fails on any equality. Returns 'false' otherwise. 747 // This test can be used to disprove the existence of a solution. If it returns 748 // true, no integer solution to the equality constraints can exist. 749 // 750 // GCD test definition: 751 // 752 // The equality constraint: 753 // 754 // c_1*x_1 + c_2*x_2 + ... + c_n*x_n = c_0 755 // 756 // has an integer solution iff: 757 // 758 // GCD of c_1, c_2, ..., c_n divides c_0. 759 bool IntegerRelation::isEmptyByGCDTest() const { 760 assert(hasConsistentState()); 761 unsigned numCols = getNumCols(); 762 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 763 DynamicAPInt gcd = abs(atEq(i, 0)); 764 for (unsigned j = 1; j < numCols - 1; ++j) { 765 gcd = llvm::gcd(gcd, abs(atEq(i, j))); 766 } 767 DynamicAPInt v = abs(atEq(i, numCols - 1)); 768 if (gcd > 0 && (v % gcd != 0)) { 769 return true; 770 } 771 } 772 return false; 773 } 774 775 // Returns a matrix where each row is a vector along which the polytope is 776 // bounded. The span of the returned vectors is guaranteed to contain all 777 // such vectors. The returned vectors are NOT guaranteed to be linearly 778 // independent. This function should not be called on empty sets. 779 // 780 // It is sufficient to check the perpendiculars of the constraints, as the set 781 // of perpendiculars which are bounded must span all bounded directions. 782 IntMatrix IntegerRelation::getBoundedDirections() const { 783 // Note that it is necessary to add the equalities too (which the constructor 784 // does) even though we don't need to check if they are bounded; whether an 785 // inequality is bounded or not depends on what other constraints, including 786 // equalities, are present. 787 Simplex simplex(*this); 788 789 assert(!simplex.isEmpty() && "It is not meaningful to ask whether a " 790 "direction is bounded in an empty set."); 791 792 SmallVector<unsigned, 8> boundedIneqs; 793 // The constructor adds the inequalities to the simplex first, so this 794 // processes all the inequalities. 795 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 796 if (simplex.isBoundedAlongConstraint(i)) 797 boundedIneqs.emplace_back(i); 798 } 799 800 // The direction vector is given by the coefficients and does not include the 801 // constant term, so the matrix has one fewer column. 802 unsigned dirsNumCols = getNumCols() - 1; 803 IntMatrix dirs(boundedIneqs.size() + getNumEqualities(), dirsNumCols); 804 805 // Copy the bounded inequalities. 806 unsigned row = 0; 807 for (unsigned i : boundedIneqs) { 808 for (unsigned col = 0; col < dirsNumCols; ++col) 809 dirs(row, col) = atIneq(i, col); 810 ++row; 811 } 812 813 // Copy the equalities. All the equalities' perpendiculars are bounded. 814 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 815 for (unsigned col = 0; col < dirsNumCols; ++col) 816 dirs(row, col) = atEq(i, col); 817 ++row; 818 } 819 820 return dirs; 821 } 822 823 bool IntegerRelation::isIntegerEmpty() const { return !findIntegerSample(); } 824 825 /// Let this set be S. If S is bounded then we directly call into the GBR 826 /// sampling algorithm. Otherwise, there are some unbounded directions, i.e., 827 /// vectors v such that S extends to infinity along v or -v. In this case we 828 /// use an algorithm described in the integer set library (isl) manual and used 829 /// by the isl_set_sample function in that library. The algorithm is: 830 /// 831 /// 1) Apply a unimodular transform T to S to obtain S*T, such that all 832 /// dimensions in which S*T is bounded lie in the linear span of a prefix of the 833 /// dimensions. 834 /// 835 /// 2) Construct a set B by removing all constraints that involve 836 /// the unbounded dimensions and then deleting the unbounded dimensions. Note 837 /// that B is a Bounded set. 838 /// 839 /// 3) Try to obtain a sample from B using the GBR sampling 840 /// algorithm. If no sample is found, return that S is empty. 841 /// 842 /// 4) Otherwise, substitute the obtained sample into S*T to obtain a set 843 /// C. C is a full-dimensional Cone and always contains a sample. 844 /// 845 /// 5) Obtain an integer sample from C. 846 /// 847 /// 6) Return T*v, where v is the concatenation of the samples from B and C. 848 /// 849 /// The following is a sketch of a proof that 850 /// a) If the algorithm returns empty, then S is empty. 851 /// b) If the algorithm returns a sample, it is a valid sample in S. 852 /// 853 /// The algorithm returns empty only if B is empty, in which case S*T is 854 /// certainly empty since B was obtained by removing constraints and then 855 /// deleting unconstrained dimensions from S*T. Since T is unimodular, a vector 856 /// v is in S*T iff T*v is in S. So in this case, since 857 /// S*T is empty, S is empty too. 858 /// 859 /// Otherwise, the algorithm substitutes the sample from B into S*T. All the 860 /// constraints of S*T that did not involve unbounded dimensions are satisfied 861 /// by this substitution. All dimensions in the linear span of the dimensions 862 /// outside the prefix are unbounded in S*T (step 1). Substituting values for 863 /// the bounded dimensions cannot make these dimensions bounded, and these are 864 /// the only remaining dimensions in C, so C is unbounded along every vector (in 865 /// the positive or negative direction, or both). C is hence a full-dimensional 866 /// cone and therefore always contains an integer point. 867 /// 868 /// Concatenating the samples from B and C gives a sample v in S*T, so the 869 /// returned sample T*v is a sample in S. 870 std::optional<SmallVector<DynamicAPInt, 8>> 871 IntegerRelation::findIntegerSample() const { 872 // First, try the GCD test heuristic. 873 if (isEmptyByGCDTest()) 874 return {}; 875 876 Simplex simplex(*this); 877 if (simplex.isEmpty()) 878 return {}; 879 880 // For a bounded set, we directly call into the GBR sampling algorithm. 881 if (!simplex.isUnbounded()) 882 return simplex.findIntegerSample(); 883 884 // The set is unbounded. We cannot directly use the GBR algorithm. 885 // 886 // m is a matrix containing, in each row, a vector in which S is 887 // bounded, such that the linear span of all these dimensions contains all 888 // bounded dimensions in S. 889 IntMatrix m = getBoundedDirections(); 890 // In column echelon form, each row of m occupies only the first rank(m) 891 // columns and has zeros on the other columns. The transform T that brings S 892 // to column echelon form is unimodular as well, so this is a suitable 893 // transform to use in step 1 of the algorithm. 894 std::pair<unsigned, LinearTransform> result = 895 LinearTransform::makeTransformToColumnEchelon(m); 896 const LinearTransform &transform = result.second; 897 // 1) Apply T to S to obtain S*T. 898 IntegerRelation transformedSet = transform.applyTo(*this); 899 900 // 2) Remove the unbounded dimensions and constraints involving them to 901 // obtain a bounded set. 902 IntegerRelation boundedSet(transformedSet); 903 unsigned numBoundedDims = result.first; 904 unsigned numUnboundedDims = getNumVars() - numBoundedDims; 905 removeConstraintsInvolvingVarRange(boundedSet, numBoundedDims, 906 numUnboundedDims); 907 boundedSet.removeVarRange(numBoundedDims, boundedSet.getNumVars()); 908 909 // 3) Try to obtain a sample from the bounded set. 910 std::optional<SmallVector<DynamicAPInt, 8>> boundedSample = 911 Simplex(boundedSet).findIntegerSample(); 912 if (!boundedSample) 913 return {}; 914 assert(boundedSet.containsPoint(*boundedSample) && 915 "Simplex returned an invalid sample!"); 916 917 // 4) Substitute the values of the bounded dimensions into S*T to obtain a 918 // full-dimensional cone, which necessarily contains an integer sample. 919 transformedSet.setAndEliminate(0, *boundedSample); 920 IntegerRelation &cone = transformedSet; 921 922 // 5) Obtain an integer sample from the cone. 923 // 924 // We shrink the cone such that for any rational point in the shrunken cone, 925 // rounding up each of the point's coordinates produces a point that still 926 // lies in the original cone. 927 // 928 // Rounding up a point x adds a number e_i in [0, 1) to each coordinate x_i. 929 // For each inequality sum_i a_i x_i + c >= 0 in the original cone, the 930 // shrunken cone will have the inequality tightened by some amount s, such 931 // that if x satisfies the shrunken cone's tightened inequality, then x + e 932 // satisfies the original inequality, i.e., 933 // 934 // sum_i a_i x_i + c + s >= 0 implies sum_i a_i (x_i + e_i) + c >= 0 935 // 936 // for any e_i values in [0, 1). In fact, we will handle the slightly more 937 // general case where e_i can be in [0, 1]. For example, consider the 938 // inequality 2x_1 - 3x_2 - 7x_3 - 6 >= 0, and let x = (3, 0, 0). How low 939 // could the LHS go if we added a number in [0, 1] to each coordinate? The LHS 940 // is minimized when we add 1 to the x_i with negative coefficient a_i and 941 // keep the other x_i the same. In the example, we would get x = (3, 1, 1), 942 // changing the value of the LHS by -3 + -7 = -10. 943 // 944 // In general, the value of the LHS can change by at most the sum of the 945 // negative a_i, so we accomodate this by shifting the inequality by this 946 // amount for the shrunken cone. 947 for (unsigned i = 0, e = cone.getNumInequalities(); i < e; ++i) { 948 for (unsigned j = 0; j < cone.getNumVars(); ++j) { 949 DynamicAPInt coeff = cone.atIneq(i, j); 950 if (coeff < 0) 951 cone.atIneq(i, cone.getNumVars()) += coeff; 952 } 953 } 954 955 // Obtain an integer sample in the cone by rounding up a rational point from 956 // the shrunken cone. Shrinking the cone amounts to shifting its apex 957 // "inwards" without changing its "shape"; the shrunken cone is still a 958 // full-dimensional cone and is hence non-empty. 959 Simplex shrunkenConeSimplex(cone); 960 assert(!shrunkenConeSimplex.isEmpty() && "Shrunken cone cannot be empty!"); 961 962 // The sample will always exist since the shrunken cone is non-empty. 963 SmallVector<Fraction, 8> shrunkenConeSample = 964 *shrunkenConeSimplex.getRationalSample(); 965 966 SmallVector<DynamicAPInt, 8> coneSample( 967 llvm::map_range(shrunkenConeSample, ceil)); 968 969 // 6) Return transform * concat(boundedSample, coneSample). 970 SmallVector<DynamicAPInt, 8> &sample = *boundedSample; 971 sample.append(coneSample.begin(), coneSample.end()); 972 return transform.postMultiplyWithColumn(sample); 973 } 974 975 /// Helper to evaluate an affine expression at a point. 976 /// The expression is a list of coefficients for the dimensions followed by the 977 /// constant term. 978 static DynamicAPInt valueAt(ArrayRef<DynamicAPInt> expr, 979 ArrayRef<DynamicAPInt> point) { 980 assert(expr.size() == 1 + point.size() && 981 "Dimensionalities of point and expression don't match!"); 982 DynamicAPInt value = expr.back(); 983 for (unsigned i = 0; i < point.size(); ++i) 984 value += expr[i] * point[i]; 985 return value; 986 } 987 988 /// A point satisfies an equality iff the value of the equality at the 989 /// expression is zero, and it satisfies an inequality iff the value of the 990 /// inequality at that point is non-negative. 991 bool IntegerRelation::containsPoint(ArrayRef<DynamicAPInt> point) const { 992 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 993 if (valueAt(getEquality(i), point) != 0) 994 return false; 995 } 996 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 997 if (valueAt(getInequality(i), point) < 0) 998 return false; 999 } 1000 return true; 1001 } 1002 1003 /// Just substitute the values given and check if an integer sample exists for 1004 /// the local vars. 1005 /// 1006 /// TODO: this could be made more efficient by handling divisions separately. 1007 /// Instead of finding an integer sample over all the locals, we can first 1008 /// compute the values of the locals that have division representations and 1009 /// only use the integer emptiness check for the locals that don't have this. 1010 /// Handling this correctly requires ordering the divs, though. 1011 std::optional<SmallVector<DynamicAPInt, 8>> 1012 IntegerRelation::containsPointNoLocal(ArrayRef<DynamicAPInt> point) const { 1013 assert(point.size() == getNumVars() - getNumLocalVars() && 1014 "Point should contain all vars except locals!"); 1015 assert(getVarKindOffset(VarKind::Local) == getNumVars() - getNumLocalVars() && 1016 "This function depends on locals being stored last!"); 1017 IntegerRelation copy = *this; 1018 copy.setAndEliminate(0, point); 1019 return copy.findIntegerSample(); 1020 } 1021 1022 DivisionRepr 1023 IntegerRelation::getLocalReprs(std::vector<MaybeLocalRepr> *repr) const { 1024 SmallVector<bool, 8> foundRepr(getNumVars(), false); 1025 for (unsigned i = 0, e = getNumDimAndSymbolVars(); i < e; ++i) 1026 foundRepr[i] = true; 1027 1028 unsigned localOffset = getVarKindOffset(VarKind::Local); 1029 DivisionRepr divs(getNumVars(), getNumLocalVars()); 1030 bool changed; 1031 do { 1032 // Each time changed is true, at end of this iteration, one or more local 1033 // vars have been detected as floor divs. 1034 changed = false; 1035 for (unsigned i = 0, e = getNumLocalVars(); i < e; ++i) { 1036 if (!foundRepr[i + localOffset]) { 1037 MaybeLocalRepr res = 1038 computeSingleVarRepr(*this, foundRepr, localOffset + i, 1039 divs.getDividend(i), divs.getDenom(i)); 1040 if (!res) { 1041 // No representation was found, so clear the representation and 1042 // continue. 1043 divs.clearRepr(i); 1044 continue; 1045 } 1046 foundRepr[localOffset + i] = true; 1047 if (repr) 1048 (*repr)[i] = res; 1049 changed = true; 1050 } 1051 } 1052 } while (changed); 1053 1054 return divs; 1055 } 1056 1057 /// Tightens inequalities given that we are dealing with integer spaces. This is 1058 /// analogous to the GCD test but applied to inequalities. The constant term can 1059 /// be reduced to the preceding multiple of the GCD of the coefficients, i.e., 1060 /// 64*i - 100 >= 0 => 64*i - 128 >= 0 (since 'i' is an integer). This is a 1061 /// fast method - linear in the number of coefficients. 1062 // Example on how this affects practical cases: consider the scenario: 1063 // 64*i >= 100, j = 64*i; without a tightening, elimination of i would yield 1064 // j >= 100 instead of the tighter (exact) j >= 128. 1065 void IntegerRelation::gcdTightenInequalities() { 1066 unsigned numCols = getNumCols(); 1067 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 1068 // Normalize the constraint and tighten the constant term by the GCD. 1069 DynamicAPInt gcd = inequalities.normalizeRow(i, getNumCols() - 1); 1070 if (gcd > 1) 1071 atIneq(i, numCols - 1) = floorDiv(atIneq(i, numCols - 1), gcd); 1072 } 1073 } 1074 1075 // Eliminates all variable variables in column range [posStart, posLimit). 1076 // Returns the number of variables eliminated. 1077 unsigned IntegerRelation::gaussianEliminateVars(unsigned posStart, 1078 unsigned posLimit) { 1079 // Return if variable positions to eliminate are out of range. 1080 assert(posLimit <= getNumVars()); 1081 assert(hasConsistentState()); 1082 1083 if (posStart >= posLimit) 1084 return 0; 1085 1086 gcdTightenInequalities(); 1087 1088 unsigned pivotCol = 0; 1089 for (pivotCol = posStart; pivotCol < posLimit; ++pivotCol) { 1090 // Find a row which has a non-zero coefficient in column 'j'. 1091 unsigned pivotRow; 1092 if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/true, &pivotRow)) { 1093 // No pivot row in equalities with non-zero at 'pivotCol'. 1094 if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/false, &pivotRow)) { 1095 // If inequalities are also non-zero in 'pivotCol', it can be 1096 // eliminated. 1097 continue; 1098 } 1099 break; 1100 } 1101 1102 // Eliminate variable at 'pivotCol' from each equality row. 1103 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 1104 eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart, 1105 /*isEq=*/true); 1106 equalities.normalizeRow(i); 1107 } 1108 1109 // Eliminate variable at 'pivotCol' from each inequality row. 1110 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 1111 eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart, 1112 /*isEq=*/false); 1113 inequalities.normalizeRow(i); 1114 } 1115 removeEquality(pivotRow); 1116 gcdTightenInequalities(); 1117 } 1118 // Update position limit based on number eliminated. 1119 posLimit = pivotCol; 1120 // Remove eliminated columns from all constraints. 1121 removeVarRange(posStart, posLimit); 1122 return posLimit - posStart; 1123 } 1124 1125 bool IntegerRelation::gaussianEliminate() { 1126 gcdTightenInequalities(); 1127 unsigned firstVar = 0, vars = getNumVars(); 1128 unsigned nowDone, eqs, pivotRow; 1129 for (nowDone = 0, eqs = getNumEqualities(); nowDone < eqs; ++nowDone) { 1130 // Finds the first non-empty column. 1131 for (; firstVar < vars; ++firstVar) { 1132 if (!findConstraintWithNonZeroAt(firstVar, true, &pivotRow)) 1133 continue; 1134 break; 1135 } 1136 // The matrix has been normalized to row echelon form. 1137 if (firstVar >= vars) 1138 break; 1139 1140 // The first pivot row found is below where it should currently be placed. 1141 if (pivotRow > nowDone) { 1142 equalities.swapRows(pivotRow, nowDone); 1143 pivotRow = nowDone; 1144 } 1145 1146 // Normalize all lower equations and all inequalities. 1147 for (unsigned i = nowDone + 1; i < eqs; ++i) { 1148 eliminateFromConstraint(this, i, pivotRow, firstVar, 0, true); 1149 equalities.normalizeRow(i); 1150 } 1151 for (unsigned i = 0, ineqs = getNumInequalities(); i < ineqs; ++i) { 1152 eliminateFromConstraint(this, i, pivotRow, firstVar, 0, false); 1153 inequalities.normalizeRow(i); 1154 } 1155 gcdTightenInequalities(); 1156 } 1157 1158 // No redundant rows. 1159 if (nowDone == eqs) 1160 return false; 1161 1162 // Check to see if the redundant rows constant is zero, a non-zero value means 1163 // the set is empty. 1164 for (unsigned i = nowDone; i < eqs; ++i) { 1165 if (atEq(i, vars) == 0) 1166 continue; 1167 1168 *this = getEmpty(getSpace()); 1169 return true; 1170 } 1171 // Eliminate rows that are confined to be all zeros. 1172 removeEqualityRange(nowDone, eqs); 1173 return true; 1174 } 1175 1176 // A more complex check to eliminate redundant inequalities. Uses FourierMotzkin 1177 // to check if a constraint is redundant. 1178 void IntegerRelation::removeRedundantInequalities() { 1179 SmallVector<bool, 32> redun(getNumInequalities(), false); 1180 // To check if an inequality is redundant, we replace the inequality by its 1181 // complement (for eg., i - 1 >= 0 by i <= 0), and check if the resulting 1182 // system is empty. If it is, the inequality is redundant. 1183 IntegerRelation tmpCst(*this); 1184 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1185 // Change the inequality to its complement. 1186 tmpCst.inequalities.negateRow(r); 1187 --tmpCst.atIneq(r, tmpCst.getNumCols() - 1); 1188 if (tmpCst.isEmpty()) { 1189 redun[r] = true; 1190 // Zero fill the redundant inequality. 1191 inequalities.fillRow(r, /*value=*/0); 1192 tmpCst.inequalities.fillRow(r, /*value=*/0); 1193 } else { 1194 // Reverse the change (to avoid recreating tmpCst each time). 1195 ++tmpCst.atIneq(r, tmpCst.getNumCols() - 1); 1196 tmpCst.inequalities.negateRow(r); 1197 } 1198 } 1199 1200 unsigned pos = 0; 1201 for (unsigned r = 0, e = getNumInequalities(); r < e; ++r) { 1202 if (!redun[r]) 1203 inequalities.copyRow(r, pos++); 1204 } 1205 inequalities.resizeVertically(pos); 1206 } 1207 1208 // A more complex check to eliminate redundant inequalities and equalities. Uses 1209 // Simplex to check if a constraint is redundant. 1210 void IntegerRelation::removeRedundantConstraints() { 1211 // First, we run gcdTightenInequalities. This allows us to catch some 1212 // constraints which are not redundant when considering rational solutions 1213 // but are redundant in terms of integer solutions. 1214 gcdTightenInequalities(); 1215 Simplex simplex(*this); 1216 simplex.detectRedundant(); 1217 1218 unsigned pos = 0; 1219 unsigned numIneqs = getNumInequalities(); 1220 // Scan to get rid of all inequalities marked redundant, in-place. In Simplex, 1221 // the first constraints added are the inequalities. 1222 for (unsigned r = 0; r < numIneqs; r++) { 1223 if (!simplex.isMarkedRedundant(r)) 1224 inequalities.copyRow(r, pos++); 1225 } 1226 inequalities.resizeVertically(pos); 1227 1228 // Scan to get rid of all equalities marked redundant, in-place. In Simplex, 1229 // after the inequalities, a pair of constraints for each equality is added. 1230 // An equality is redundant if both the inequalities in its pair are 1231 // redundant. 1232 pos = 0; 1233 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 1234 if (!(simplex.isMarkedRedundant(numIneqs + 2 * r) && 1235 simplex.isMarkedRedundant(numIneqs + 2 * r + 1))) 1236 equalities.copyRow(r, pos++); 1237 } 1238 equalities.resizeVertically(pos); 1239 } 1240 1241 std::optional<DynamicAPInt> IntegerRelation::computeVolume() const { 1242 assert(getNumSymbolVars() == 0 && "Symbols are not yet supported!"); 1243 1244 Simplex simplex(*this); 1245 // If the polytope is rationally empty, there are certainly no integer 1246 // points. 1247 if (simplex.isEmpty()) 1248 return DynamicAPInt(0); 1249 1250 // Just find the maximum and minimum integer value of each non-local var 1251 // separately, thus finding the number of integer values each such var can 1252 // take. Multiplying these together gives a valid overapproximation of the 1253 // number of integer points in the relation. The result this gives is 1254 // equivalent to projecting (rationally) the relation onto its non-local vars 1255 // and returning the number of integer points in a minimal axis-parallel 1256 // hyperrectangular overapproximation of that. 1257 // 1258 // We also handle the special case where one dimension is unbounded and 1259 // another dimension can take no integer values. In this case, the volume is 1260 // zero. 1261 // 1262 // If there is no such empty dimension, if any dimension is unbounded we 1263 // just return the result as unbounded. 1264 DynamicAPInt count(1); 1265 SmallVector<DynamicAPInt, 8> dim(getNumVars() + 1); 1266 bool hasUnboundedVar = false; 1267 for (unsigned i = 0, e = getNumDimAndSymbolVars(); i < e; ++i) { 1268 dim[i] = 1; 1269 auto [min, max] = simplex.computeIntegerBounds(dim); 1270 dim[i] = 0; 1271 1272 assert((!min.isEmpty() && !max.isEmpty()) && 1273 "Polytope should be rationally non-empty!"); 1274 1275 // One of the dimensions is unbounded. Note this fact. We will return 1276 // unbounded if none of the other dimensions makes the volume zero. 1277 if (min.isUnbounded() || max.isUnbounded()) { 1278 hasUnboundedVar = true; 1279 continue; 1280 } 1281 1282 // In this case there are no valid integer points and the volume is 1283 // definitely zero. 1284 if (min.getBoundedOptimum() > max.getBoundedOptimum()) 1285 return DynamicAPInt(0); 1286 1287 count *= (*max - *min + 1); 1288 } 1289 1290 if (count == 0) 1291 return DynamicAPInt(0); 1292 if (hasUnboundedVar) 1293 return {}; 1294 return count; 1295 } 1296 1297 void IntegerRelation::eliminateRedundantLocalVar(unsigned posA, unsigned posB) { 1298 assert(posA < getNumLocalVars() && "Invalid local var position"); 1299 assert(posB < getNumLocalVars() && "Invalid local var position"); 1300 1301 unsigned localOffset = getVarKindOffset(VarKind::Local); 1302 posA += localOffset; 1303 posB += localOffset; 1304 inequalities.addToColumn(posB, posA, 1); 1305 equalities.addToColumn(posB, posA, 1); 1306 removeVar(posB); 1307 } 1308 1309 /// mergeAndAlignSymbols's implementation can be broken down into two steps: 1310 /// 1. Merge and align identifiers into `other` from `this. If an identifier 1311 /// from `this` exists in `other` then we align it. Otherwise, we assume it is a 1312 /// new identifier and insert it into `other` in the same position as `this`. 1313 /// 2. Add identifiers that are in `other` but not `this to `this`. 1314 void IntegerRelation::mergeAndAlignSymbols(IntegerRelation &other) { 1315 assert(space.isUsingIds() && other.space.isUsingIds() && 1316 "both relations need to have identifers to merge and align"); 1317 1318 unsigned i = 0; 1319 for (const Identifier identifier : space.getIds(VarKind::Symbol)) { 1320 // Search in `other` starting at position `i` since the left of `i` is 1321 // aligned. 1322 const Identifier *findBegin = 1323 other.space.getIds(VarKind::Symbol).begin() + i; 1324 const Identifier *findEnd = other.space.getIds(VarKind::Symbol).end(); 1325 const Identifier *itr = std::find(findBegin, findEnd, identifier); 1326 if (itr != findEnd) { 1327 other.swapVar(other.getVarKindOffset(VarKind::Symbol) + i, 1328 other.getVarKindOffset(VarKind::Symbol) + i + 1329 std::distance(findBegin, itr)); 1330 } else { 1331 other.insertVar(VarKind::Symbol, i); 1332 other.space.setId(VarKind::Symbol, i, identifier); 1333 } 1334 ++i; 1335 } 1336 1337 for (unsigned e = other.getNumVarKind(VarKind::Symbol); i < e; ++i) { 1338 insertVar(VarKind::Symbol, i); 1339 space.setId(VarKind::Symbol, i, other.space.getId(VarKind::Symbol, i)); 1340 } 1341 } 1342 1343 /// Adds additional local ids to the sets such that they both have the union 1344 /// of the local ids in each set, without changing the set of points that 1345 /// lie in `this` and `other`. 1346 /// 1347 /// To detect local ids that always take the same value, each local id is 1348 /// represented as a floordiv with constant denominator in terms of other ids. 1349 /// After extracting these divisions, local ids in `other` with the same 1350 /// division representation as some other local id in any set are considered 1351 /// duplicate and are merged. 1352 /// 1353 /// It is possible that division representation for some local id cannot be 1354 /// obtained, and thus these local ids are not considered for detecting 1355 /// duplicates. 1356 unsigned IntegerRelation::mergeLocalVars(IntegerRelation &other) { 1357 IntegerRelation &relA = *this; 1358 IntegerRelation &relB = other; 1359 1360 unsigned oldALocals = relA.getNumLocalVars(); 1361 1362 // Merge function that merges the local variables in both sets by treating 1363 // them as the same variable. 1364 auto merge = [&relA, &relB, oldALocals](unsigned i, unsigned j) -> bool { 1365 // We only merge from local at pos j to local at pos i, where j > i. 1366 if (i >= j) 1367 return false; 1368 1369 // If i < oldALocals, we are trying to merge duplicate divs. Since we do not 1370 // want to merge duplicates in A, we ignore this call. 1371 if (j < oldALocals) 1372 return false; 1373 1374 // Merge local at pos j into local at position i. 1375 relA.eliminateRedundantLocalVar(i, j); 1376 relB.eliminateRedundantLocalVar(i, j); 1377 return true; 1378 }; 1379 1380 presburger::mergeLocalVars(*this, other, merge); 1381 1382 // Since we do not remove duplicate divisions in relA, this is guranteed to be 1383 // non-negative. 1384 return relA.getNumLocalVars() - oldALocals; 1385 } 1386 1387 bool IntegerRelation::hasOnlyDivLocals() const { 1388 return getLocalReprs().hasAllReprs(); 1389 } 1390 1391 void IntegerRelation::removeDuplicateDivs() { 1392 DivisionRepr divs = getLocalReprs(); 1393 auto merge = [this](unsigned i, unsigned j) -> bool { 1394 eliminateRedundantLocalVar(i, j); 1395 return true; 1396 }; 1397 divs.removeDuplicateDivs(merge); 1398 } 1399 1400 void IntegerRelation::simplify() { 1401 bool changed = true; 1402 // Repeat until we reach a fixed point. 1403 while (changed) { 1404 if (isObviouslyEmpty()) 1405 return; 1406 changed = false; 1407 normalizeConstraintsByGCD(); 1408 changed |= gaussianEliminate(); 1409 changed |= removeDuplicateConstraints(); 1410 } 1411 // Current set is not empty. 1412 } 1413 1414 /// Removes local variables using equalities. Each equality is checked if it 1415 /// can be reduced to the form: `e = affine-expr`, where `e` is a local 1416 /// variable and `affine-expr` is an affine expression not containing `e`. 1417 /// If an equality satisfies this form, the local variable is replaced in 1418 /// each constraint and then removed. The equality used to replace this local 1419 /// variable is also removed. 1420 void IntegerRelation::removeRedundantLocalVars() { 1421 // Normalize the equality constraints to reduce coefficients of local 1422 // variables to 1 wherever possible. 1423 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) 1424 equalities.normalizeRow(i); 1425 1426 while (true) { 1427 unsigned i, e, j, f; 1428 for (i = 0, e = getNumEqualities(); i < e; ++i) { 1429 // Find a local variable to eliminate using ith equality. 1430 for (j = getNumDimAndSymbolVars(), f = getNumVars(); j < f; ++j) 1431 if (abs(atEq(i, j)) == 1) 1432 break; 1433 1434 // Local variable can be eliminated using ith equality. 1435 if (j < f) 1436 break; 1437 } 1438 1439 // No equality can be used to eliminate a local variable. 1440 if (i == e) 1441 break; 1442 1443 // Use the ith equality to simplify other equalities. If any changes 1444 // are made to an equality constraint, it is normalized by GCD. 1445 for (unsigned k = 0, t = getNumEqualities(); k < t; ++k) { 1446 if (atEq(k, j) != 0) { 1447 eliminateFromConstraint(this, k, i, j, j, /*isEq=*/true); 1448 equalities.normalizeRow(k); 1449 } 1450 } 1451 1452 // Use the ith equality to simplify inequalities. 1453 for (unsigned k = 0, t = getNumInequalities(); k < t; ++k) 1454 eliminateFromConstraint(this, k, i, j, j, /*isEq=*/false); 1455 1456 // Remove the ith equality and the found local variable. 1457 removeVar(j); 1458 removeEquality(i); 1459 } 1460 } 1461 1462 void IntegerRelation::convertVarKind(VarKind srcKind, unsigned varStart, 1463 unsigned varLimit, VarKind dstKind, 1464 unsigned pos) { 1465 assert(varLimit <= getNumVarKind(srcKind) && "invalid id range"); 1466 1467 if (varStart >= varLimit) 1468 return; 1469 1470 unsigned srcOffset = getVarKindOffset(srcKind); 1471 unsigned dstOffset = getVarKindOffset(dstKind); 1472 unsigned convertCount = varLimit - varStart; 1473 int forwardMoveOffset = dstOffset > srcOffset ? -convertCount : 0; 1474 1475 equalities.moveColumns(srcOffset + varStart, convertCount, 1476 dstOffset + pos + forwardMoveOffset); 1477 inequalities.moveColumns(srcOffset + varStart, convertCount, 1478 dstOffset + pos + forwardMoveOffset); 1479 1480 space.convertVarKind(srcKind, varStart, varLimit - varStart, dstKind, pos); 1481 } 1482 1483 void IntegerRelation::addBound(BoundType type, unsigned pos, 1484 const DynamicAPInt &value) { 1485 assert(pos < getNumCols()); 1486 if (type == BoundType::EQ) { 1487 unsigned row = equalities.appendExtraRow(); 1488 equalities(row, pos) = 1; 1489 equalities(row, getNumCols() - 1) = -value; 1490 } else { 1491 unsigned row = inequalities.appendExtraRow(); 1492 inequalities(row, pos) = type == BoundType::LB ? 1 : -1; 1493 inequalities(row, getNumCols() - 1) = 1494 type == BoundType::LB ? -value : value; 1495 } 1496 } 1497 1498 void IntegerRelation::addBound(BoundType type, ArrayRef<DynamicAPInt> expr, 1499 const DynamicAPInt &value) { 1500 assert(type != BoundType::EQ && "EQ not implemented"); 1501 assert(expr.size() == getNumCols()); 1502 unsigned row = inequalities.appendExtraRow(); 1503 for (unsigned i = 0, e = expr.size(); i < e; ++i) 1504 inequalities(row, i) = type == BoundType::LB ? expr[i] : -expr[i]; 1505 inequalities(inequalities.getNumRows() - 1, getNumCols() - 1) += 1506 type == BoundType::LB ? -value : value; 1507 } 1508 1509 /// Adds a new local variable as the floordiv of an affine function of other 1510 /// variables, the coefficients of which are provided in 'dividend' and with 1511 /// respect to a positive constant 'divisor'. Two constraints are added to the 1512 /// system to capture equivalence with the floordiv. 1513 /// q = expr floordiv c <=> c*q <= expr <= c*q + c - 1. 1514 void IntegerRelation::addLocalFloorDiv(ArrayRef<DynamicAPInt> dividend, 1515 const DynamicAPInt &divisor) { 1516 assert(dividend.size() == getNumCols() && "incorrect dividend size"); 1517 assert(divisor > 0 && "positive divisor expected"); 1518 1519 appendVar(VarKind::Local); 1520 1521 SmallVector<DynamicAPInt, 8> dividendCopy(dividend); 1522 dividendCopy.insert(dividendCopy.end() - 1, DynamicAPInt(0)); 1523 addInequality( 1524 getDivLowerBound(dividendCopy, divisor, dividendCopy.size() - 2)); 1525 addInequality( 1526 getDivUpperBound(dividendCopy, divisor, dividendCopy.size() - 2)); 1527 } 1528 1529 /// Finds an equality that equates the specified variable to a constant. 1530 /// Returns the position of the equality row. If 'symbolic' is set to true, 1531 /// symbols are also treated like a constant, i.e., an affine function of the 1532 /// symbols is also treated like a constant. Returns -1 if such an equality 1533 /// could not be found. 1534 static int findEqualityToConstant(const IntegerRelation &cst, unsigned pos, 1535 bool symbolic = false) { 1536 assert(pos < cst.getNumVars() && "invalid position"); 1537 for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) { 1538 DynamicAPInt v = cst.atEq(r, pos); 1539 if (v * v != 1) 1540 continue; 1541 unsigned c; 1542 unsigned f = symbolic ? cst.getNumDimVars() : cst.getNumVars(); 1543 // This checks for zeros in all positions other than 'pos' in [0, f) 1544 for (c = 0; c < f; c++) { 1545 if (c == pos) 1546 continue; 1547 if (cst.atEq(r, c) != 0) { 1548 // Dependent on another variable. 1549 break; 1550 } 1551 } 1552 if (c == f) 1553 // Equality is free of other variables. 1554 return r; 1555 } 1556 return -1; 1557 } 1558 1559 LogicalResult IntegerRelation::constantFoldVar(unsigned pos) { 1560 assert(pos < getNumVars() && "invalid position"); 1561 int rowIdx; 1562 if ((rowIdx = findEqualityToConstant(*this, pos)) == -1) 1563 return failure(); 1564 1565 // atEq(rowIdx, pos) is either -1 or 1. 1566 assert(atEq(rowIdx, pos) * atEq(rowIdx, pos) == 1); 1567 DynamicAPInt constVal = -atEq(rowIdx, getNumCols() - 1) / atEq(rowIdx, pos); 1568 setAndEliminate(pos, constVal); 1569 return success(); 1570 } 1571 1572 void IntegerRelation::constantFoldVarRange(unsigned pos, unsigned num) { 1573 for (unsigned s = pos, t = pos, e = pos + num; s < e; s++) { 1574 if (constantFoldVar(t).failed()) 1575 t++; 1576 } 1577 } 1578 1579 /// Returns a non-negative constant bound on the extent (upper bound - lower 1580 /// bound) of the specified variable if it is found to be a constant; returns 1581 /// std::nullopt if it's not a constant. This methods treats symbolic variables 1582 /// specially, i.e., it looks for constant differences between affine 1583 /// expressions involving only the symbolic variables. See comments at function 1584 /// definition for example. 'lb', if provided, is set to the lower bound 1585 /// associated with the constant difference. Note that 'lb' is purely symbolic 1586 /// and thus will contain the coefficients of the symbolic variables and the 1587 /// constant coefficient. 1588 // Egs: 0 <= i <= 15, return 16. 1589 // s0 + 2 <= i <= s0 + 17, returns 16. (s0 has to be a symbol) 1590 // s0 + s1 + 16 <= d0 <= s0 + s1 + 31, returns 16. 1591 // s0 - 7 <= 8*j <= s0 returns 1 with lb = s0, lbDivisor = 8 (since lb = 1592 // ceil(s0 - 7 / 8) = floor(s0 / 8)). 1593 std::optional<DynamicAPInt> IntegerRelation::getConstantBoundOnDimSize( 1594 unsigned pos, SmallVectorImpl<DynamicAPInt> *lb, 1595 DynamicAPInt *boundFloorDivisor, SmallVectorImpl<DynamicAPInt> *ub, 1596 unsigned *minLbPos, unsigned *minUbPos) const { 1597 assert(pos < getNumDimVars() && "Invalid variable position"); 1598 1599 // Find an equality for 'pos'^th variable that equates it to some function 1600 // of the symbolic variables (+ constant). 1601 int eqPos = findEqualityToConstant(*this, pos, /*symbolic=*/true); 1602 if (eqPos != -1) { 1603 auto eq = getEquality(eqPos); 1604 // If the equality involves a local var, punt for now. 1605 // TODO: this can be handled in the future by using the explicit 1606 // representation of the local vars. 1607 if (!std::all_of(eq.begin() + getNumDimAndSymbolVars(), eq.end() - 1, 1608 [](const DynamicAPInt &coeff) { return coeff == 0; })) 1609 return std::nullopt; 1610 1611 // This variable can only take a single value. 1612 if (lb) { 1613 // Set lb to that symbolic value. 1614 lb->resize(getNumSymbolVars() + 1); 1615 if (ub) 1616 ub->resize(getNumSymbolVars() + 1); 1617 for (unsigned c = 0, f = getNumSymbolVars() + 1; c < f; c++) { 1618 DynamicAPInt v = atEq(eqPos, pos); 1619 // atEq(eqRow, pos) is either -1 or 1. 1620 assert(v * v == 1); 1621 (*lb)[c] = v < 0 ? atEq(eqPos, getNumDimVars() + c) / -v 1622 : -atEq(eqPos, getNumDimVars() + c) / v; 1623 // Since this is an equality, ub = lb. 1624 if (ub) 1625 (*ub)[c] = (*lb)[c]; 1626 } 1627 assert(boundFloorDivisor && 1628 "both lb and divisor or none should be provided"); 1629 *boundFloorDivisor = 1; 1630 } 1631 if (minLbPos) 1632 *minLbPos = eqPos; 1633 if (minUbPos) 1634 *minUbPos = eqPos; 1635 return DynamicAPInt(1); 1636 } 1637 1638 // Check if the variable appears at all in any of the inequalities. 1639 unsigned r, e; 1640 for (r = 0, e = getNumInequalities(); r < e; r++) { 1641 if (atIneq(r, pos) != 0) 1642 break; 1643 } 1644 if (r == e) 1645 // If it doesn't, there isn't a bound on it. 1646 return std::nullopt; 1647 1648 // Positions of constraints that are lower/upper bounds on the variable. 1649 SmallVector<unsigned, 4> lbIndices, ubIndices; 1650 1651 // Gather all symbolic lower bounds and upper bounds of the variable, i.e., 1652 // the bounds can only involve symbolic (and local) variables. Since the 1653 // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower 1654 // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1. 1655 getLowerAndUpperBoundIndices(pos, &lbIndices, &ubIndices, 1656 /*eqIndices=*/nullptr, /*offset=*/0, 1657 /*num=*/getNumDimVars()); 1658 1659 std::optional<DynamicAPInt> minDiff; 1660 unsigned minLbPosition = 0, minUbPosition = 0; 1661 for (auto ubPos : ubIndices) { 1662 for (auto lbPos : lbIndices) { 1663 // Look for a lower bound and an upper bound that only differ by a 1664 // constant, i.e., pairs of the form 0 <= c_pos - f(c_i's) <= diffConst. 1665 // For example, if ii is the pos^th variable, we are looking for 1666 // constraints like ii >= i, ii <= ii + 50, 50 being the difference. The 1667 // minimum among all such constant differences is kept since that's the 1668 // constant bounding the extent of the pos^th variable. 1669 unsigned j, e; 1670 for (j = 0, e = getNumCols() - 1; j < e; j++) 1671 if (atIneq(ubPos, j) != -atIneq(lbPos, j)) { 1672 break; 1673 } 1674 if (j < getNumCols() - 1) 1675 continue; 1676 DynamicAPInt diff = ceilDiv(atIneq(ubPos, getNumCols() - 1) + 1677 atIneq(lbPos, getNumCols() - 1) + 1, 1678 atIneq(lbPos, pos)); 1679 // This bound is non-negative by definition. 1680 diff = std::max<DynamicAPInt>(diff, DynamicAPInt(0)); 1681 if (minDiff == std::nullopt || diff < minDiff) { 1682 minDiff = diff; 1683 minLbPosition = lbPos; 1684 minUbPosition = ubPos; 1685 } 1686 } 1687 } 1688 if (lb && minDiff) { 1689 // Set lb to the symbolic lower bound. 1690 lb->resize(getNumSymbolVars() + 1); 1691 if (ub) 1692 ub->resize(getNumSymbolVars() + 1); 1693 // The lower bound is the ceildiv of the lb constraint over the coefficient 1694 // of the variable at 'pos'. We express the ceildiv equivalently as a floor 1695 // for uniformity. For eg., if the lower bound constraint was: 32*d0 - N + 1696 // 31 >= 0, the lower bound for d0 is ceil(N - 31, 32), i.e., floor(N, 32). 1697 *boundFloorDivisor = atIneq(minLbPosition, pos); 1698 assert(*boundFloorDivisor == -atIneq(minUbPosition, pos)); 1699 for (unsigned c = 0, e = getNumSymbolVars() + 1; c < e; c++) { 1700 (*lb)[c] = -atIneq(minLbPosition, getNumDimVars() + c); 1701 } 1702 if (ub) { 1703 for (unsigned c = 0, e = getNumSymbolVars() + 1; c < e; c++) 1704 (*ub)[c] = atIneq(minUbPosition, getNumDimVars() + c); 1705 } 1706 // The lower bound leads to a ceildiv while the upper bound is a floordiv 1707 // whenever the coefficient at pos != 1. ceildiv (val / d) = floordiv (val + 1708 // d - 1 / d); hence, the addition of 'atIneq(minLbPosition, pos) - 1' to 1709 // the constant term for the lower bound. 1710 (*lb)[getNumSymbolVars()] += atIneq(minLbPosition, pos) - 1; 1711 } 1712 if (minLbPos) 1713 *minLbPos = minLbPosition; 1714 if (minUbPos) 1715 *minUbPos = minUbPosition; 1716 return minDiff; 1717 } 1718 1719 template <bool isLower> 1720 std::optional<DynamicAPInt> 1721 IntegerRelation::computeConstantLowerOrUpperBound(unsigned pos) { 1722 assert(pos < getNumVars() && "invalid position"); 1723 // Project to 'pos'. 1724 projectOut(0, pos); 1725 projectOut(1, getNumVars() - 1); 1726 // Check if there's an equality equating the '0'^th variable to a constant. 1727 int eqRowIdx = findEqualityToConstant(*this, 0, /*symbolic=*/false); 1728 if (eqRowIdx != -1) 1729 // atEq(rowIdx, 0) is either -1 or 1. 1730 return -atEq(eqRowIdx, getNumCols() - 1) / atEq(eqRowIdx, 0); 1731 1732 // Check if the variable appears at all in any of the inequalities. 1733 unsigned r, e; 1734 for (r = 0, e = getNumInequalities(); r < e; r++) { 1735 if (atIneq(r, 0) != 0) 1736 break; 1737 } 1738 if (r == e) 1739 // If it doesn't, there isn't a bound on it. 1740 return std::nullopt; 1741 1742 std::optional<DynamicAPInt> minOrMaxConst; 1743 1744 // Take the max across all const lower bounds (or min across all constant 1745 // upper bounds). 1746 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1747 if (isLower) { 1748 if (atIneq(r, 0) <= 0) 1749 // Not a lower bound. 1750 continue; 1751 } else if (atIneq(r, 0) >= 0) { 1752 // Not an upper bound. 1753 continue; 1754 } 1755 unsigned c, f; 1756 for (c = 0, f = getNumCols() - 1; c < f; c++) 1757 if (c != 0 && atIneq(r, c) != 0) 1758 break; 1759 if (c < getNumCols() - 1) 1760 // Not a constant bound. 1761 continue; 1762 1763 DynamicAPInt boundConst = 1764 isLower ? ceilDiv(-atIneq(r, getNumCols() - 1), atIneq(r, 0)) 1765 : floorDiv(atIneq(r, getNumCols() - 1), -atIneq(r, 0)); 1766 if (isLower) { 1767 if (minOrMaxConst == std::nullopt || boundConst > minOrMaxConst) 1768 minOrMaxConst = boundConst; 1769 } else { 1770 if (minOrMaxConst == std::nullopt || boundConst < minOrMaxConst) 1771 minOrMaxConst = boundConst; 1772 } 1773 } 1774 return minOrMaxConst; 1775 } 1776 1777 std::optional<DynamicAPInt> 1778 IntegerRelation::getConstantBound(BoundType type, unsigned pos) const { 1779 if (type == BoundType::LB) 1780 return IntegerRelation(*this) 1781 .computeConstantLowerOrUpperBound</*isLower=*/true>(pos); 1782 if (type == BoundType::UB) 1783 return IntegerRelation(*this) 1784 .computeConstantLowerOrUpperBound</*isLower=*/false>(pos); 1785 1786 assert(type == BoundType::EQ && "expected EQ"); 1787 std::optional<DynamicAPInt> lb = 1788 IntegerRelation(*this).computeConstantLowerOrUpperBound</*isLower=*/true>( 1789 pos); 1790 std::optional<DynamicAPInt> ub = 1791 IntegerRelation(*this) 1792 .computeConstantLowerOrUpperBound</*isLower=*/false>(pos); 1793 return (lb && ub && *lb == *ub) ? std::optional<DynamicAPInt>(*ub) 1794 : std::nullopt; 1795 } 1796 1797 // A simple (naive and conservative) check for hyper-rectangularity. 1798 bool IntegerRelation::isHyperRectangular(unsigned pos, unsigned num) const { 1799 assert(pos < getNumCols() - 1); 1800 // Check for two non-zero coefficients in the range [pos, pos + sum). 1801 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1802 unsigned sum = 0; 1803 for (unsigned c = pos; c < pos + num; c++) { 1804 if (atIneq(r, c) != 0) 1805 sum++; 1806 } 1807 if (sum > 1) 1808 return false; 1809 } 1810 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 1811 unsigned sum = 0; 1812 for (unsigned c = pos; c < pos + num; c++) { 1813 if (atEq(r, c) != 0) 1814 sum++; 1815 } 1816 if (sum > 1) 1817 return false; 1818 } 1819 return true; 1820 } 1821 1822 /// Removes duplicate constraints, trivially true constraints, and constraints 1823 /// that can be detected as redundant as a result of differing only in their 1824 /// constant term part. A constraint of the form <non-negative constant> >= 0 is 1825 /// considered trivially true. 1826 // Uses a DenseSet to hash and detect duplicates followed by a linear scan to 1827 // remove duplicates in place. 1828 void IntegerRelation::removeTrivialRedundancy() { 1829 gcdTightenInequalities(); 1830 normalizeConstraintsByGCD(); 1831 1832 // A map used to detect redundancy stemming from constraints that only differ 1833 // in their constant term. The value stored is <row position, const term> 1834 // for a given row. 1835 SmallDenseMap<ArrayRef<DynamicAPInt>, std::pair<unsigned, DynamicAPInt>> 1836 rowsWithoutConstTerm; 1837 // To unique rows. 1838 SmallDenseSet<ArrayRef<DynamicAPInt>, 8> rowSet; 1839 1840 // Check if constraint is of the form <non-negative-constant> >= 0. 1841 auto isTriviallyValid = [&](unsigned r) -> bool { 1842 for (unsigned c = 0, e = getNumCols() - 1; c < e; c++) { 1843 if (atIneq(r, c) != 0) 1844 return false; 1845 } 1846 return atIneq(r, getNumCols() - 1) >= 0; 1847 }; 1848 1849 // Detect and mark redundant constraints. 1850 SmallVector<bool, 256> redunIneq(getNumInequalities(), false); 1851 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1852 DynamicAPInt *rowStart = &inequalities(r, 0); 1853 auto row = ArrayRef<DynamicAPInt>(rowStart, getNumCols()); 1854 if (isTriviallyValid(r) || !rowSet.insert(row).second) { 1855 redunIneq[r] = true; 1856 continue; 1857 } 1858 1859 // Among constraints that only differ in the constant term part, mark 1860 // everything other than the one with the smallest constant term redundant. 1861 // (eg: among i - 16j - 5 >= 0, i - 16j - 1 >=0, i - 16j - 7 >= 0, the 1862 // former two are redundant). 1863 DynamicAPInt constTerm = atIneq(r, getNumCols() - 1); 1864 auto rowWithoutConstTerm = 1865 ArrayRef<DynamicAPInt>(rowStart, getNumCols() - 1); 1866 const auto &ret = 1867 rowsWithoutConstTerm.insert({rowWithoutConstTerm, {r, constTerm}}); 1868 if (!ret.second) { 1869 // Check if the other constraint has a higher constant term. 1870 auto &val = ret.first->second; 1871 if (val.second > constTerm) { 1872 // The stored row is redundant. Mark it so, and update with this one. 1873 redunIneq[val.first] = true; 1874 val = {r, constTerm}; 1875 } else { 1876 // The one stored makes this one redundant. 1877 redunIneq[r] = true; 1878 } 1879 } 1880 } 1881 1882 // Scan to get rid of all rows marked redundant, in-place. 1883 unsigned pos = 0; 1884 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) 1885 if (!redunIneq[r]) 1886 inequalities.copyRow(r, pos++); 1887 1888 inequalities.resizeVertically(pos); 1889 1890 // TODO: consider doing this for equalities as well, but probably not worth 1891 // the savings. 1892 } 1893 1894 #undef DEBUG_TYPE 1895 #define DEBUG_TYPE "fm" 1896 1897 /// Eliminates variable at the specified position using Fourier-Motzkin 1898 /// variable elimination. This technique is exact for rational spaces but 1899 /// conservative (in "rare" cases) for integer spaces. The operation corresponds 1900 /// to a projection operation yielding the (convex) set of integer points 1901 /// contained in the rational shadow of the set. An emptiness test that relies 1902 /// on this method will guarantee emptiness, i.e., it disproves the existence of 1903 /// a solution if it says it's empty. 1904 /// If a non-null isResultIntegerExact is passed, it is set to true if the 1905 /// result is also integer exact. If it's set to false, the obtained solution 1906 /// *may* not be exact, i.e., it may contain integer points that do not have an 1907 /// integer pre-image in the original set. 1908 /// 1909 /// Eg: 1910 /// j >= 0, j <= i + 1 1911 /// i >= 0, i <= N + 1 1912 /// Eliminating i yields, 1913 /// j >= 0, 0 <= N + 1, j - 1 <= N + 1 1914 /// 1915 /// If darkShadow = true, this method computes the dark shadow on elimination; 1916 /// the dark shadow is a convex integer subset of the exact integer shadow. A 1917 /// non-empty dark shadow proves the existence of an integer solution. The 1918 /// elimination in such a case could however be an under-approximation, and thus 1919 /// should not be used for scanning sets or used by itself for dependence 1920 /// checking. 1921 /// 1922 /// Eg: 2-d set, * represents grid points, 'o' represents a point in the set. 1923 /// ^ 1924 /// | 1925 /// | * * * * o o 1926 /// i | * * o o o o 1927 /// | o * * * * * 1928 /// ---------------> 1929 /// j -> 1930 /// 1931 /// Eliminating i from this system (projecting on the j dimension): 1932 /// rational shadow / integer light shadow: 1 <= j <= 6 1933 /// dark shadow: 3 <= j <= 6 1934 /// exact integer shadow: j = 1 \union 3 <= j <= 6 1935 /// holes/splinters: j = 2 1936 /// 1937 /// darkShadow = false, isResultIntegerExact = nullptr are default values. 1938 // TODO: a slight modification to yield dark shadow version of FM (tightened), 1939 // which can prove the existence of a solution if there is one. 1940 void IntegerRelation::fourierMotzkinEliminate(unsigned pos, bool darkShadow, 1941 bool *isResultIntegerExact) { 1942 LLVM_DEBUG(llvm::dbgs() << "FM input (eliminate pos " << pos << "):\n"); 1943 LLVM_DEBUG(dump()); 1944 assert(pos < getNumVars() && "invalid position"); 1945 assert(hasConsistentState()); 1946 1947 // Check if this variable can be eliminated through a substitution. 1948 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 1949 if (atEq(r, pos) != 0) { 1950 // Use Gaussian elimination here (since we have an equality). 1951 LogicalResult ret = gaussianEliminateVar(pos); 1952 (void)ret; 1953 assert(ret.succeeded() && "Gaussian elimination guaranteed to succeed"); 1954 LLVM_DEBUG(llvm::dbgs() << "FM output (through Gaussian elimination):\n"); 1955 LLVM_DEBUG(dump()); 1956 return; 1957 } 1958 } 1959 1960 // A fast linear time tightening. 1961 gcdTightenInequalities(); 1962 1963 // Check if the variable appears at all in any of the inequalities. 1964 if (isColZero(pos)) { 1965 // If it doesn't appear, just remove the column and return. 1966 // TODO: refactor removeColumns to use it from here. 1967 removeVar(pos); 1968 LLVM_DEBUG(llvm::dbgs() << "FM output:\n"); 1969 LLVM_DEBUG(dump()); 1970 return; 1971 } 1972 1973 // Positions of constraints that are lower bounds on the variable. 1974 SmallVector<unsigned, 4> lbIndices; 1975 // Positions of constraints that are lower bounds on the variable. 1976 SmallVector<unsigned, 4> ubIndices; 1977 // Positions of constraints that do not involve the variable. 1978 std::vector<unsigned> nbIndices; 1979 nbIndices.reserve(getNumInequalities()); 1980 1981 // Gather all lower bounds and upper bounds of the variable. Since the 1982 // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower 1983 // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1. 1984 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1985 if (atIneq(r, pos) == 0) { 1986 // Var does not appear in bound. 1987 nbIndices.emplace_back(r); 1988 } else if (atIneq(r, pos) >= 1) { 1989 // Lower bound. 1990 lbIndices.emplace_back(r); 1991 } else { 1992 // Upper bound. 1993 ubIndices.emplace_back(r); 1994 } 1995 } 1996 1997 PresburgerSpace newSpace = getSpace(); 1998 VarKind idKindRemove = newSpace.getVarKindAt(pos); 1999 unsigned relativePos = pos - newSpace.getVarKindOffset(idKindRemove); 2000 newSpace.removeVarRange(idKindRemove, relativePos, relativePos + 1); 2001 2002 /// Create the new system which has one variable less. 2003 IntegerRelation newRel(lbIndices.size() * ubIndices.size() + nbIndices.size(), 2004 getNumEqualities(), getNumCols() - 1, newSpace); 2005 2006 // This will be used to check if the elimination was integer exact. 2007 bool allLCMsAreOne = true; 2008 2009 // Let x be the variable we are eliminating. 2010 // For each lower bound, lb <= c_l*x, and each upper bound c_u*x <= ub, (note 2011 // that c_l, c_u >= 1) we have: 2012 // lb*lcm(c_l, c_u)/c_l <= lcm(c_l, c_u)*x <= ub*lcm(c_l, c_u)/c_u 2013 // We thus generate a constraint: 2014 // lcm(c_l, c_u)/c_l*lb <= lcm(c_l, c_u)/c_u*ub. 2015 // Note if c_l = c_u = 1, all integer points captured by the resulting 2016 // constraint correspond to integer points in the original system (i.e., they 2017 // have integer pre-images). Hence, if the lcm's are all 1, the elimination is 2018 // integer exact. 2019 for (auto ubPos : ubIndices) { 2020 for (auto lbPos : lbIndices) { 2021 SmallVector<DynamicAPInt, 4> ineq; 2022 ineq.reserve(newRel.getNumCols()); 2023 DynamicAPInt lbCoeff = atIneq(lbPos, pos); 2024 // Note that in the comments above, ubCoeff is the negation of the 2025 // coefficient in the canonical form as the view taken here is that of the 2026 // term being moved to the other size of '>='. 2027 DynamicAPInt ubCoeff = -atIneq(ubPos, pos); 2028 // TODO: refactor this loop to avoid all branches inside. 2029 for (unsigned l = 0, e = getNumCols(); l < e; l++) { 2030 if (l == pos) 2031 continue; 2032 assert(lbCoeff >= 1 && ubCoeff >= 1 && "bounds wrongly identified"); 2033 DynamicAPInt lcm = llvm::lcm(lbCoeff, ubCoeff); 2034 ineq.emplace_back(atIneq(ubPos, l) * (lcm / ubCoeff) + 2035 atIneq(lbPos, l) * (lcm / lbCoeff)); 2036 assert(lcm > 0 && "lcm should be positive!"); 2037 if (lcm != 1) 2038 allLCMsAreOne = false; 2039 } 2040 if (darkShadow) { 2041 // The dark shadow is a convex subset of the exact integer shadow. If 2042 // there is a point here, it proves the existence of a solution. 2043 ineq[ineq.size() - 1] += lbCoeff * ubCoeff - lbCoeff - ubCoeff + 1; 2044 } 2045 // TODO: we need to have a way to add inequalities in-place in 2046 // IntegerRelation instead of creating and copying over. 2047 newRel.addInequality(ineq); 2048 } 2049 } 2050 2051 LLVM_DEBUG(llvm::dbgs() << "FM isResultIntegerExact: " << allLCMsAreOne 2052 << "\n"); 2053 if (allLCMsAreOne && isResultIntegerExact) 2054 *isResultIntegerExact = true; 2055 2056 // Copy over the constraints not involving this variable. 2057 for (auto nbPos : nbIndices) { 2058 SmallVector<DynamicAPInt, 4> ineq; 2059 ineq.reserve(getNumCols() - 1); 2060 for (unsigned l = 0, e = getNumCols(); l < e; l++) { 2061 if (l == pos) 2062 continue; 2063 ineq.emplace_back(atIneq(nbPos, l)); 2064 } 2065 newRel.addInequality(ineq); 2066 } 2067 2068 assert(newRel.getNumConstraints() == 2069 lbIndices.size() * ubIndices.size() + nbIndices.size()); 2070 2071 // Copy over the equalities. 2072 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 2073 SmallVector<DynamicAPInt, 4> eq; 2074 eq.reserve(newRel.getNumCols()); 2075 for (unsigned l = 0, e = getNumCols(); l < e; l++) { 2076 if (l == pos) 2077 continue; 2078 eq.emplace_back(atEq(r, l)); 2079 } 2080 newRel.addEquality(eq); 2081 } 2082 2083 // GCD tightening and normalization allows detection of more trivially 2084 // redundant constraints. 2085 newRel.gcdTightenInequalities(); 2086 newRel.normalizeConstraintsByGCD(); 2087 newRel.removeTrivialRedundancy(); 2088 clearAndCopyFrom(newRel); 2089 LLVM_DEBUG(llvm::dbgs() << "FM output:\n"); 2090 LLVM_DEBUG(dump()); 2091 } 2092 2093 #undef DEBUG_TYPE 2094 #define DEBUG_TYPE "presburger" 2095 2096 void IntegerRelation::projectOut(unsigned pos, unsigned num) { 2097 if (num == 0) 2098 return; 2099 2100 // 'pos' can be at most getNumCols() - 2 if num > 0. 2101 assert((getNumCols() < 2 || pos <= getNumCols() - 2) && "invalid position"); 2102 assert(pos + num < getNumCols() && "invalid range"); 2103 2104 // Eliminate as many variables as possible using Gaussian elimination. 2105 unsigned currentPos = pos; 2106 unsigned numToEliminate = num; 2107 unsigned numGaussianEliminated = 0; 2108 2109 while (currentPos < getNumVars()) { 2110 unsigned curNumEliminated = 2111 gaussianEliminateVars(currentPos, currentPos + numToEliminate); 2112 ++currentPos; 2113 numToEliminate -= curNumEliminated + 1; 2114 numGaussianEliminated += curNumEliminated; 2115 } 2116 2117 // Eliminate the remaining using Fourier-Motzkin. 2118 for (unsigned i = 0; i < num - numGaussianEliminated; i++) { 2119 unsigned numToEliminate = num - numGaussianEliminated - i; 2120 fourierMotzkinEliminate( 2121 getBestVarToEliminate(*this, pos, pos + numToEliminate)); 2122 } 2123 2124 // Fast/trivial simplifications. 2125 gcdTightenInequalities(); 2126 // Normalize constraints after tightening since the latter impacts this, but 2127 // not the other way round. 2128 normalizeConstraintsByGCD(); 2129 } 2130 2131 namespace { 2132 2133 enum BoundCmpResult { Greater, Less, Equal, Unknown }; 2134 2135 /// Compares two affine bounds whose coefficients are provided in 'first' and 2136 /// 'second'. The last coefficient is the constant term. 2137 static BoundCmpResult compareBounds(ArrayRef<DynamicAPInt> a, 2138 ArrayRef<DynamicAPInt> b) { 2139 assert(a.size() == b.size()); 2140 2141 // For the bounds to be comparable, their corresponding variable 2142 // coefficients should be equal; the constant terms are then compared to 2143 // determine less/greater/equal. 2144 2145 if (!std::equal(a.begin(), a.end() - 1, b.begin())) 2146 return Unknown; 2147 2148 if (a.back() == b.back()) 2149 return Equal; 2150 2151 return a.back() < b.back() ? Less : Greater; 2152 } 2153 } // namespace 2154 2155 // Returns constraints that are common to both A & B. 2156 static void getCommonConstraints(const IntegerRelation &a, 2157 const IntegerRelation &b, IntegerRelation &c) { 2158 c = IntegerRelation(a.getSpace()); 2159 // a naive O(n^2) check should be enough here given the input sizes. 2160 for (unsigned r = 0, e = a.getNumInequalities(); r < e; ++r) { 2161 for (unsigned s = 0, f = b.getNumInequalities(); s < f; ++s) { 2162 if (a.getInequality(r) == b.getInequality(s)) { 2163 c.addInequality(a.getInequality(r)); 2164 break; 2165 } 2166 } 2167 } 2168 for (unsigned r = 0, e = a.getNumEqualities(); r < e; ++r) { 2169 for (unsigned s = 0, f = b.getNumEqualities(); s < f; ++s) { 2170 if (a.getEquality(r) == b.getEquality(s)) { 2171 c.addEquality(a.getEquality(r)); 2172 break; 2173 } 2174 } 2175 } 2176 } 2177 2178 // Computes the bounding box with respect to 'other' by finding the min of the 2179 // lower bounds and the max of the upper bounds along each of the dimensions. 2180 LogicalResult 2181 IntegerRelation::unionBoundingBox(const IntegerRelation &otherCst) { 2182 assert(space.isEqual(otherCst.getSpace()) && "Spaces should match."); 2183 assert(getNumLocalVars() == 0 && "local ids not supported yet here"); 2184 2185 // Get the constraints common to both systems; these will be added as is to 2186 // the union. 2187 IntegerRelation commonCst(PresburgerSpace::getRelationSpace()); 2188 getCommonConstraints(*this, otherCst, commonCst); 2189 2190 std::vector<SmallVector<DynamicAPInt, 8>> boundingLbs; 2191 std::vector<SmallVector<DynamicAPInt, 8>> boundingUbs; 2192 boundingLbs.reserve(2 * getNumDimVars()); 2193 boundingUbs.reserve(2 * getNumDimVars()); 2194 2195 // To hold lower and upper bounds for each dimension. 2196 SmallVector<DynamicAPInt, 4> lb, otherLb, ub, otherUb; 2197 // To compute min of lower bounds and max of upper bounds for each dimension. 2198 SmallVector<DynamicAPInt, 4> minLb(getNumSymbolVars() + 1); 2199 SmallVector<DynamicAPInt, 4> maxUb(getNumSymbolVars() + 1); 2200 // To compute final new lower and upper bounds for the union. 2201 SmallVector<DynamicAPInt, 8> newLb(getNumCols()), newUb(getNumCols()); 2202 2203 DynamicAPInt lbFloorDivisor, otherLbFloorDivisor; 2204 for (unsigned d = 0, e = getNumDimVars(); d < e; ++d) { 2205 auto extent = getConstantBoundOnDimSize(d, &lb, &lbFloorDivisor, &ub); 2206 if (!extent.has_value()) 2207 // TODO: symbolic extents when necessary. 2208 // TODO: handle union if a dimension is unbounded. 2209 return failure(); 2210 2211 auto otherExtent = otherCst.getConstantBoundOnDimSize( 2212 d, &otherLb, &otherLbFloorDivisor, &otherUb); 2213 if (!otherExtent.has_value() || lbFloorDivisor != otherLbFloorDivisor) 2214 // TODO: symbolic extents when necessary. 2215 return failure(); 2216 2217 assert(lbFloorDivisor > 0 && "divisor always expected to be positive"); 2218 2219 auto res = compareBounds(lb, otherLb); 2220 // Identify min. 2221 if (res == BoundCmpResult::Less || res == BoundCmpResult::Equal) { 2222 minLb = lb; 2223 // Since the divisor is for a floordiv, we need to convert to ceildiv, 2224 // i.e., i >= expr floordiv div <=> i >= (expr - div + 1) ceildiv div <=> 2225 // div * i >= expr - div + 1. 2226 minLb.back() -= lbFloorDivisor - 1; 2227 } else if (res == BoundCmpResult::Greater) { 2228 minLb = otherLb; 2229 minLb.back() -= otherLbFloorDivisor - 1; 2230 } else { 2231 // Uncomparable - check for constant lower/upper bounds. 2232 auto constLb = getConstantBound(BoundType::LB, d); 2233 auto constOtherLb = otherCst.getConstantBound(BoundType::LB, d); 2234 if (!constLb.has_value() || !constOtherLb.has_value()) 2235 return failure(); 2236 std::fill(minLb.begin(), minLb.end(), 0); 2237 minLb.back() = std::min(*constLb, *constOtherLb); 2238 } 2239 2240 // Do the same for ub's but max of upper bounds. Identify max. 2241 auto uRes = compareBounds(ub, otherUb); 2242 if (uRes == BoundCmpResult::Greater || uRes == BoundCmpResult::Equal) { 2243 maxUb = ub; 2244 } else if (uRes == BoundCmpResult::Less) { 2245 maxUb = otherUb; 2246 } else { 2247 // Uncomparable - check for constant lower/upper bounds. 2248 auto constUb = getConstantBound(BoundType::UB, d); 2249 auto constOtherUb = otherCst.getConstantBound(BoundType::UB, d); 2250 if (!constUb.has_value() || !constOtherUb.has_value()) 2251 return failure(); 2252 std::fill(maxUb.begin(), maxUb.end(), 0); 2253 maxUb.back() = std::max(*constUb, *constOtherUb); 2254 } 2255 2256 std::fill(newLb.begin(), newLb.end(), 0); 2257 std::fill(newUb.begin(), newUb.end(), 0); 2258 2259 // The divisor for lb, ub, otherLb, otherUb at this point is lbDivisor, 2260 // and so it's the divisor for newLb and newUb as well. 2261 newLb[d] = lbFloorDivisor; 2262 newUb[d] = -lbFloorDivisor; 2263 // Copy over the symbolic part + constant term. 2264 std::copy(minLb.begin(), minLb.end(), newLb.begin() + getNumDimVars()); 2265 std::transform(newLb.begin() + getNumDimVars(), newLb.end(), 2266 newLb.begin() + getNumDimVars(), 2267 std::negate<DynamicAPInt>()); 2268 std::copy(maxUb.begin(), maxUb.end(), newUb.begin() + getNumDimVars()); 2269 2270 boundingLbs.emplace_back(newLb); 2271 boundingUbs.emplace_back(newUb); 2272 } 2273 2274 // Clear all constraints and add the lower/upper bounds for the bounding box. 2275 clearConstraints(); 2276 for (unsigned d = 0, e = getNumDimVars(); d < e; ++d) { 2277 addInequality(boundingLbs[d]); 2278 addInequality(boundingUbs[d]); 2279 } 2280 2281 // Add the constraints that were common to both systems. 2282 append(commonCst); 2283 removeTrivialRedundancy(); 2284 2285 // TODO: copy over pure symbolic constraints from this and 'other' over to the 2286 // union (since the above are just the union along dimensions); we shouldn't 2287 // be discarding any other constraints on the symbols. 2288 2289 return success(); 2290 } 2291 2292 bool IntegerRelation::isColZero(unsigned pos) const { 2293 unsigned rowPos; 2294 return !findConstraintWithNonZeroAt(pos, /*isEq=*/false, &rowPos) && 2295 !findConstraintWithNonZeroAt(pos, /*isEq=*/true, &rowPos); 2296 } 2297 2298 /// Find positions of inequalities and equalities that do not have a coefficient 2299 /// for [pos, pos + num) variables. 2300 static void getIndependentConstraints(const IntegerRelation &cst, unsigned pos, 2301 unsigned num, 2302 SmallVectorImpl<unsigned> &nbIneqIndices, 2303 SmallVectorImpl<unsigned> &nbEqIndices) { 2304 assert(pos < cst.getNumVars() && "invalid start position"); 2305 assert(pos + num <= cst.getNumVars() && "invalid limit"); 2306 2307 for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) { 2308 // The bounds are to be independent of [offset, offset + num) columns. 2309 unsigned c; 2310 for (c = pos; c < pos + num; ++c) { 2311 if (cst.atIneq(r, c) != 0) 2312 break; 2313 } 2314 if (c == pos + num) 2315 nbIneqIndices.emplace_back(r); 2316 } 2317 2318 for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) { 2319 // The bounds are to be independent of [offset, offset + num) columns. 2320 unsigned c; 2321 for (c = pos; c < pos + num; ++c) { 2322 if (cst.atEq(r, c) != 0) 2323 break; 2324 } 2325 if (c == pos + num) 2326 nbEqIndices.emplace_back(r); 2327 } 2328 } 2329 2330 void IntegerRelation::removeIndependentConstraints(unsigned pos, unsigned num) { 2331 assert(pos + num <= getNumVars() && "invalid range"); 2332 2333 // Remove constraints that are independent of these variables. 2334 SmallVector<unsigned, 4> nbIneqIndices, nbEqIndices; 2335 getIndependentConstraints(*this, /*pos=*/0, num, nbIneqIndices, nbEqIndices); 2336 2337 // Iterate in reverse so that indices don't have to be updated. 2338 // TODO: This method can be made more efficient (because removal of each 2339 // inequality leads to much shifting/copying in the underlying buffer). 2340 for (auto nbIndex : llvm::reverse(nbIneqIndices)) 2341 removeInequality(nbIndex); 2342 for (auto nbIndex : llvm::reverse(nbEqIndices)) 2343 removeEquality(nbIndex); 2344 } 2345 2346 IntegerPolyhedron IntegerRelation::getDomainSet() const { 2347 IntegerRelation copyRel = *this; 2348 2349 // Convert Range variables to Local variables. 2350 copyRel.convertVarKind(VarKind::Range, 0, getNumVarKind(VarKind::Range), 2351 VarKind::Local); 2352 2353 // Convert Domain variables to SetDim(Range) variables. 2354 copyRel.convertVarKind(VarKind::Domain, 0, getNumVarKind(VarKind::Domain), 2355 VarKind::SetDim); 2356 2357 return IntegerPolyhedron(std::move(copyRel)); 2358 } 2359 2360 bool IntegerRelation::removeDuplicateConstraints() { 2361 bool changed = false; 2362 SmallDenseMap<ArrayRef<DynamicAPInt>, unsigned> hashTable; 2363 unsigned ineqs = getNumInequalities(), cols = getNumCols(); 2364 2365 if (ineqs <= 1) 2366 return changed; 2367 2368 // Check if the non-constant part of the constraint is the same. 2369 ArrayRef<DynamicAPInt> row = getInequality(0).drop_back(); 2370 hashTable.insert({row, 0}); 2371 for (unsigned k = 1; k < ineqs; ++k) { 2372 row = getInequality(k).drop_back(); 2373 if (hashTable.try_emplace(row, k).second) 2374 continue; 2375 2376 // For identical cases, keep only the smaller part of the constant term. 2377 unsigned l = hashTable[row]; 2378 changed = true; 2379 if (atIneq(k, cols - 1) <= atIneq(l, cols - 1)) 2380 inequalities.swapRows(k, l); 2381 removeInequality(k); 2382 --k; 2383 --ineqs; 2384 } 2385 2386 // Check the neg form of each inequality, need an extra vector to store it. 2387 SmallVector<DynamicAPInt> negIneq(cols - 1); 2388 for (unsigned k = 0; k < ineqs; ++k) { 2389 row = getInequality(k).drop_back(); 2390 negIneq.assign(row.begin(), row.end()); 2391 for (DynamicAPInt &ele : negIneq) 2392 ele = -ele; 2393 if (!hashTable.contains(negIneq)) 2394 continue; 2395 2396 // For cases where the neg is the same as other inequalities, check that the 2397 // sum of their constant terms is positive. 2398 unsigned l = hashTable[row]; 2399 auto sum = atIneq(l, cols - 1) + atIneq(k, cols - 1); 2400 if (sum > 0 || l == k) 2401 continue; 2402 2403 // A sum of constant terms equal to zero combines two inequalities into one 2404 // equation, less than zero means the set is empty. 2405 changed = true; 2406 if (k < l) 2407 std::swap(l, k); 2408 if (sum == 0) { 2409 addEquality(getInequality(k)); 2410 removeInequality(k); 2411 removeInequality(l); 2412 } else 2413 *this = getEmpty(getSpace()); 2414 break; 2415 } 2416 2417 return changed; 2418 } 2419 2420 IntegerPolyhedron IntegerRelation::getRangeSet() const { 2421 IntegerRelation copyRel = *this; 2422 2423 // Convert Domain variables to Local variables. 2424 copyRel.convertVarKind(VarKind::Domain, 0, getNumVarKind(VarKind::Domain), 2425 VarKind::Local); 2426 2427 // We do not need to do anything to Range variables since they are already in 2428 // SetDim position. 2429 2430 return IntegerPolyhedron(std::move(copyRel)); 2431 } 2432 2433 void IntegerRelation::intersectDomain(const IntegerPolyhedron &poly) { 2434 assert(getDomainSet().getSpace().isCompatible(poly.getSpace()) && 2435 "Domain set is not compatible with poly"); 2436 2437 // Treating the poly as a relation, convert it from `0 -> R` to `R -> 0`. 2438 IntegerRelation rel = poly; 2439 rel.inverse(); 2440 2441 // Append dummy range variables to make the spaces compatible. 2442 rel.appendVar(VarKind::Range, getNumRangeVars()); 2443 2444 // Intersect in place. 2445 mergeLocalVars(rel); 2446 append(rel); 2447 } 2448 2449 void IntegerRelation::intersectRange(const IntegerPolyhedron &poly) { 2450 assert(getRangeSet().getSpace().isCompatible(poly.getSpace()) && 2451 "Range set is not compatible with poly"); 2452 2453 IntegerRelation rel = poly; 2454 2455 // Append dummy domain variables to make the spaces compatible. 2456 rel.appendVar(VarKind::Domain, getNumDomainVars()); 2457 2458 mergeLocalVars(rel); 2459 append(rel); 2460 } 2461 2462 void IntegerRelation::inverse() { 2463 unsigned numRangeVars = getNumVarKind(VarKind::Range); 2464 convertVarKind(VarKind::Domain, 0, getVarKindEnd(VarKind::Domain), 2465 VarKind::Range); 2466 convertVarKind(VarKind::Range, 0, numRangeVars, VarKind::Domain); 2467 } 2468 2469 void IntegerRelation::compose(const IntegerRelation &rel) { 2470 assert(getRangeSet().getSpace().isCompatible(rel.getDomainSet().getSpace()) && 2471 "Range of `this` should be compatible with Domain of `rel`"); 2472 2473 IntegerRelation copyRel = rel; 2474 2475 // Let relation `this` be R1: A -> B, and `rel` be R2: B -> C. 2476 // We convert R1 to A -> (B X C), and R2 to B X C then intersect the range of 2477 // R1 with R2. After this, we get R1: A -> C, by projecting out B. 2478 // TODO: Using nested spaces here would help, since we could directly 2479 // intersect the range with another relation. 2480 unsigned numBVars = getNumRangeVars(); 2481 2482 // Convert R1 from A -> B to A -> (B X C). 2483 appendVar(VarKind::Range, copyRel.getNumRangeVars()); 2484 2485 // Convert R2 to B X C. 2486 copyRel.convertVarKind(VarKind::Domain, 0, numBVars, VarKind::Range, 0); 2487 2488 // Intersect R2 to range of R1. 2489 intersectRange(IntegerPolyhedron(copyRel)); 2490 2491 // Project out B in R1. 2492 convertVarKind(VarKind::Range, 0, numBVars, VarKind::Local); 2493 } 2494 2495 void IntegerRelation::applyDomain(const IntegerRelation &rel) { 2496 inverse(); 2497 compose(rel); 2498 inverse(); 2499 } 2500 2501 void IntegerRelation::applyRange(const IntegerRelation &rel) { compose(rel); } 2502 2503 void IntegerRelation::printSpace(raw_ostream &os) const { 2504 space.print(os); 2505 os << getNumConstraints() << " constraints\n"; 2506 } 2507 2508 void IntegerRelation::removeTrivialEqualities() { 2509 for (int i = getNumEqualities() - 1; i >= 0; --i) 2510 if (rangeIsZero(getEquality(i))) 2511 removeEquality(i); 2512 } 2513 2514 bool IntegerRelation::isFullDim() { 2515 if (getNumVars() == 0) 2516 return true; 2517 if (isEmpty()) 2518 return false; 2519 2520 // If there is a non-trivial equality, the space cannot be full-dimensional. 2521 removeTrivialEqualities(); 2522 if (getNumEqualities() > 0) 2523 return false; 2524 2525 // The polytope is full-dimensional iff it is not flat along any of the 2526 // inequality directions. 2527 Simplex simplex(*this); 2528 return llvm::none_of(llvm::seq<int>(getNumInequalities()), [&](int i) { 2529 return simplex.isFlatAlong(getInequality(i)); 2530 }); 2531 } 2532 2533 void IntegerRelation::mergeAndCompose(const IntegerRelation &other) { 2534 assert(getNumDomainVars() == other.getNumRangeVars() && 2535 "Domain of this and range of other do not match"); 2536 // assert(std::equal(values.begin(), values.begin() + 2537 // other.getNumDomainVars(), 2538 // otherValues.begin() + other.getNumDomainVars()) && 2539 // "Domain of this and range of other do not match"); 2540 2541 IntegerRelation result = other; 2542 2543 const unsigned thisDomain = getNumDomainVars(); 2544 const unsigned thisRange = getNumRangeVars(); 2545 const unsigned otherDomain = other.getNumDomainVars(); 2546 const unsigned otherRange = other.getNumRangeVars(); 2547 2548 // Add dimension variables temporarily to merge symbol and local vars. 2549 // Convert `this` from 2550 // [thisDomain] -> [thisRange] 2551 // to 2552 // [otherDomain thisDomain] -> [otherRange thisRange]. 2553 // and `result` from 2554 // [otherDomain] -> [otherRange] 2555 // to 2556 // [otherDomain thisDomain] -> [otherRange thisRange] 2557 insertVar(VarKind::Domain, 0, otherDomain); 2558 insertVar(VarKind::Range, 0, otherRange); 2559 result.insertVar(VarKind::Domain, otherDomain, thisDomain); 2560 result.insertVar(VarKind::Range, otherRange, thisRange); 2561 2562 // Merge symbol and local variables. 2563 mergeAndAlignSymbols(result); 2564 mergeLocalVars(result); 2565 2566 // Convert `result` from [otherDomain thisDomain] -> [otherRange thisRange] to 2567 // [otherDomain] -> [thisRange] 2568 result.removeVarRange(VarKind::Domain, otherDomain, otherDomain + thisDomain); 2569 result.convertToLocal(VarKind::Range, 0, otherRange); 2570 // Convert `this` from [otherDomain thisDomain] -> [otherRange thisRange] to 2571 // [otherDomain] -> [thisRange] 2572 convertToLocal(VarKind::Domain, otherDomain, otherDomain + thisDomain); 2573 removeVarRange(VarKind::Range, 0, otherRange); 2574 2575 // Add and match domain of `result` to domain of `this`. 2576 for (unsigned i = 0, e = result.getNumDomainVars(); i < e; ++i) 2577 if (result.getSpace().getId(VarKind::Domain, i).hasValue()) 2578 space.setId(VarKind::Domain, i, 2579 result.getSpace().getId(VarKind::Domain, i)); 2580 // Add and match range of `this` to range of `result`. 2581 for (unsigned i = 0, e = getNumRangeVars(); i < e; ++i) 2582 if (space.getId(VarKind::Range, i).hasValue()) 2583 result.space.setId(VarKind::Range, i, space.getId(VarKind::Range, i)); 2584 2585 // Append `this` to `result` and simplify constraints. 2586 result.append(*this); 2587 result.removeRedundantLocalVars(); 2588 2589 *this = result; 2590 } 2591 2592 void IntegerRelation::print(raw_ostream &os) const { 2593 assert(hasConsistentState()); 2594 printSpace(os); 2595 PrintTableMetrics ptm = {0, 0, "-"}; 2596 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) 2597 for (unsigned j = 0, f = getNumCols(); j < f; ++j) 2598 updatePrintMetrics<DynamicAPInt>(atEq(i, j), ptm); 2599 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) 2600 for (unsigned j = 0, f = getNumCols(); j < f; ++j) 2601 updatePrintMetrics<DynamicAPInt>(atIneq(i, j), ptm); 2602 // Print using PrintMetrics. 2603 unsigned MIN_SPACING = 1; 2604 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 2605 for (unsigned j = 0, f = getNumCols(); j < f; ++j) { 2606 printWithPrintMetrics<DynamicAPInt>(os, atEq(i, j), MIN_SPACING, ptm); 2607 } 2608 os << " = 0\n"; 2609 } 2610 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 2611 for (unsigned j = 0, f = getNumCols(); j < f; ++j) { 2612 printWithPrintMetrics<DynamicAPInt>(os, atIneq(i, j), MIN_SPACING, ptm); 2613 } 2614 os << " >= 0\n"; 2615 } 2616 os << '\n'; 2617 } 2618 2619 void IntegerRelation::dump() const { print(llvm::errs()); } 2620 2621 unsigned IntegerPolyhedron::insertVar(VarKind kind, unsigned pos, 2622 unsigned num) { 2623 assert((kind != VarKind::Domain || num == 0) && 2624 "Domain has to be zero in a set"); 2625 return IntegerRelation::insertVar(kind, pos, num); 2626 } 2627 IntegerPolyhedron 2628 IntegerPolyhedron::intersect(const IntegerPolyhedron &other) const { 2629 return IntegerPolyhedron(IntegerRelation::intersect(other)); 2630 } 2631 2632 PresburgerSet IntegerPolyhedron::subtract(const PresburgerSet &other) const { 2633 return PresburgerSet(IntegerRelation::subtract(other)); 2634 } 2635