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 // varaiables supporting symbolic identifiers and existential quantification. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "mlir/Analysis/Presburger/IntegerRelation.h" 16 #include "mlir/Analysis/Presburger/LinearTransform.h" 17 #include "mlir/Analysis/Presburger/PresburgerRelation.h" 18 #include "mlir/Analysis/Presburger/Simplex.h" 19 #include "mlir/Analysis/Presburger/Utils.h" 20 #include "llvm/ADT/DenseMap.h" 21 #include "llvm/ADT/DenseSet.h" 22 #include "llvm/Support/Debug.h" 23 24 #define DEBUG_TYPE "presburger" 25 26 using namespace mlir; 27 using namespace presburger; 28 29 using llvm::SmallDenseMap; 30 using llvm::SmallDenseSet; 31 32 std::unique_ptr<IntegerRelation> IntegerRelation::clone() const { 33 return std::make_unique<IntegerRelation>(*this); 34 } 35 36 std::unique_ptr<IntegerPolyhedron> IntegerPolyhedron::clone() const { 37 return std::make_unique<IntegerPolyhedron>(*this); 38 } 39 40 void IntegerRelation::append(const IntegerRelation &other) { 41 assert(isSpaceEqual(other) && "Spaces must be equal."); 42 43 inequalities.reserveRows(inequalities.getNumRows() + 44 other.getNumInequalities()); 45 equalities.reserveRows(equalities.getNumRows() + other.getNumEqualities()); 46 47 for (unsigned r = 0, e = other.getNumInequalities(); r < e; r++) { 48 addInequality(other.getInequality(r)); 49 } 50 for (unsigned r = 0, e = other.getNumEqualities(); r < e; r++) { 51 addEquality(other.getEquality(r)); 52 } 53 } 54 55 IntegerRelation IntegerRelation::intersect(IntegerRelation other) const { 56 IntegerRelation result = *this; 57 result.mergeLocalIds(other); 58 result.append(other); 59 return result; 60 } 61 62 bool IntegerRelation::isEqual(const IntegerRelation &other) const { 63 assert(isSpaceEqual(other) && "Spaces must be equal."); 64 return PresburgerRelation(*this).isEqual(PresburgerRelation(other)); 65 } 66 67 bool IntegerRelation::isSubsetOf(const IntegerRelation &other) const { 68 assert(isSpaceEqual(other) && "Spaces must be equal."); 69 return PresburgerRelation(*this).isSubsetOf(PresburgerRelation(other)); 70 } 71 72 MaybeOptimum<SmallVector<Fraction, 8>> 73 IntegerRelation::findRationalLexMin() const { 74 assert(getNumSymbolIds() == 0 && "Symbols are not supported!"); 75 MaybeOptimum<SmallVector<Fraction, 8>> maybeLexMin = 76 LexSimplex(*this).findRationalLexMin(); 77 78 if (!maybeLexMin.isBounded()) 79 return maybeLexMin; 80 81 // The Simplex returns the lexmin over all the variables including locals. But 82 // locals are not actually part of the space and should not be returned in the 83 // result. Since the locals are placed last in the list of identifiers, they 84 // will be minimized last in the lexmin. So simply truncating out the locals 85 // from the end of the answer gives the desired lexmin over the dimensions. 86 assert(maybeLexMin->size() == getNumIds() && 87 "Incorrect number of vars in lexMin!"); 88 maybeLexMin->resize(getNumDimAndSymbolIds()); 89 return maybeLexMin; 90 } 91 92 MaybeOptimum<SmallVector<int64_t, 8>> 93 IntegerRelation::findIntegerLexMin() const { 94 assert(getNumSymbolIds() == 0 && "Symbols are not supported!"); 95 MaybeOptimum<SmallVector<int64_t, 8>> maybeLexMin = 96 LexSimplex(*this).findIntegerLexMin(); 97 98 if (!maybeLexMin.isBounded()) 99 return maybeLexMin.getKind(); 100 101 // The Simplex returns the lexmin over all the variables including locals. But 102 // locals are not actually part of the space and should not be returned in the 103 // result. Since the locals are placed last in the list of identifiers, they 104 // will be minimized last in the lexmin. So simply truncating out the locals 105 // from the end of the answer gives the desired lexmin over the dimensions. 106 assert(maybeLexMin->size() == getNumIds() && 107 "Incorrect number of vars in lexMin!"); 108 maybeLexMin->resize(getNumDimAndSymbolIds()); 109 return maybeLexMin; 110 } 111 112 static bool rangeIsZero(ArrayRef<int64_t> range) { 113 return llvm::all_of(range, [](int64_t x) { return x == 0; }); 114 } 115 116 void removeConstraintsInvolvingIdRange(IntegerRelation &poly, unsigned begin, 117 unsigned count) { 118 // We loop until i > 0 and index into i - 1 to avoid sign issues. 119 // 120 // We iterate backwards so that whether we remove constraint i - 1 or not, the 121 // next constraint to be tested is always i - 2. 122 for (unsigned i = poly.getNumEqualities(); i > 0; i--) 123 if (!rangeIsZero(poly.getEquality(i - 1).slice(begin, count))) 124 poly.removeEquality(i - 1); 125 for (unsigned i = poly.getNumInequalities(); i > 0; i--) 126 if (!rangeIsZero(poly.getInequality(i - 1).slice(begin, count))) 127 poly.removeInequality(i - 1); 128 } 129 130 IntegerRelation::CountsSnapshot IntegerRelation::getCounts() const { 131 return {PresburgerSpace(*this), getNumInequalities(), getNumEqualities()}; 132 } 133 134 void IntegerRelation::truncateIdKind(IdKind kind, 135 const CountsSnapshot &counts) { 136 truncateIdKind(kind, counts.getSpace().getNumIdKind(kind)); 137 } 138 139 void IntegerRelation::truncate(const CountsSnapshot &counts) { 140 truncateIdKind(IdKind::Domain, counts); 141 truncateIdKind(IdKind::Range, counts); 142 truncateIdKind(IdKind::Symbol, counts); 143 truncateIdKind(IdKind::Local, counts); 144 removeInequalityRange(counts.getNumIneqs(), getNumInequalities()); 145 removeEqualityRange(counts.getNumEqs(), getNumEqualities()); 146 } 147 148 unsigned IntegerRelation::insertId(IdKind kind, unsigned pos, unsigned num) { 149 assert(pos <= getNumIdKind(kind)); 150 151 unsigned insertPos = PresburgerSpace::insertId(kind, pos, num); 152 inequalities.insertColumns(insertPos, num); 153 equalities.insertColumns(insertPos, num); 154 return insertPos; 155 } 156 157 unsigned IntegerRelation::appendId(IdKind kind, unsigned num) { 158 unsigned pos = getNumIdKind(kind); 159 return insertId(kind, pos, num); 160 } 161 162 void IntegerRelation::addEquality(ArrayRef<int64_t> eq) { 163 assert(eq.size() == getNumCols()); 164 unsigned row = equalities.appendExtraRow(); 165 for (unsigned i = 0, e = eq.size(); i < e; ++i) 166 equalities(row, i) = eq[i]; 167 } 168 169 void IntegerRelation::addInequality(ArrayRef<int64_t> inEq) { 170 assert(inEq.size() == getNumCols()); 171 unsigned row = inequalities.appendExtraRow(); 172 for (unsigned i = 0, e = inEq.size(); i < e; ++i) 173 inequalities(row, i) = inEq[i]; 174 } 175 176 void IntegerRelation::removeId(IdKind kind, unsigned pos) { 177 removeIdRange(kind, pos, pos + 1); 178 } 179 180 void IntegerRelation::removeId(unsigned pos) { removeIdRange(pos, pos + 1); } 181 182 void IntegerRelation::removeIdRange(IdKind kind, unsigned idStart, 183 unsigned idLimit) { 184 assert(idLimit <= getNumIdKind(kind)); 185 186 if (idStart >= idLimit) 187 return; 188 189 // Remove eliminated identifiers from the constraints. 190 unsigned offset = getIdKindOffset(kind); 191 equalities.removeColumns(offset + idStart, idLimit - idStart); 192 inequalities.removeColumns(offset + idStart, idLimit - idStart); 193 194 // Remove eliminated identifiers from the space. 195 PresburgerSpace::removeIdRange(kind, idStart, idLimit); 196 } 197 198 void IntegerRelation::removeIdRange(unsigned idStart, unsigned idLimit) { 199 assert(idLimit <= getNumIds()); 200 201 if (idStart >= idLimit) 202 return; 203 204 // Helper function to remove ids of the specified kind in the given range 205 // [start, limit), The range is absolute (i.e. it is not relative to the kind 206 // of identifier). Also updates `limit` to reflect the deleted identifiers. 207 auto removeIdKindInRange = [this](IdKind kind, unsigned &start, 208 unsigned &limit) { 209 if (start >= limit) 210 return; 211 212 unsigned offset = getIdKindOffset(kind); 213 unsigned num = getNumIdKind(kind); 214 215 // Get `start`, `limit` relative to the specified kind. 216 unsigned relativeStart = 217 start <= offset ? 0 : std::min(num, start - offset); 218 unsigned relativeLimit = 219 limit <= offset ? 0 : std::min(num, limit - offset); 220 221 // Remove ids of the specified kind in the relative range. 222 removeIdRange(kind, relativeStart, relativeLimit); 223 224 // Update `limit` to reflect deleted identifiers. 225 // `start` does not need to be updated because any identifiers that are 226 // deleted are after position `start`. 227 limit -= relativeLimit - relativeStart; 228 }; 229 230 removeIdKindInRange(IdKind::Domain, idStart, idLimit); 231 removeIdKindInRange(IdKind::Range, idStart, idLimit); 232 removeIdKindInRange(IdKind::Symbol, idStart, idLimit); 233 removeIdKindInRange(IdKind::Local, idStart, idLimit); 234 } 235 236 void IntegerRelation::removeEquality(unsigned pos) { 237 equalities.removeRow(pos); 238 } 239 240 void IntegerRelation::removeInequality(unsigned pos) { 241 inequalities.removeRow(pos); 242 } 243 244 void IntegerRelation::removeEqualityRange(unsigned start, unsigned end) { 245 if (start >= end) 246 return; 247 equalities.removeRows(start, end - start); 248 } 249 250 void IntegerRelation::removeInequalityRange(unsigned start, unsigned end) { 251 if (start >= end) 252 return; 253 inequalities.removeRows(start, end - start); 254 } 255 256 void IntegerRelation::swapId(unsigned posA, unsigned posB) { 257 assert(posA < getNumIds() && "invalid position A"); 258 assert(posB < getNumIds() && "invalid position B"); 259 260 if (posA == posB) 261 return; 262 263 inequalities.swapColumns(posA, posB); 264 equalities.swapColumns(posA, posB); 265 } 266 267 void IntegerRelation::clearConstraints() { 268 equalities.resizeVertically(0); 269 inequalities.resizeVertically(0); 270 } 271 272 /// Gather all lower and upper bounds of the identifier at `pos`, and 273 /// optionally any equalities on it. In addition, the bounds are to be 274 /// independent of identifiers in position range [`offset`, `offset` + `num`). 275 void IntegerRelation::getLowerAndUpperBoundIndices( 276 unsigned pos, SmallVectorImpl<unsigned> *lbIndices, 277 SmallVectorImpl<unsigned> *ubIndices, SmallVectorImpl<unsigned> *eqIndices, 278 unsigned offset, unsigned num) const { 279 assert(pos < getNumIds() && "invalid position"); 280 assert(offset + num < getNumCols() && "invalid range"); 281 282 // Checks for a constraint that has a non-zero coeff for the identifiers in 283 // the position range [offset, offset + num) while ignoring `pos`. 284 auto containsConstraintDependentOnRange = [&](unsigned r, bool isEq) { 285 unsigned c, f; 286 auto cst = isEq ? getEquality(r) : getInequality(r); 287 for (c = offset, f = offset + num; c < f; ++c) { 288 if (c == pos) 289 continue; 290 if (cst[c] != 0) 291 break; 292 } 293 return c < f; 294 }; 295 296 // Gather all lower bounds and upper bounds of the variable. Since the 297 // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower 298 // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1. 299 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 300 // The bounds are to be independent of [offset, offset + num) columns. 301 if (containsConstraintDependentOnRange(r, /*isEq=*/false)) 302 continue; 303 if (atIneq(r, pos) >= 1) { 304 // Lower bound. 305 lbIndices->push_back(r); 306 } else if (atIneq(r, pos) <= -1) { 307 // Upper bound. 308 ubIndices->push_back(r); 309 } 310 } 311 312 // An equality is both a lower and upper bound. Record any equalities 313 // involving the pos^th identifier. 314 if (!eqIndices) 315 return; 316 317 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 318 if (atEq(r, pos) == 0) 319 continue; 320 if (containsConstraintDependentOnRange(r, /*isEq=*/true)) 321 continue; 322 eqIndices->push_back(r); 323 } 324 } 325 326 bool IntegerRelation::hasConsistentState() const { 327 if (!inequalities.hasConsistentState()) 328 return false; 329 if (!equalities.hasConsistentState()) 330 return false; 331 return true; 332 } 333 334 void IntegerRelation::setAndEliminate(unsigned pos, ArrayRef<int64_t> values) { 335 if (values.empty()) 336 return; 337 assert(pos + values.size() <= getNumIds() && 338 "invalid position or too many values"); 339 // Setting x_j = p in sum_i a_i x_i + c is equivalent to adding p*a_j to the 340 // constant term and removing the id x_j. We do this for all the ids 341 // pos, pos + 1, ... pos + values.size() - 1. 342 unsigned constantColPos = getNumCols() - 1; 343 for (unsigned i = 0, numVals = values.size(); i < numVals; ++i) 344 inequalities.addToColumn(i + pos, constantColPos, values[i]); 345 for (unsigned i = 0, numVals = values.size(); i < numVals; ++i) 346 equalities.addToColumn(i + pos, constantColPos, values[i]); 347 removeIdRange(pos, pos + values.size()); 348 } 349 350 void IntegerRelation::clearAndCopyFrom(const IntegerRelation &other) { 351 *this = other; 352 } 353 354 // Searches for a constraint with a non-zero coefficient at `colIdx` in 355 // equality (isEq=true) or inequality (isEq=false) constraints. 356 // Returns true and sets row found in search in `rowIdx`, false otherwise. 357 bool IntegerRelation::findConstraintWithNonZeroAt(unsigned colIdx, bool isEq, 358 unsigned *rowIdx) const { 359 assert(colIdx < getNumCols() && "position out of bounds"); 360 auto at = [&](unsigned rowIdx) -> int64_t { 361 return isEq ? atEq(rowIdx, colIdx) : atIneq(rowIdx, colIdx); 362 }; 363 unsigned e = isEq ? getNumEqualities() : getNumInequalities(); 364 for (*rowIdx = 0; *rowIdx < e; ++(*rowIdx)) { 365 if (at(*rowIdx) != 0) { 366 return true; 367 } 368 } 369 return false; 370 } 371 372 void IntegerRelation::normalizeConstraintsByGCD() { 373 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) 374 equalities.normalizeRow(i); 375 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) 376 inequalities.normalizeRow(i); 377 } 378 379 bool IntegerRelation::hasInvalidConstraint() const { 380 assert(hasConsistentState()); 381 auto check = [&](bool isEq) -> bool { 382 unsigned numCols = getNumCols(); 383 unsigned numRows = isEq ? getNumEqualities() : getNumInequalities(); 384 for (unsigned i = 0, e = numRows; i < e; ++i) { 385 unsigned j; 386 for (j = 0; j < numCols - 1; ++j) { 387 int64_t v = isEq ? atEq(i, j) : atIneq(i, j); 388 // Skip rows with non-zero variable coefficients. 389 if (v != 0) 390 break; 391 } 392 if (j < numCols - 1) { 393 continue; 394 } 395 // Check validity of constant term at 'numCols - 1' w.r.t 'isEq'. 396 // Example invalid constraints include: '1 == 0' or '-1 >= 0' 397 int64_t v = isEq ? atEq(i, numCols - 1) : atIneq(i, numCols - 1); 398 if ((isEq && v != 0) || (!isEq && v < 0)) { 399 return true; 400 } 401 } 402 return false; 403 }; 404 if (check(/*isEq=*/true)) 405 return true; 406 return check(/*isEq=*/false); 407 } 408 409 /// Eliminate identifier from constraint at `rowIdx` based on coefficient at 410 /// pivotRow, pivotCol. Columns in range [elimColStart, pivotCol) will not be 411 /// updated as they have already been eliminated. 412 static void eliminateFromConstraint(IntegerRelation *constraints, 413 unsigned rowIdx, unsigned pivotRow, 414 unsigned pivotCol, unsigned elimColStart, 415 bool isEq) { 416 // Skip if equality 'rowIdx' if same as 'pivotRow'. 417 if (isEq && rowIdx == pivotRow) 418 return; 419 auto at = [&](unsigned i, unsigned j) -> int64_t { 420 return isEq ? constraints->atEq(i, j) : constraints->atIneq(i, j); 421 }; 422 int64_t leadCoeff = at(rowIdx, pivotCol); 423 // Skip if leading coefficient at 'rowIdx' is already zero. 424 if (leadCoeff == 0) 425 return; 426 int64_t pivotCoeff = constraints->atEq(pivotRow, pivotCol); 427 int64_t sign = (leadCoeff * pivotCoeff > 0) ? -1 : 1; 428 int64_t lcm = mlir::lcm(pivotCoeff, leadCoeff); 429 int64_t pivotMultiplier = sign * (lcm / std::abs(pivotCoeff)); 430 int64_t rowMultiplier = lcm / std::abs(leadCoeff); 431 432 unsigned numCols = constraints->getNumCols(); 433 for (unsigned j = 0; j < numCols; ++j) { 434 // Skip updating column 'j' if it was just eliminated. 435 if (j >= elimColStart && j < pivotCol) 436 continue; 437 int64_t v = pivotMultiplier * constraints->atEq(pivotRow, j) + 438 rowMultiplier * at(rowIdx, j); 439 isEq ? constraints->atEq(rowIdx, j) = v 440 : constraints->atIneq(rowIdx, j) = v; 441 } 442 } 443 444 /// Returns the position of the identifier that has the minimum <number of lower 445 /// bounds> times <number of upper bounds> from the specified range of 446 /// identifiers [start, end). It is often best to eliminate in the increasing 447 /// order of these counts when doing Fourier-Motzkin elimination since FM adds 448 /// that many new constraints. 449 static unsigned getBestIdToEliminate(const IntegerRelation &cst, unsigned start, 450 unsigned end) { 451 assert(start < cst.getNumIds() && end < cst.getNumIds() + 1); 452 453 auto getProductOfNumLowerUpperBounds = [&](unsigned pos) { 454 unsigned numLb = 0; 455 unsigned numUb = 0; 456 for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) { 457 if (cst.atIneq(r, pos) > 0) { 458 ++numLb; 459 } else if (cst.atIneq(r, pos) < 0) { 460 ++numUb; 461 } 462 } 463 return numLb * numUb; 464 }; 465 466 unsigned minLoc = start; 467 unsigned min = getProductOfNumLowerUpperBounds(start); 468 for (unsigned c = start + 1; c < end; c++) { 469 unsigned numLbUbProduct = getProductOfNumLowerUpperBounds(c); 470 if (numLbUbProduct < min) { 471 min = numLbUbProduct; 472 minLoc = c; 473 } 474 } 475 return minLoc; 476 } 477 478 // Checks for emptiness of the set by eliminating identifiers successively and 479 // using the GCD test (on all equality constraints) and checking for trivially 480 // invalid constraints. Returns 'true' if the constraint system is found to be 481 // empty; false otherwise. 482 bool IntegerRelation::isEmpty() const { 483 if (isEmptyByGCDTest() || hasInvalidConstraint()) 484 return true; 485 486 IntegerRelation tmpCst(*this); 487 488 // First, eliminate as many local variables as possible using equalities. 489 tmpCst.removeRedundantLocalVars(); 490 if (tmpCst.isEmptyByGCDTest() || tmpCst.hasInvalidConstraint()) 491 return true; 492 493 // Eliminate as many identifiers as possible using Gaussian elimination. 494 unsigned currentPos = 0; 495 while (currentPos < tmpCst.getNumIds()) { 496 tmpCst.gaussianEliminateIds(currentPos, tmpCst.getNumIds()); 497 ++currentPos; 498 // We check emptiness through trivial checks after eliminating each ID to 499 // detect emptiness early. Since the checks isEmptyByGCDTest() and 500 // hasInvalidConstraint() are linear time and single sweep on the constraint 501 // buffer, this appears reasonable - but can optimize in the future. 502 if (tmpCst.hasInvalidConstraint() || tmpCst.isEmptyByGCDTest()) 503 return true; 504 } 505 506 // Eliminate the remaining using FM. 507 for (unsigned i = 0, e = tmpCst.getNumIds(); i < e; i++) { 508 tmpCst.fourierMotzkinEliminate( 509 getBestIdToEliminate(tmpCst, 0, tmpCst.getNumIds())); 510 // Check for a constraint explosion. This rarely happens in practice, but 511 // this check exists as a safeguard against improperly constructed 512 // constraint systems or artificially created arbitrarily complex systems 513 // that aren't the intended use case for IntegerRelation. This is 514 // needed since FM has a worst case exponential complexity in theory. 515 if (tmpCst.getNumConstraints() >= kExplosionFactor * getNumIds()) { 516 LLVM_DEBUG(llvm::dbgs() << "FM constraint explosion detected\n"); 517 return false; 518 } 519 520 // FM wouldn't have modified the equalities in any way. So no need to again 521 // run GCD test. Check for trivial invalid constraints. 522 if (tmpCst.hasInvalidConstraint()) 523 return true; 524 } 525 return false; 526 } 527 528 // Runs the GCD test on all equality constraints. Returns 'true' if this test 529 // fails on any equality. Returns 'false' otherwise. 530 // This test can be used to disprove the existence of a solution. If it returns 531 // true, no integer solution to the equality constraints can exist. 532 // 533 // GCD test definition: 534 // 535 // The equality constraint: 536 // 537 // c_1*x_1 + c_2*x_2 + ... + c_n*x_n = c_0 538 // 539 // has an integer solution iff: 540 // 541 // GCD of c_1, c_2, ..., c_n divides c_0. 542 // 543 bool IntegerRelation::isEmptyByGCDTest() const { 544 assert(hasConsistentState()); 545 unsigned numCols = getNumCols(); 546 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 547 uint64_t gcd = std::abs(atEq(i, 0)); 548 for (unsigned j = 1; j < numCols - 1; ++j) { 549 gcd = llvm::GreatestCommonDivisor64(gcd, std::abs(atEq(i, j))); 550 } 551 int64_t v = std::abs(atEq(i, numCols - 1)); 552 if (gcd > 0 && (v % gcd != 0)) { 553 return true; 554 } 555 } 556 return false; 557 } 558 559 // Returns a matrix where each row is a vector along which the polytope is 560 // bounded. The span of the returned vectors is guaranteed to contain all 561 // such vectors. The returned vectors are NOT guaranteed to be linearly 562 // independent. This function should not be called on empty sets. 563 // 564 // It is sufficient to check the perpendiculars of the constraints, as the set 565 // of perpendiculars which are bounded must span all bounded directions. 566 Matrix IntegerRelation::getBoundedDirections() const { 567 // Note that it is necessary to add the equalities too (which the constructor 568 // does) even though we don't need to check if they are bounded; whether an 569 // inequality is bounded or not depends on what other constraints, including 570 // equalities, are present. 571 Simplex simplex(*this); 572 573 assert(!simplex.isEmpty() && "It is not meaningful to ask whether a " 574 "direction is bounded in an empty set."); 575 576 SmallVector<unsigned, 8> boundedIneqs; 577 // The constructor adds the inequalities to the simplex first, so this 578 // processes all the inequalities. 579 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 580 if (simplex.isBoundedAlongConstraint(i)) 581 boundedIneqs.push_back(i); 582 } 583 584 // The direction vector is given by the coefficients and does not include the 585 // constant term, so the matrix has one fewer column. 586 unsigned dirsNumCols = getNumCols() - 1; 587 Matrix dirs(boundedIneqs.size() + getNumEqualities(), dirsNumCols); 588 589 // Copy the bounded inequalities. 590 unsigned row = 0; 591 for (unsigned i : boundedIneqs) { 592 for (unsigned col = 0; col < dirsNumCols; ++col) 593 dirs(row, col) = atIneq(i, col); 594 ++row; 595 } 596 597 // Copy the equalities. All the equalities' perpendiculars are bounded. 598 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 599 for (unsigned col = 0; col < dirsNumCols; ++col) 600 dirs(row, col) = atEq(i, col); 601 ++row; 602 } 603 604 return dirs; 605 } 606 607 bool IntegerRelation::isIntegerEmpty() const { 608 return !findIntegerSample().hasValue(); 609 } 610 611 /// Let this set be S. If S is bounded then we directly call into the GBR 612 /// sampling algorithm. Otherwise, there are some unbounded directions, i.e., 613 /// vectors v such that S extends to infinity along v or -v. In this case we 614 /// use an algorithm described in the integer set library (isl) manual and used 615 /// by the isl_set_sample function in that library. The algorithm is: 616 /// 617 /// 1) Apply a unimodular transform T to S to obtain S*T, such that all 618 /// dimensions in which S*T is bounded lie in the linear span of a prefix of the 619 /// dimensions. 620 /// 621 /// 2) Construct a set B by removing all constraints that involve 622 /// the unbounded dimensions and then deleting the unbounded dimensions. Note 623 /// that B is a Bounded set. 624 /// 625 /// 3) Try to obtain a sample from B using the GBR sampling 626 /// algorithm. If no sample is found, return that S is empty. 627 /// 628 /// 4) Otherwise, substitute the obtained sample into S*T to obtain a set 629 /// C. C is a full-dimensional Cone and always contains a sample. 630 /// 631 /// 5) Obtain an integer sample from C. 632 /// 633 /// 6) Return T*v, where v is the concatenation of the samples from B and C. 634 /// 635 /// The following is a sketch of a proof that 636 /// a) If the algorithm returns empty, then S is empty. 637 /// b) If the algorithm returns a sample, it is a valid sample in S. 638 /// 639 /// The algorithm returns empty only if B is empty, in which case S*T is 640 /// certainly empty since B was obtained by removing constraints and then 641 /// deleting unconstrained dimensions from S*T. Since T is unimodular, a vector 642 /// v is in S*T iff T*v is in S. So in this case, since 643 /// S*T is empty, S is empty too. 644 /// 645 /// Otherwise, the algorithm substitutes the sample from B into S*T. All the 646 /// constraints of S*T that did not involve unbounded dimensions are satisfied 647 /// by this substitution. All dimensions in the linear span of the dimensions 648 /// outside the prefix are unbounded in S*T (step 1). Substituting values for 649 /// the bounded dimensions cannot make these dimensions bounded, and these are 650 /// the only remaining dimensions in C, so C is unbounded along every vector (in 651 /// the positive or negative direction, or both). C is hence a full-dimensional 652 /// cone and therefore always contains an integer point. 653 /// 654 /// Concatenating the samples from B and C gives a sample v in S*T, so the 655 /// returned sample T*v is a sample in S. 656 Optional<SmallVector<int64_t, 8>> IntegerRelation::findIntegerSample() const { 657 // First, try the GCD test heuristic. 658 if (isEmptyByGCDTest()) 659 return {}; 660 661 Simplex simplex(*this); 662 if (simplex.isEmpty()) 663 return {}; 664 665 // For a bounded set, we directly call into the GBR sampling algorithm. 666 if (!simplex.isUnbounded()) 667 return simplex.findIntegerSample(); 668 669 // The set is unbounded. We cannot directly use the GBR algorithm. 670 // 671 // m is a matrix containing, in each row, a vector in which S is 672 // bounded, such that the linear span of all these dimensions contains all 673 // bounded dimensions in S. 674 Matrix m = getBoundedDirections(); 675 // In column echelon form, each row of m occupies only the first rank(m) 676 // columns and has zeros on the other columns. The transform T that brings S 677 // to column echelon form is unimodular as well, so this is a suitable 678 // transform to use in step 1 of the algorithm. 679 std::pair<unsigned, LinearTransform> result = 680 LinearTransform::makeTransformToColumnEchelon(std::move(m)); 681 const LinearTransform &transform = result.second; 682 // 1) Apply T to S to obtain S*T. 683 IntegerRelation transformedSet = transform.applyTo(*this); 684 685 // 2) Remove the unbounded dimensions and constraints involving them to 686 // obtain a bounded set. 687 IntegerRelation boundedSet(transformedSet); 688 unsigned numBoundedDims = result.first; 689 unsigned numUnboundedDims = getNumIds() - numBoundedDims; 690 removeConstraintsInvolvingIdRange(boundedSet, numBoundedDims, 691 numUnboundedDims); 692 boundedSet.removeIdRange(numBoundedDims, boundedSet.getNumIds()); 693 694 // 3) Try to obtain a sample from the bounded set. 695 Optional<SmallVector<int64_t, 8>> boundedSample = 696 Simplex(boundedSet).findIntegerSample(); 697 if (!boundedSample) 698 return {}; 699 assert(boundedSet.containsPoint(*boundedSample) && 700 "Simplex returned an invalid sample!"); 701 702 // 4) Substitute the values of the bounded dimensions into S*T to obtain a 703 // full-dimensional cone, which necessarily contains an integer sample. 704 transformedSet.setAndEliminate(0, *boundedSample); 705 IntegerRelation &cone = transformedSet; 706 707 // 5) Obtain an integer sample from the cone. 708 // 709 // We shrink the cone such that for any rational point in the shrunken cone, 710 // rounding up each of the point's coordinates produces a point that still 711 // lies in the original cone. 712 // 713 // Rounding up a point x adds a number e_i in [0, 1) to each coordinate x_i. 714 // For each inequality sum_i a_i x_i + c >= 0 in the original cone, the 715 // shrunken cone will have the inequality tightened by some amount s, such 716 // that if x satisfies the shrunken cone's tightened inequality, then x + e 717 // satisfies the original inequality, i.e., 718 // 719 // sum_i a_i x_i + c + s >= 0 implies sum_i a_i (x_i + e_i) + c >= 0 720 // 721 // for any e_i values in [0, 1). In fact, we will handle the slightly more 722 // general case where e_i can be in [0, 1]. For example, consider the 723 // inequality 2x_1 - 3x_2 - 7x_3 - 6 >= 0, and let x = (3, 0, 0). How low 724 // could the LHS go if we added a number in [0, 1] to each coordinate? The LHS 725 // is minimized when we add 1 to the x_i with negative coefficient a_i and 726 // keep the other x_i the same. In the example, we would get x = (3, 1, 1), 727 // changing the value of the LHS by -3 + -7 = -10. 728 // 729 // In general, the value of the LHS can change by at most the sum of the 730 // negative a_i, so we accomodate this by shifting the inequality by this 731 // amount for the shrunken cone. 732 for (unsigned i = 0, e = cone.getNumInequalities(); i < e; ++i) { 733 for (unsigned j = 0; j < cone.getNumIds(); ++j) { 734 int64_t coeff = cone.atIneq(i, j); 735 if (coeff < 0) 736 cone.atIneq(i, cone.getNumIds()) += coeff; 737 } 738 } 739 740 // Obtain an integer sample in the cone by rounding up a rational point from 741 // the shrunken cone. Shrinking the cone amounts to shifting its apex 742 // "inwards" without changing its "shape"; the shrunken cone is still a 743 // full-dimensional cone and is hence non-empty. 744 Simplex shrunkenConeSimplex(cone); 745 assert(!shrunkenConeSimplex.isEmpty() && "Shrunken cone cannot be empty!"); 746 747 // The sample will always exist since the shrunken cone is non-empty. 748 SmallVector<Fraction, 8> shrunkenConeSample = 749 *shrunkenConeSimplex.getRationalSample(); 750 751 SmallVector<int64_t, 8> coneSample(llvm::map_range(shrunkenConeSample, ceil)); 752 753 // 6) Return transform * concat(boundedSample, coneSample). 754 SmallVector<int64_t, 8> &sample = boundedSample.getValue(); 755 sample.append(coneSample.begin(), coneSample.end()); 756 return transform.postMultiplyWithColumn(sample); 757 } 758 759 /// Helper to evaluate an affine expression at a point. 760 /// The expression is a list of coefficients for the dimensions followed by the 761 /// constant term. 762 static int64_t valueAt(ArrayRef<int64_t> expr, ArrayRef<int64_t> point) { 763 assert(expr.size() == 1 + point.size() && 764 "Dimensionalities of point and expression don't match!"); 765 int64_t value = expr.back(); 766 for (unsigned i = 0; i < point.size(); ++i) 767 value += expr[i] * point[i]; 768 return value; 769 } 770 771 /// A point satisfies an equality iff the value of the equality at the 772 /// expression is zero, and it satisfies an inequality iff the value of the 773 /// inequality at that point is non-negative. 774 bool IntegerRelation::containsPoint(ArrayRef<int64_t> point) const { 775 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 776 if (valueAt(getEquality(i), point) != 0) 777 return false; 778 } 779 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 780 if (valueAt(getInequality(i), point) < 0) 781 return false; 782 } 783 return true; 784 } 785 786 /// Just substitute the values given and check if an integer sample exists for 787 /// the local ids. 788 /// 789 /// TODO: this could be made more efficient by handling divisions separately. 790 /// Instead of finding an integer sample over all the locals, we can first 791 /// compute the values of the locals that have division representations and 792 /// only use the integer emptiness check for the locals that don't have this. 793 /// Handling this correctly requires ordering the divs, though. 794 Optional<SmallVector<int64_t, 8>> 795 IntegerRelation::containsPointNoLocal(ArrayRef<int64_t> point) const { 796 assert(point.size() == getNumIds() - getNumLocalIds() && 797 "Point should contain all ids except locals!"); 798 assert(getIdKindOffset(IdKind::Local) == getNumIds() - getNumLocalIds() && 799 "This function depends on locals being stored last!"); 800 IntegerRelation copy = *this; 801 copy.setAndEliminate(0, point); 802 return copy.findIntegerSample(); 803 } 804 805 void IntegerRelation::getLocalReprs(std::vector<MaybeLocalRepr> &repr) const { 806 std::vector<SmallVector<int64_t, 8>> dividends(getNumLocalIds()); 807 SmallVector<unsigned, 4> denominators(getNumLocalIds()); 808 getLocalReprs(dividends, denominators, repr); 809 } 810 811 void IntegerRelation::getLocalReprs( 812 std::vector<SmallVector<int64_t, 8>> ÷nds, 813 SmallVector<unsigned, 4> &denominators) const { 814 std::vector<MaybeLocalRepr> repr(getNumLocalIds()); 815 getLocalReprs(dividends, denominators, repr); 816 } 817 818 void IntegerRelation::getLocalReprs( 819 std::vector<SmallVector<int64_t, 8>> ÷nds, 820 SmallVector<unsigned, 4> &denominators, 821 std::vector<MaybeLocalRepr> &repr) const { 822 823 repr.resize(getNumLocalIds()); 824 dividends.resize(getNumLocalIds()); 825 denominators.resize(getNumLocalIds()); 826 827 SmallVector<bool, 8> foundRepr(getNumIds(), false); 828 for (unsigned i = 0, e = getNumDimAndSymbolIds(); i < e; ++i) 829 foundRepr[i] = true; 830 831 unsigned divOffset = getNumDimAndSymbolIds(); 832 bool changed; 833 do { 834 // Each time changed is true, at end of this iteration, one or more local 835 // vars have been detected as floor divs. 836 changed = false; 837 for (unsigned i = 0, e = getNumLocalIds(); i < e; ++i) { 838 if (!foundRepr[i + divOffset]) { 839 MaybeLocalRepr res = computeSingleVarRepr( 840 *this, foundRepr, divOffset + i, dividends[i], denominators[i]); 841 if (!res) 842 continue; 843 foundRepr[i + divOffset] = true; 844 repr[i] = res; 845 changed = true; 846 } 847 } 848 } while (changed); 849 850 // Set 0 denominator for identifiers for which no division representation 851 // could be found. 852 for (unsigned i = 0, e = repr.size(); i < e; ++i) 853 if (!repr[i]) 854 denominators[i] = 0; 855 } 856 857 /// Tightens inequalities given that we are dealing with integer spaces. This is 858 /// analogous to the GCD test but applied to inequalities. The constant term can 859 /// be reduced to the preceding multiple of the GCD of the coefficients, i.e., 860 /// 64*i - 100 >= 0 => 64*i - 128 >= 0 (since 'i' is an integer). This is a 861 /// fast method - linear in the number of coefficients. 862 // Example on how this affects practical cases: consider the scenario: 863 // 64*i >= 100, j = 64*i; without a tightening, elimination of i would yield 864 // j >= 100 instead of the tighter (exact) j >= 128. 865 void IntegerRelation::gcdTightenInequalities() { 866 unsigned numCols = getNumCols(); 867 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 868 // Normalize the constraint and tighten the constant term by the GCD. 869 uint64_t gcd = inequalities.normalizeRow(i, getNumCols() - 1); 870 if (gcd > 1) 871 atIneq(i, numCols - 1) = mlir::floorDiv(atIneq(i, numCols - 1), gcd); 872 } 873 } 874 875 // Eliminates all identifier variables in column range [posStart, posLimit). 876 // Returns the number of variables eliminated. 877 unsigned IntegerRelation::gaussianEliminateIds(unsigned posStart, 878 unsigned posLimit) { 879 // Return if identifier positions to eliminate are out of range. 880 assert(posLimit <= getNumIds()); 881 assert(hasConsistentState()); 882 883 if (posStart >= posLimit) 884 return 0; 885 886 gcdTightenInequalities(); 887 888 unsigned pivotCol = 0; 889 for (pivotCol = posStart; pivotCol < posLimit; ++pivotCol) { 890 // Find a row which has a non-zero coefficient in column 'j'. 891 unsigned pivotRow; 892 if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/true, &pivotRow)) { 893 // No pivot row in equalities with non-zero at 'pivotCol'. 894 if (!findConstraintWithNonZeroAt(pivotCol, /*isEq=*/false, &pivotRow)) { 895 // If inequalities are also non-zero in 'pivotCol', it can be 896 // eliminated. 897 continue; 898 } 899 break; 900 } 901 902 // Eliminate identifier at 'pivotCol' from each equality row. 903 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 904 eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart, 905 /*isEq=*/true); 906 equalities.normalizeRow(i); 907 } 908 909 // Eliminate identifier at 'pivotCol' from each inequality row. 910 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 911 eliminateFromConstraint(this, i, pivotRow, pivotCol, posStart, 912 /*isEq=*/false); 913 inequalities.normalizeRow(i); 914 } 915 removeEquality(pivotRow); 916 gcdTightenInequalities(); 917 } 918 // Update position limit based on number eliminated. 919 posLimit = pivotCol; 920 // Remove eliminated columns from all constraints. 921 removeIdRange(posStart, posLimit); 922 return posLimit - posStart; 923 } 924 925 // A more complex check to eliminate redundant inequalities. Uses FourierMotzkin 926 // to check if a constraint is redundant. 927 void IntegerRelation::removeRedundantInequalities() { 928 SmallVector<bool, 32> redun(getNumInequalities(), false); 929 // To check if an inequality is redundant, we replace the inequality by its 930 // complement (for eg., i - 1 >= 0 by i <= 0), and check if the resulting 931 // system is empty. If it is, the inequality is redundant. 932 IntegerRelation tmpCst(*this); 933 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 934 // Change the inequality to its complement. 935 tmpCst.inequalities.negateRow(r); 936 tmpCst.atIneq(r, tmpCst.getNumCols() - 1)--; 937 if (tmpCst.isEmpty()) { 938 redun[r] = true; 939 // Zero fill the redundant inequality. 940 inequalities.fillRow(r, /*value=*/0); 941 tmpCst.inequalities.fillRow(r, /*value=*/0); 942 } else { 943 // Reverse the change (to avoid recreating tmpCst each time). 944 tmpCst.atIneq(r, tmpCst.getNumCols() - 1)++; 945 tmpCst.inequalities.negateRow(r); 946 } 947 } 948 949 unsigned pos = 0; 950 for (unsigned r = 0, e = getNumInequalities(); r < e; ++r) { 951 if (!redun[r]) 952 inequalities.copyRow(r, pos++); 953 } 954 inequalities.resizeVertically(pos); 955 } 956 957 // A more complex check to eliminate redundant inequalities and equalities. Uses 958 // Simplex to check if a constraint is redundant. 959 void IntegerRelation::removeRedundantConstraints() { 960 // First, we run gcdTightenInequalities. This allows us to catch some 961 // constraints which are not redundant when considering rational solutions 962 // but are redundant in terms of integer solutions. 963 gcdTightenInequalities(); 964 Simplex simplex(*this); 965 simplex.detectRedundant(); 966 967 unsigned pos = 0; 968 unsigned numIneqs = getNumInequalities(); 969 // Scan to get rid of all inequalities marked redundant, in-place. In Simplex, 970 // the first constraints added are the inequalities. 971 for (unsigned r = 0; r < numIneqs; r++) { 972 if (!simplex.isMarkedRedundant(r)) 973 inequalities.copyRow(r, pos++); 974 } 975 inequalities.resizeVertically(pos); 976 977 // Scan to get rid of all equalities marked redundant, in-place. In Simplex, 978 // after the inequalities, a pair of constraints for each equality is added. 979 // An equality is redundant if both the inequalities in its pair are 980 // redundant. 981 pos = 0; 982 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 983 if (!(simplex.isMarkedRedundant(numIneqs + 2 * r) && 984 simplex.isMarkedRedundant(numIneqs + 2 * r + 1))) 985 equalities.copyRow(r, pos++); 986 } 987 equalities.resizeVertically(pos); 988 } 989 990 Optional<uint64_t> IntegerRelation::computeVolume() const { 991 assert(getNumSymbolIds() == 0 && "Symbols are not yet supported!"); 992 993 Simplex simplex(*this); 994 // If the polytope is rationally empty, there are certainly no integer 995 // points. 996 if (simplex.isEmpty()) 997 return 0; 998 999 // Just find the maximum and minimum integer value of each non-local id 1000 // separately, thus finding the number of integer values each such id can 1001 // take. Multiplying these together gives a valid overapproximation of the 1002 // number of integer points in the relation. The result this gives is 1003 // equivalent to projecting (rationally) the relation onto its non-local ids 1004 // and returning the number of integer points in a minimal axis-parallel 1005 // hyperrectangular overapproximation of that. 1006 // 1007 // We also handle the special case where one dimension is unbounded and 1008 // another dimension can take no integer values. In this case, the volume is 1009 // zero. 1010 // 1011 // If there is no such empty dimension, if any dimension is unbounded we 1012 // just return the result as unbounded. 1013 uint64_t count = 1; 1014 SmallVector<int64_t, 8> dim(getNumIds() + 1); 1015 bool hasUnboundedId = false; 1016 for (unsigned i = 0, e = getNumDimAndSymbolIds(); i < e; ++i) { 1017 dim[i] = 1; 1018 MaybeOptimum<int64_t> min, max; 1019 std::tie(min, max) = simplex.computeIntegerBounds(dim); 1020 dim[i] = 0; 1021 1022 assert((!min.isEmpty() && !max.isEmpty()) && 1023 "Polytope should be rationally non-empty!"); 1024 1025 // One of the dimensions is unbounded. Note this fact. We will return 1026 // unbounded if none of the other dimensions makes the volume zero. 1027 if (min.isUnbounded() || max.isUnbounded()) { 1028 hasUnboundedId = true; 1029 continue; 1030 } 1031 1032 // In this case there are no valid integer points and the volume is 1033 // definitely zero. 1034 if (min.getBoundedOptimum() > max.getBoundedOptimum()) 1035 return 0; 1036 1037 count *= (*max - *min + 1); 1038 } 1039 1040 if (count == 0) 1041 return 0; 1042 if (hasUnboundedId) 1043 return {}; 1044 return count; 1045 } 1046 1047 void IntegerRelation::eliminateRedundantLocalId(unsigned posA, unsigned posB) { 1048 assert(posA < getNumLocalIds() && "Invalid local id position"); 1049 assert(posB < getNumLocalIds() && "Invalid local id position"); 1050 1051 unsigned localOffset = getIdKindOffset(IdKind::Local); 1052 posA += localOffset; 1053 posB += localOffset; 1054 inequalities.addToColumn(posB, posA, 1); 1055 equalities.addToColumn(posB, posA, 1); 1056 removeId(posB); 1057 } 1058 1059 /// Adds additional local ids to the sets such that they both have the union 1060 /// of the local ids in each set, without changing the set of points that 1061 /// lie in `this` and `other`. 1062 /// 1063 /// To detect local ids that always take the same in both sets, each local id is 1064 /// represented as a floordiv with constant denominator in terms of other ids. 1065 /// After extracting these divisions, local ids with the same division 1066 /// representation are considered duplicate and are merged. It is possible that 1067 /// division representation for some local id cannot be obtained, and thus these 1068 /// local ids are not considered for detecting duplicates. 1069 void IntegerRelation::mergeLocalIds(IntegerRelation &other) { 1070 assert(isSpaceCompatible(other) && "Spaces should be compatible."); 1071 1072 IntegerRelation &relA = *this; 1073 IntegerRelation &relB = other; 1074 1075 // Merge local ids of relA and relB without using division information, 1076 // i.e. append local ids of `relB` to `relA` and insert local ids of `relA` 1077 // to `relB` at start of its local ids. 1078 unsigned initLocals = relA.getNumLocalIds(); 1079 insertId(IdKind::Local, relA.getNumLocalIds(), relB.getNumLocalIds()); 1080 relB.insertId(IdKind::Local, 0, initLocals); 1081 1082 // Get division representations from each rel. 1083 std::vector<SmallVector<int64_t, 8>> divsA, divsB; 1084 SmallVector<unsigned, 4> denomsA, denomsB; 1085 relA.getLocalReprs(divsA, denomsA); 1086 relB.getLocalReprs(divsB, denomsB); 1087 1088 // Copy division information for relB into `divsA` and `denomsA`, so that 1089 // these have the combined division information of both rels. Since newly 1090 // added local variables in relA and relB have no constraints, they will not 1091 // have any division representation. 1092 std::copy(divsB.begin() + initLocals, divsB.end(), 1093 divsA.begin() + initLocals); 1094 std::copy(denomsB.begin() + initLocals, denomsB.end(), 1095 denomsA.begin() + initLocals); 1096 1097 // Merge function that merges the local variables in both sets by treating 1098 // them as the same identifier. 1099 auto merge = [&relA, &relB](unsigned i, unsigned j) -> bool { 1100 relA.eliminateRedundantLocalId(i, j); 1101 relB.eliminateRedundantLocalId(i, j); 1102 return true; 1103 }; 1104 1105 // Merge all divisions by removing duplicate divisions. 1106 unsigned localOffset = getIdKindOffset(IdKind::Local); 1107 presburger::removeDuplicateDivs(divsA, denomsA, localOffset, merge); 1108 } 1109 1110 void IntegerRelation::removeDuplicateDivs() { 1111 std::vector<SmallVector<int64_t, 8>> divs; 1112 SmallVector<unsigned, 4> denoms; 1113 1114 getLocalReprs(divs, denoms); 1115 auto merge = [this](unsigned i, unsigned j) -> bool { 1116 eliminateRedundantLocalId(i, j); 1117 return true; 1118 }; 1119 presburger::removeDuplicateDivs(divs, denoms, getIdKindOffset(IdKind::Local), 1120 merge); 1121 } 1122 1123 /// Removes local variables using equalities. Each equality is checked if it 1124 /// can be reduced to the form: `e = affine-expr`, where `e` is a local 1125 /// variable and `affine-expr` is an affine expression not containing `e`. 1126 /// If an equality satisfies this form, the local variable is replaced in 1127 /// each constraint and then removed. The equality used to replace this local 1128 /// variable is also removed. 1129 void IntegerRelation::removeRedundantLocalVars() { 1130 // Normalize the equality constraints to reduce coefficients of local 1131 // variables to 1 wherever possible. 1132 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) 1133 equalities.normalizeRow(i); 1134 1135 while (true) { 1136 unsigned i, e, j, f; 1137 for (i = 0, e = getNumEqualities(); i < e; ++i) { 1138 // Find a local variable to eliminate using ith equality. 1139 for (j = getNumDimAndSymbolIds(), f = getNumIds(); j < f; ++j) 1140 if (std::abs(atEq(i, j)) == 1) 1141 break; 1142 1143 // Local variable can be eliminated using ith equality. 1144 if (j < f) 1145 break; 1146 } 1147 1148 // No equality can be used to eliminate a local variable. 1149 if (i == e) 1150 break; 1151 1152 // Use the ith equality to simplify other equalities. If any changes 1153 // are made to an equality constraint, it is normalized by GCD. 1154 for (unsigned k = 0, t = getNumEqualities(); k < t; ++k) { 1155 if (atEq(k, j) != 0) { 1156 eliminateFromConstraint(this, k, i, j, j, /*isEq=*/true); 1157 equalities.normalizeRow(k); 1158 } 1159 } 1160 1161 // Use the ith equality to simplify inequalities. 1162 for (unsigned k = 0, t = getNumInequalities(); k < t; ++k) 1163 eliminateFromConstraint(this, k, i, j, j, /*isEq=*/false); 1164 1165 // Remove the ith equality and the found local variable. 1166 removeId(j); 1167 removeEquality(i); 1168 } 1169 } 1170 1171 void IntegerRelation::convertIdKind(IdKind srcKind, unsigned idStart, 1172 unsigned idLimit, IdKind dstKind) { 1173 assert(idLimit <= getNumIdKind(srcKind) && "Invalid id range"); 1174 1175 if (idStart >= idLimit) 1176 return; 1177 1178 // Append new local variables corresponding to the dimensions to be converted. 1179 unsigned newIdsBegin = getIdKindEnd(dstKind); 1180 unsigned convertCount = idLimit - idStart; 1181 appendId(dstKind, convertCount); 1182 1183 // Swap the new local variables with dimensions. 1184 // 1185 // Essentially, this moves the information corresponding to the specified ids 1186 // of kind `srcKind` to the `convertCount` newly created ids of kind 1187 // `dstKind`. In particular, this moves the columns in the constraint 1188 // matrices, and zeros out the initially occupied columns (because the newly 1189 // created ids we're swapping with were zero-initialized). 1190 unsigned offset = getIdKindOffset(srcKind); 1191 for (unsigned i = 0; i < convertCount; ++i) 1192 swapId(offset + idStart + i, newIdsBegin + i); 1193 1194 // Complete the move by deleting the initially occupied columns. 1195 removeIdRange(srcKind, idStart, idLimit); 1196 } 1197 1198 void IntegerRelation::addBound(BoundType type, unsigned pos, int64_t value) { 1199 assert(pos < getNumCols()); 1200 if (type == BoundType::EQ) { 1201 unsigned row = equalities.appendExtraRow(); 1202 equalities(row, pos) = 1; 1203 equalities(row, getNumCols() - 1) = -value; 1204 } else { 1205 unsigned row = inequalities.appendExtraRow(); 1206 inequalities(row, pos) = type == BoundType::LB ? 1 : -1; 1207 inequalities(row, getNumCols() - 1) = 1208 type == BoundType::LB ? -value : value; 1209 } 1210 } 1211 1212 void IntegerRelation::addBound(BoundType type, ArrayRef<int64_t> expr, 1213 int64_t value) { 1214 assert(type != BoundType::EQ && "EQ not implemented"); 1215 assert(expr.size() == getNumCols()); 1216 unsigned row = inequalities.appendExtraRow(); 1217 for (unsigned i = 0, e = expr.size(); i < e; ++i) 1218 inequalities(row, i) = type == BoundType::LB ? expr[i] : -expr[i]; 1219 inequalities(inequalities.getNumRows() - 1, getNumCols() - 1) += 1220 type == BoundType::LB ? -value : value; 1221 } 1222 1223 /// Adds a new local identifier as the floordiv of an affine function of other 1224 /// identifiers, the coefficients of which are provided in 'dividend' and with 1225 /// respect to a positive constant 'divisor'. Two constraints are added to the 1226 /// system to capture equivalence with the floordiv. 1227 /// q = expr floordiv c <=> c*q <= expr <= c*q + c - 1. 1228 void IntegerRelation::addLocalFloorDiv(ArrayRef<int64_t> dividend, 1229 int64_t divisor) { 1230 assert(dividend.size() == getNumCols() && "incorrect dividend size"); 1231 assert(divisor > 0 && "positive divisor expected"); 1232 1233 appendId(IdKind::Local); 1234 1235 // Add two constraints for this new identifier 'q'. 1236 SmallVector<int64_t, 8> bound(dividend.size() + 1); 1237 1238 // dividend - q * divisor >= 0 1239 std::copy(dividend.begin(), dividend.begin() + dividend.size() - 1, 1240 bound.begin()); 1241 bound.back() = dividend.back(); 1242 bound[getNumIds() - 1] = -divisor; 1243 addInequality(bound); 1244 1245 // -dividend +qdivisor * q + divisor - 1 >= 0 1246 std::transform(bound.begin(), bound.end(), bound.begin(), 1247 std::negate<int64_t>()); 1248 bound[bound.size() - 1] += divisor - 1; 1249 addInequality(bound); 1250 } 1251 1252 /// Finds an equality that equates the specified identifier to a constant. 1253 /// Returns the position of the equality row. If 'symbolic' is set to true, 1254 /// symbols are also treated like a constant, i.e., an affine function of the 1255 /// symbols is also treated like a constant. Returns -1 if such an equality 1256 /// could not be found. 1257 static int findEqualityToConstant(const IntegerRelation &cst, unsigned pos, 1258 bool symbolic = false) { 1259 assert(pos < cst.getNumIds() && "invalid position"); 1260 for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) { 1261 int64_t v = cst.atEq(r, pos); 1262 if (v * v != 1) 1263 continue; 1264 unsigned c; 1265 unsigned f = symbolic ? cst.getNumDimIds() : cst.getNumIds(); 1266 // This checks for zeros in all positions other than 'pos' in [0, f) 1267 for (c = 0; c < f; c++) { 1268 if (c == pos) 1269 continue; 1270 if (cst.atEq(r, c) != 0) { 1271 // Dependent on another identifier. 1272 break; 1273 } 1274 } 1275 if (c == f) 1276 // Equality is free of other identifiers. 1277 return r; 1278 } 1279 return -1; 1280 } 1281 1282 LogicalResult IntegerRelation::constantFoldId(unsigned pos) { 1283 assert(pos < getNumIds() && "invalid position"); 1284 int rowIdx; 1285 if ((rowIdx = findEqualityToConstant(*this, pos)) == -1) 1286 return failure(); 1287 1288 // atEq(rowIdx, pos) is either -1 or 1. 1289 assert(atEq(rowIdx, pos) * atEq(rowIdx, pos) == 1); 1290 int64_t constVal = -atEq(rowIdx, getNumCols() - 1) / atEq(rowIdx, pos); 1291 setAndEliminate(pos, constVal); 1292 return success(); 1293 } 1294 1295 void IntegerRelation::constantFoldIdRange(unsigned pos, unsigned num) { 1296 for (unsigned s = pos, t = pos, e = pos + num; s < e; s++) { 1297 if (failed(constantFoldId(t))) 1298 t++; 1299 } 1300 } 1301 1302 /// Returns a non-negative constant bound on the extent (upper bound - lower 1303 /// bound) of the specified identifier if it is found to be a constant; returns 1304 /// None if it's not a constant. This methods treats symbolic identifiers 1305 /// specially, i.e., it looks for constant differences between affine 1306 /// expressions involving only the symbolic identifiers. See comments at 1307 /// function definition for example. 'lb', if provided, is set to the lower 1308 /// bound associated with the constant difference. Note that 'lb' is purely 1309 /// symbolic and thus will contain the coefficients of the symbolic identifiers 1310 /// and the constant coefficient. 1311 // Egs: 0 <= i <= 15, return 16. 1312 // s0 + 2 <= i <= s0 + 17, returns 16. (s0 has to be a symbol) 1313 // s0 + s1 + 16 <= d0 <= s0 + s1 + 31, returns 16. 1314 // s0 - 7 <= 8*j <= s0 returns 1 with lb = s0, lbDivisor = 8 (since lb = 1315 // ceil(s0 - 7 / 8) = floor(s0 / 8)). 1316 Optional<int64_t> IntegerRelation::getConstantBoundOnDimSize( 1317 unsigned pos, SmallVectorImpl<int64_t> *lb, int64_t *boundFloorDivisor, 1318 SmallVectorImpl<int64_t> *ub, unsigned *minLbPos, 1319 unsigned *minUbPos) const { 1320 assert(pos < getNumDimIds() && "Invalid identifier position"); 1321 1322 // Find an equality for 'pos'^th identifier that equates it to some function 1323 // of the symbolic identifiers (+ constant). 1324 int eqPos = findEqualityToConstant(*this, pos, /*symbolic=*/true); 1325 if (eqPos != -1) { 1326 auto eq = getEquality(eqPos); 1327 // If the equality involves a local var, punt for now. 1328 // TODO: this can be handled in the future by using the explicit 1329 // representation of the local vars. 1330 if (!std::all_of(eq.begin() + getNumDimAndSymbolIds(), eq.end() - 1, 1331 [](int64_t coeff) { return coeff == 0; })) 1332 return None; 1333 1334 // This identifier can only take a single value. 1335 if (lb) { 1336 // Set lb to that symbolic value. 1337 lb->resize(getNumSymbolIds() + 1); 1338 if (ub) 1339 ub->resize(getNumSymbolIds() + 1); 1340 for (unsigned c = 0, f = getNumSymbolIds() + 1; c < f; c++) { 1341 int64_t v = atEq(eqPos, pos); 1342 // atEq(eqRow, pos) is either -1 or 1. 1343 assert(v * v == 1); 1344 (*lb)[c] = v < 0 ? atEq(eqPos, getNumDimIds() + c) / -v 1345 : -atEq(eqPos, getNumDimIds() + c) / v; 1346 // Since this is an equality, ub = lb. 1347 if (ub) 1348 (*ub)[c] = (*lb)[c]; 1349 } 1350 assert(boundFloorDivisor && 1351 "both lb and divisor or none should be provided"); 1352 *boundFloorDivisor = 1; 1353 } 1354 if (minLbPos) 1355 *minLbPos = eqPos; 1356 if (minUbPos) 1357 *minUbPos = eqPos; 1358 return 1; 1359 } 1360 1361 // Check if the identifier appears at all in any of the inequalities. 1362 unsigned r, e; 1363 for (r = 0, e = getNumInequalities(); r < e; r++) { 1364 if (atIneq(r, pos) != 0) 1365 break; 1366 } 1367 if (r == e) 1368 // If it doesn't, there isn't a bound on it. 1369 return None; 1370 1371 // Positions of constraints that are lower/upper bounds on the variable. 1372 SmallVector<unsigned, 4> lbIndices, ubIndices; 1373 1374 // Gather all symbolic lower bounds and upper bounds of the variable, i.e., 1375 // the bounds can only involve symbolic (and local) identifiers. Since the 1376 // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower 1377 // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1. 1378 getLowerAndUpperBoundIndices(pos, &lbIndices, &ubIndices, 1379 /*eqIndices=*/nullptr, /*offset=*/0, 1380 /*num=*/getNumDimIds()); 1381 1382 Optional<int64_t> minDiff = None; 1383 unsigned minLbPosition = 0, minUbPosition = 0; 1384 for (auto ubPos : ubIndices) { 1385 for (auto lbPos : lbIndices) { 1386 // Look for a lower bound and an upper bound that only differ by a 1387 // constant, i.e., pairs of the form 0 <= c_pos - f(c_i's) <= diffConst. 1388 // For example, if ii is the pos^th variable, we are looking for 1389 // constraints like ii >= i, ii <= ii + 50, 50 being the difference. The 1390 // minimum among all such constant differences is kept since that's the 1391 // constant bounding the extent of the pos^th variable. 1392 unsigned j, e; 1393 for (j = 0, e = getNumCols() - 1; j < e; j++) 1394 if (atIneq(ubPos, j) != -atIneq(lbPos, j)) { 1395 break; 1396 } 1397 if (j < getNumCols() - 1) 1398 continue; 1399 int64_t diff = ceilDiv(atIneq(ubPos, getNumCols() - 1) + 1400 atIneq(lbPos, getNumCols() - 1) + 1, 1401 atIneq(lbPos, pos)); 1402 // This bound is non-negative by definition. 1403 diff = std::max<int64_t>(diff, 0); 1404 if (minDiff == None || diff < minDiff) { 1405 minDiff = diff; 1406 minLbPosition = lbPos; 1407 minUbPosition = ubPos; 1408 } 1409 } 1410 } 1411 if (lb && minDiff.hasValue()) { 1412 // Set lb to the symbolic lower bound. 1413 lb->resize(getNumSymbolIds() + 1); 1414 if (ub) 1415 ub->resize(getNumSymbolIds() + 1); 1416 // The lower bound is the ceildiv of the lb constraint over the coefficient 1417 // of the variable at 'pos'. We express the ceildiv equivalently as a floor 1418 // for uniformity. For eg., if the lower bound constraint was: 32*d0 - N + 1419 // 31 >= 0, the lower bound for d0 is ceil(N - 31, 32), i.e., floor(N, 32). 1420 *boundFloorDivisor = atIneq(minLbPosition, pos); 1421 assert(*boundFloorDivisor == -atIneq(minUbPosition, pos)); 1422 for (unsigned c = 0, e = getNumSymbolIds() + 1; c < e; c++) { 1423 (*lb)[c] = -atIneq(minLbPosition, getNumDimIds() + c); 1424 } 1425 if (ub) { 1426 for (unsigned c = 0, e = getNumSymbolIds() + 1; c < e; c++) 1427 (*ub)[c] = atIneq(minUbPosition, getNumDimIds() + c); 1428 } 1429 // The lower bound leads to a ceildiv while the upper bound is a floordiv 1430 // whenever the coefficient at pos != 1. ceildiv (val / d) = floordiv (val + 1431 // d - 1 / d); hence, the addition of 'atIneq(minLbPosition, pos) - 1' to 1432 // the constant term for the lower bound. 1433 (*lb)[getNumSymbolIds()] += atIneq(minLbPosition, pos) - 1; 1434 } 1435 if (minLbPos) 1436 *minLbPos = minLbPosition; 1437 if (minUbPos) 1438 *minUbPos = minUbPosition; 1439 return minDiff; 1440 } 1441 1442 template <bool isLower> 1443 Optional<int64_t> 1444 IntegerRelation::computeConstantLowerOrUpperBound(unsigned pos) { 1445 assert(pos < getNumIds() && "invalid position"); 1446 // Project to 'pos'. 1447 projectOut(0, pos); 1448 projectOut(1, getNumIds() - 1); 1449 // Check if there's an equality equating the '0'^th identifier to a constant. 1450 int eqRowIdx = findEqualityToConstant(*this, 0, /*symbolic=*/false); 1451 if (eqRowIdx != -1) 1452 // atEq(rowIdx, 0) is either -1 or 1. 1453 return -atEq(eqRowIdx, getNumCols() - 1) / atEq(eqRowIdx, 0); 1454 1455 // Check if the identifier appears at all in any of the inequalities. 1456 unsigned r, e; 1457 for (r = 0, e = getNumInequalities(); r < e; r++) { 1458 if (atIneq(r, 0) != 0) 1459 break; 1460 } 1461 if (r == e) 1462 // If it doesn't, there isn't a bound on it. 1463 return None; 1464 1465 Optional<int64_t> minOrMaxConst = None; 1466 1467 // Take the max across all const lower bounds (or min across all constant 1468 // upper bounds). 1469 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1470 if (isLower) { 1471 if (atIneq(r, 0) <= 0) 1472 // Not a lower bound. 1473 continue; 1474 } else if (atIneq(r, 0) >= 0) { 1475 // Not an upper bound. 1476 continue; 1477 } 1478 unsigned c, f; 1479 for (c = 0, f = getNumCols() - 1; c < f; c++) 1480 if (c != 0 && atIneq(r, c) != 0) 1481 break; 1482 if (c < getNumCols() - 1) 1483 // Not a constant bound. 1484 continue; 1485 1486 int64_t boundConst = 1487 isLower ? mlir::ceilDiv(-atIneq(r, getNumCols() - 1), atIneq(r, 0)) 1488 : mlir::floorDiv(atIneq(r, getNumCols() - 1), -atIneq(r, 0)); 1489 if (isLower) { 1490 if (minOrMaxConst == None || boundConst > minOrMaxConst) 1491 minOrMaxConst = boundConst; 1492 } else { 1493 if (minOrMaxConst == None || boundConst < minOrMaxConst) 1494 minOrMaxConst = boundConst; 1495 } 1496 } 1497 return minOrMaxConst; 1498 } 1499 1500 Optional<int64_t> IntegerRelation::getConstantBound(BoundType type, 1501 unsigned pos) const { 1502 if (type == BoundType::LB) 1503 return IntegerRelation(*this) 1504 .computeConstantLowerOrUpperBound</*isLower=*/true>(pos); 1505 if (type == BoundType::UB) 1506 return IntegerRelation(*this) 1507 .computeConstantLowerOrUpperBound</*isLower=*/false>(pos); 1508 1509 assert(type == BoundType::EQ && "expected EQ"); 1510 Optional<int64_t> lb = 1511 IntegerRelation(*this).computeConstantLowerOrUpperBound</*isLower=*/true>( 1512 pos); 1513 Optional<int64_t> ub = 1514 IntegerRelation(*this) 1515 .computeConstantLowerOrUpperBound</*isLower=*/false>(pos); 1516 return (lb && ub && *lb == *ub) ? Optional<int64_t>(*ub) : None; 1517 } 1518 1519 // A simple (naive and conservative) check for hyper-rectangularity. 1520 bool IntegerRelation::isHyperRectangular(unsigned pos, unsigned num) const { 1521 assert(pos < getNumCols() - 1); 1522 // Check for two non-zero coefficients in the range [pos, pos + sum). 1523 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1524 unsigned sum = 0; 1525 for (unsigned c = pos; c < pos + num; c++) { 1526 if (atIneq(r, c) != 0) 1527 sum++; 1528 } 1529 if (sum > 1) 1530 return false; 1531 } 1532 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 1533 unsigned sum = 0; 1534 for (unsigned c = pos; c < pos + num; c++) { 1535 if (atEq(r, c) != 0) 1536 sum++; 1537 } 1538 if (sum > 1) 1539 return false; 1540 } 1541 return true; 1542 } 1543 1544 /// Removes duplicate constraints, trivially true constraints, and constraints 1545 /// that can be detected as redundant as a result of differing only in their 1546 /// constant term part. A constraint of the form <non-negative constant> >= 0 is 1547 /// considered trivially true. 1548 // Uses a DenseSet to hash and detect duplicates followed by a linear scan to 1549 // remove duplicates in place. 1550 void IntegerRelation::removeTrivialRedundancy() { 1551 gcdTightenInequalities(); 1552 normalizeConstraintsByGCD(); 1553 1554 // A map used to detect redundancy stemming from constraints that only differ 1555 // in their constant term. The value stored is <row position, const term> 1556 // for a given row. 1557 SmallDenseMap<ArrayRef<int64_t>, std::pair<unsigned, int64_t>> 1558 rowsWithoutConstTerm; 1559 // To unique rows. 1560 SmallDenseSet<ArrayRef<int64_t>, 8> rowSet; 1561 1562 // Check if constraint is of the form <non-negative-constant> >= 0. 1563 auto isTriviallyValid = [&](unsigned r) -> bool { 1564 for (unsigned c = 0, e = getNumCols() - 1; c < e; c++) { 1565 if (atIneq(r, c) != 0) 1566 return false; 1567 } 1568 return atIneq(r, getNumCols() - 1) >= 0; 1569 }; 1570 1571 // Detect and mark redundant constraints. 1572 SmallVector<bool, 256> redunIneq(getNumInequalities(), false); 1573 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1574 int64_t *rowStart = &inequalities(r, 0); 1575 auto row = ArrayRef<int64_t>(rowStart, getNumCols()); 1576 if (isTriviallyValid(r) || !rowSet.insert(row).second) { 1577 redunIneq[r] = true; 1578 continue; 1579 } 1580 1581 // Among constraints that only differ in the constant term part, mark 1582 // everything other than the one with the smallest constant term redundant. 1583 // (eg: among i - 16j - 5 >= 0, i - 16j - 1 >=0, i - 16j - 7 >= 0, the 1584 // former two are redundant). 1585 int64_t constTerm = atIneq(r, getNumCols() - 1); 1586 auto rowWithoutConstTerm = ArrayRef<int64_t>(rowStart, getNumCols() - 1); 1587 const auto &ret = 1588 rowsWithoutConstTerm.insert({rowWithoutConstTerm, {r, constTerm}}); 1589 if (!ret.second) { 1590 // Check if the other constraint has a higher constant term. 1591 auto &val = ret.first->second; 1592 if (val.second > constTerm) { 1593 // The stored row is redundant. Mark it so, and update with this one. 1594 redunIneq[val.first] = true; 1595 val = {r, constTerm}; 1596 } else { 1597 // The one stored makes this one redundant. 1598 redunIneq[r] = true; 1599 } 1600 } 1601 } 1602 1603 // Scan to get rid of all rows marked redundant, in-place. 1604 unsigned pos = 0; 1605 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) 1606 if (!redunIneq[r]) 1607 inequalities.copyRow(r, pos++); 1608 1609 inequalities.resizeVertically(pos); 1610 1611 // TODO: consider doing this for equalities as well, but probably not worth 1612 // the savings. 1613 } 1614 1615 #undef DEBUG_TYPE 1616 #define DEBUG_TYPE "fm" 1617 1618 /// Eliminates identifier at the specified position using Fourier-Motzkin 1619 /// variable elimination. This technique is exact for rational spaces but 1620 /// conservative (in "rare" cases) for integer spaces. The operation corresponds 1621 /// to a projection operation yielding the (convex) set of integer points 1622 /// contained in the rational shadow of the set. An emptiness test that relies 1623 /// on this method will guarantee emptiness, i.e., it disproves the existence of 1624 /// a solution if it says it's empty. 1625 /// If a non-null isResultIntegerExact is passed, it is set to true if the 1626 /// result is also integer exact. If it's set to false, the obtained solution 1627 /// *may* not be exact, i.e., it may contain integer points that do not have an 1628 /// integer pre-image in the original set. 1629 /// 1630 /// Eg: 1631 /// j >= 0, j <= i + 1 1632 /// i >= 0, i <= N + 1 1633 /// Eliminating i yields, 1634 /// j >= 0, 0 <= N + 1, j - 1 <= N + 1 1635 /// 1636 /// If darkShadow = true, this method computes the dark shadow on elimination; 1637 /// the dark shadow is a convex integer subset of the exact integer shadow. A 1638 /// non-empty dark shadow proves the existence of an integer solution. The 1639 /// elimination in such a case could however be an under-approximation, and thus 1640 /// should not be used for scanning sets or used by itself for dependence 1641 /// checking. 1642 /// 1643 /// Eg: 2-d set, * represents grid points, 'o' represents a point in the set. 1644 /// ^ 1645 /// | 1646 /// | * * * * o o 1647 /// i | * * o o o o 1648 /// | o * * * * * 1649 /// ---------------> 1650 /// j -> 1651 /// 1652 /// Eliminating i from this system (projecting on the j dimension): 1653 /// rational shadow / integer light shadow: 1 <= j <= 6 1654 /// dark shadow: 3 <= j <= 6 1655 /// exact integer shadow: j = 1 \union 3 <= j <= 6 1656 /// holes/splinters: j = 2 1657 /// 1658 /// darkShadow = false, isResultIntegerExact = nullptr are default values. 1659 // TODO: a slight modification to yield dark shadow version of FM (tightened), 1660 // which can prove the existence of a solution if there is one. 1661 void IntegerRelation::fourierMotzkinEliminate(unsigned pos, bool darkShadow, 1662 bool *isResultIntegerExact) { 1663 LLVM_DEBUG(llvm::dbgs() << "FM input (eliminate pos " << pos << "):\n"); 1664 LLVM_DEBUG(dump()); 1665 assert(pos < getNumIds() && "invalid position"); 1666 assert(hasConsistentState()); 1667 1668 // Check if this identifier can be eliminated through a substitution. 1669 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 1670 if (atEq(r, pos) != 0) { 1671 // Use Gaussian elimination here (since we have an equality). 1672 LogicalResult ret = gaussianEliminateId(pos); 1673 (void)ret; 1674 assert(succeeded(ret) && "Gaussian elimination guaranteed to succeed"); 1675 LLVM_DEBUG(llvm::dbgs() << "FM output (through Gaussian elimination):\n"); 1676 LLVM_DEBUG(dump()); 1677 return; 1678 } 1679 } 1680 1681 // A fast linear time tightening. 1682 gcdTightenInequalities(); 1683 1684 // Check if the identifier appears at all in any of the inequalities. 1685 if (isColZero(pos)) { 1686 // If it doesn't appear, just remove the column and return. 1687 // TODO: refactor removeColumns to use it from here. 1688 removeId(pos); 1689 LLVM_DEBUG(llvm::dbgs() << "FM output:\n"); 1690 LLVM_DEBUG(dump()); 1691 return; 1692 } 1693 1694 // Positions of constraints that are lower bounds on the variable. 1695 SmallVector<unsigned, 4> lbIndices; 1696 // Positions of constraints that are lower bounds on the variable. 1697 SmallVector<unsigned, 4> ubIndices; 1698 // Positions of constraints that do not involve the variable. 1699 std::vector<unsigned> nbIndices; 1700 nbIndices.reserve(getNumInequalities()); 1701 1702 // Gather all lower bounds and upper bounds of the variable. Since the 1703 // canonical form c_1*x_1 + c_2*x_2 + ... + c_0 >= 0, a constraint is a lower 1704 // bound for x_i if c_i >= 1, and an upper bound if c_i <= -1. 1705 for (unsigned r = 0, e = getNumInequalities(); r < e; r++) { 1706 if (atIneq(r, pos) == 0) { 1707 // Id does not appear in bound. 1708 nbIndices.push_back(r); 1709 } else if (atIneq(r, pos) >= 1) { 1710 // Lower bound. 1711 lbIndices.push_back(r); 1712 } else { 1713 // Upper bound. 1714 ubIndices.push_back(r); 1715 } 1716 } 1717 1718 PresburgerSpace newSpace = getSpace(); 1719 IdKind idKindRemove = newSpace.getIdKindAt(pos); 1720 unsigned relativePos = pos - newSpace.getIdKindOffset(idKindRemove); 1721 newSpace.removeIdRange(idKindRemove, relativePos, relativePos + 1); 1722 1723 /// Create the new system which has one identifier less. 1724 IntegerRelation newRel(lbIndices.size() * ubIndices.size() + nbIndices.size(), 1725 getNumEqualities(), getNumCols() - 1, newSpace); 1726 1727 // This will be used to check if the elimination was integer exact. 1728 unsigned lcmProducts = 1; 1729 1730 // Let x be the variable we are eliminating. 1731 // For each lower bound, lb <= c_l*x, and each upper bound c_u*x <= ub, (note 1732 // that c_l, c_u >= 1) we have: 1733 // lb*lcm(c_l, c_u)/c_l <= lcm(c_l, c_u)*x <= ub*lcm(c_l, c_u)/c_u 1734 // We thus generate a constraint: 1735 // lcm(c_l, c_u)/c_l*lb <= lcm(c_l, c_u)/c_u*ub. 1736 // Note if c_l = c_u = 1, all integer points captured by the resulting 1737 // constraint correspond to integer points in the original system (i.e., they 1738 // have integer pre-images). Hence, if the lcm's are all 1, the elimination is 1739 // integer exact. 1740 for (auto ubPos : ubIndices) { 1741 for (auto lbPos : lbIndices) { 1742 SmallVector<int64_t, 4> ineq; 1743 ineq.reserve(newRel.getNumCols()); 1744 int64_t lbCoeff = atIneq(lbPos, pos); 1745 // Note that in the comments above, ubCoeff is the negation of the 1746 // coefficient in the canonical form as the view taken here is that of the 1747 // term being moved to the other size of '>='. 1748 int64_t ubCoeff = -atIneq(ubPos, pos); 1749 // TODO: refactor this loop to avoid all branches inside. 1750 for (unsigned l = 0, e = getNumCols(); l < e; l++) { 1751 if (l == pos) 1752 continue; 1753 assert(lbCoeff >= 1 && ubCoeff >= 1 && "bounds wrongly identified"); 1754 int64_t lcm = mlir::lcm(lbCoeff, ubCoeff); 1755 ineq.push_back(atIneq(ubPos, l) * (lcm / ubCoeff) + 1756 atIneq(lbPos, l) * (lcm / lbCoeff)); 1757 lcmProducts *= lcm; 1758 } 1759 if (darkShadow) { 1760 // The dark shadow is a convex subset of the exact integer shadow. If 1761 // there is a point here, it proves the existence of a solution. 1762 ineq[ineq.size() - 1] += lbCoeff * ubCoeff - lbCoeff - ubCoeff + 1; 1763 } 1764 // TODO: we need to have a way to add inequalities in-place in 1765 // IntegerRelation instead of creating and copying over. 1766 newRel.addInequality(ineq); 1767 } 1768 } 1769 1770 LLVM_DEBUG(llvm::dbgs() << "FM isResultIntegerExact: " << (lcmProducts == 1) 1771 << "\n"); 1772 if (lcmProducts == 1 && isResultIntegerExact) 1773 *isResultIntegerExact = true; 1774 1775 // Copy over the constraints not involving this variable. 1776 for (auto nbPos : nbIndices) { 1777 SmallVector<int64_t, 4> ineq; 1778 ineq.reserve(getNumCols() - 1); 1779 for (unsigned l = 0, e = getNumCols(); l < e; l++) { 1780 if (l == pos) 1781 continue; 1782 ineq.push_back(atIneq(nbPos, l)); 1783 } 1784 newRel.addInequality(ineq); 1785 } 1786 1787 assert(newRel.getNumConstraints() == 1788 lbIndices.size() * ubIndices.size() + nbIndices.size()); 1789 1790 // Copy over the equalities. 1791 for (unsigned r = 0, e = getNumEqualities(); r < e; r++) { 1792 SmallVector<int64_t, 4> eq; 1793 eq.reserve(newRel.getNumCols()); 1794 for (unsigned l = 0, e = getNumCols(); l < e; l++) { 1795 if (l == pos) 1796 continue; 1797 eq.push_back(atEq(r, l)); 1798 } 1799 newRel.addEquality(eq); 1800 } 1801 1802 // GCD tightening and normalization allows detection of more trivially 1803 // redundant constraints. 1804 newRel.gcdTightenInequalities(); 1805 newRel.normalizeConstraintsByGCD(); 1806 newRel.removeTrivialRedundancy(); 1807 clearAndCopyFrom(newRel); 1808 LLVM_DEBUG(llvm::dbgs() << "FM output:\n"); 1809 LLVM_DEBUG(dump()); 1810 } 1811 1812 #undef DEBUG_TYPE 1813 #define DEBUG_TYPE "presburger" 1814 1815 void IntegerRelation::projectOut(unsigned pos, unsigned num) { 1816 if (num == 0) 1817 return; 1818 1819 // 'pos' can be at most getNumCols() - 2 if num > 0. 1820 assert((getNumCols() < 2 || pos <= getNumCols() - 2) && "invalid position"); 1821 assert(pos + num < getNumCols() && "invalid range"); 1822 1823 // Eliminate as many identifiers as possible using Gaussian elimination. 1824 unsigned currentPos = pos; 1825 unsigned numToEliminate = num; 1826 unsigned numGaussianEliminated = 0; 1827 1828 while (currentPos < getNumIds()) { 1829 unsigned curNumEliminated = 1830 gaussianEliminateIds(currentPos, currentPos + numToEliminate); 1831 ++currentPos; 1832 numToEliminate -= curNumEliminated + 1; 1833 numGaussianEliminated += curNumEliminated; 1834 } 1835 1836 // Eliminate the remaining using Fourier-Motzkin. 1837 for (unsigned i = 0; i < num - numGaussianEliminated; i++) { 1838 unsigned numToEliminate = num - numGaussianEliminated - i; 1839 fourierMotzkinEliminate( 1840 getBestIdToEliminate(*this, pos, pos + numToEliminate)); 1841 } 1842 1843 // Fast/trivial simplifications. 1844 gcdTightenInequalities(); 1845 // Normalize constraints after tightening since the latter impacts this, but 1846 // not the other way round. 1847 normalizeConstraintsByGCD(); 1848 } 1849 1850 namespace { 1851 1852 enum BoundCmpResult { Greater, Less, Equal, Unknown }; 1853 1854 /// Compares two affine bounds whose coefficients are provided in 'first' and 1855 /// 'second'. The last coefficient is the constant term. 1856 static BoundCmpResult compareBounds(ArrayRef<int64_t> a, ArrayRef<int64_t> b) { 1857 assert(a.size() == b.size()); 1858 1859 // For the bounds to be comparable, their corresponding identifier 1860 // coefficients should be equal; the constant terms are then compared to 1861 // determine less/greater/equal. 1862 1863 if (!std::equal(a.begin(), a.end() - 1, b.begin())) 1864 return Unknown; 1865 1866 if (a.back() == b.back()) 1867 return Equal; 1868 1869 return a.back() < b.back() ? Less : Greater; 1870 } 1871 } // namespace 1872 1873 // Returns constraints that are common to both A & B. 1874 static void getCommonConstraints(const IntegerRelation &a, 1875 const IntegerRelation &b, IntegerRelation &c) { 1876 c = IntegerRelation(a.getSpace()); 1877 // a naive O(n^2) check should be enough here given the input sizes. 1878 for (unsigned r = 0, e = a.getNumInequalities(); r < e; ++r) { 1879 for (unsigned s = 0, f = b.getNumInequalities(); s < f; ++s) { 1880 if (a.getInequality(r) == b.getInequality(s)) { 1881 c.addInequality(a.getInequality(r)); 1882 break; 1883 } 1884 } 1885 } 1886 for (unsigned r = 0, e = a.getNumEqualities(); r < e; ++r) { 1887 for (unsigned s = 0, f = b.getNumEqualities(); s < f; ++s) { 1888 if (a.getEquality(r) == b.getEquality(s)) { 1889 c.addEquality(a.getEquality(r)); 1890 break; 1891 } 1892 } 1893 } 1894 } 1895 1896 // Computes the bounding box with respect to 'other' by finding the min of the 1897 // lower bounds and the max of the upper bounds along each of the dimensions. 1898 LogicalResult 1899 IntegerRelation::unionBoundingBox(const IntegerRelation &otherCst) { 1900 assert(isSpaceEqual(otherCst) && "Spaces should match."); 1901 assert(getNumLocalIds() == 0 && "local ids not supported yet here"); 1902 1903 // Get the constraints common to both systems; these will be added as is to 1904 // the union. 1905 IntegerRelation commonCst(PresburgerSpace::getRelationSpace()); 1906 getCommonConstraints(*this, otherCst, commonCst); 1907 1908 std::vector<SmallVector<int64_t, 8>> boundingLbs; 1909 std::vector<SmallVector<int64_t, 8>> boundingUbs; 1910 boundingLbs.reserve(2 * getNumDimIds()); 1911 boundingUbs.reserve(2 * getNumDimIds()); 1912 1913 // To hold lower and upper bounds for each dimension. 1914 SmallVector<int64_t, 4> lb, otherLb, ub, otherUb; 1915 // To compute min of lower bounds and max of upper bounds for each dimension. 1916 SmallVector<int64_t, 4> minLb(getNumSymbolIds() + 1); 1917 SmallVector<int64_t, 4> maxUb(getNumSymbolIds() + 1); 1918 // To compute final new lower and upper bounds for the union. 1919 SmallVector<int64_t, 8> newLb(getNumCols()), newUb(getNumCols()); 1920 1921 int64_t lbFloorDivisor, otherLbFloorDivisor; 1922 for (unsigned d = 0, e = getNumDimIds(); d < e; ++d) { 1923 auto extent = getConstantBoundOnDimSize(d, &lb, &lbFloorDivisor, &ub); 1924 if (!extent.hasValue()) 1925 // TODO: symbolic extents when necessary. 1926 // TODO: handle union if a dimension is unbounded. 1927 return failure(); 1928 1929 auto otherExtent = otherCst.getConstantBoundOnDimSize( 1930 d, &otherLb, &otherLbFloorDivisor, &otherUb); 1931 if (!otherExtent.hasValue() || lbFloorDivisor != otherLbFloorDivisor) 1932 // TODO: symbolic extents when necessary. 1933 return failure(); 1934 1935 assert(lbFloorDivisor > 0 && "divisor always expected to be positive"); 1936 1937 auto res = compareBounds(lb, otherLb); 1938 // Identify min. 1939 if (res == BoundCmpResult::Less || res == BoundCmpResult::Equal) { 1940 minLb = lb; 1941 // Since the divisor is for a floordiv, we need to convert to ceildiv, 1942 // i.e., i >= expr floordiv div <=> i >= (expr - div + 1) ceildiv div <=> 1943 // div * i >= expr - div + 1. 1944 minLb.back() -= lbFloorDivisor - 1; 1945 } else if (res == BoundCmpResult::Greater) { 1946 minLb = otherLb; 1947 minLb.back() -= otherLbFloorDivisor - 1; 1948 } else { 1949 // Uncomparable - check for constant lower/upper bounds. 1950 auto constLb = getConstantBound(BoundType::LB, d); 1951 auto constOtherLb = otherCst.getConstantBound(BoundType::LB, d); 1952 if (!constLb.hasValue() || !constOtherLb.hasValue()) 1953 return failure(); 1954 std::fill(minLb.begin(), minLb.end(), 0); 1955 minLb.back() = std::min(constLb.getValue(), constOtherLb.getValue()); 1956 } 1957 1958 // Do the same for ub's but max of upper bounds. Identify max. 1959 auto uRes = compareBounds(ub, otherUb); 1960 if (uRes == BoundCmpResult::Greater || uRes == BoundCmpResult::Equal) { 1961 maxUb = ub; 1962 } else if (uRes == BoundCmpResult::Less) { 1963 maxUb = otherUb; 1964 } else { 1965 // Uncomparable - check for constant lower/upper bounds. 1966 auto constUb = getConstantBound(BoundType::UB, d); 1967 auto constOtherUb = otherCst.getConstantBound(BoundType::UB, d); 1968 if (!constUb.hasValue() || !constOtherUb.hasValue()) 1969 return failure(); 1970 std::fill(maxUb.begin(), maxUb.end(), 0); 1971 maxUb.back() = std::max(constUb.getValue(), constOtherUb.getValue()); 1972 } 1973 1974 std::fill(newLb.begin(), newLb.end(), 0); 1975 std::fill(newUb.begin(), newUb.end(), 0); 1976 1977 // The divisor for lb, ub, otherLb, otherUb at this point is lbDivisor, 1978 // and so it's the divisor for newLb and newUb as well. 1979 newLb[d] = lbFloorDivisor; 1980 newUb[d] = -lbFloorDivisor; 1981 // Copy over the symbolic part + constant term. 1982 std::copy(minLb.begin(), minLb.end(), newLb.begin() + getNumDimIds()); 1983 std::transform(newLb.begin() + getNumDimIds(), newLb.end(), 1984 newLb.begin() + getNumDimIds(), std::negate<int64_t>()); 1985 std::copy(maxUb.begin(), maxUb.end(), newUb.begin() + getNumDimIds()); 1986 1987 boundingLbs.push_back(newLb); 1988 boundingUbs.push_back(newUb); 1989 } 1990 1991 // Clear all constraints and add the lower/upper bounds for the bounding box. 1992 clearConstraints(); 1993 for (unsigned d = 0, e = getNumDimIds(); d < e; ++d) { 1994 addInequality(boundingLbs[d]); 1995 addInequality(boundingUbs[d]); 1996 } 1997 1998 // Add the constraints that were common to both systems. 1999 append(commonCst); 2000 removeTrivialRedundancy(); 2001 2002 // TODO: copy over pure symbolic constraints from this and 'other' over to the 2003 // union (since the above are just the union along dimensions); we shouldn't 2004 // be discarding any other constraints on the symbols. 2005 2006 return success(); 2007 } 2008 2009 bool IntegerRelation::isColZero(unsigned pos) const { 2010 unsigned rowPos; 2011 return !findConstraintWithNonZeroAt(pos, /*isEq=*/false, &rowPos) && 2012 !findConstraintWithNonZeroAt(pos, /*isEq=*/true, &rowPos); 2013 } 2014 2015 /// Find positions of inequalities and equalities that do not have a coefficient 2016 /// for [pos, pos + num) identifiers. 2017 static void getIndependentConstraints(const IntegerRelation &cst, unsigned pos, 2018 unsigned num, 2019 SmallVectorImpl<unsigned> &nbIneqIndices, 2020 SmallVectorImpl<unsigned> &nbEqIndices) { 2021 assert(pos < cst.getNumIds() && "invalid start position"); 2022 assert(pos + num <= cst.getNumIds() && "invalid limit"); 2023 2024 for (unsigned r = 0, e = cst.getNumInequalities(); r < e; r++) { 2025 // The bounds are to be independent of [offset, offset + num) columns. 2026 unsigned c; 2027 for (c = pos; c < pos + num; ++c) { 2028 if (cst.atIneq(r, c) != 0) 2029 break; 2030 } 2031 if (c == pos + num) 2032 nbIneqIndices.push_back(r); 2033 } 2034 2035 for (unsigned r = 0, e = cst.getNumEqualities(); r < e; r++) { 2036 // The bounds are to be independent of [offset, offset + num) columns. 2037 unsigned c; 2038 for (c = pos; c < pos + num; ++c) { 2039 if (cst.atEq(r, c) != 0) 2040 break; 2041 } 2042 if (c == pos + num) 2043 nbEqIndices.push_back(r); 2044 } 2045 } 2046 2047 void IntegerRelation::removeIndependentConstraints(unsigned pos, unsigned num) { 2048 assert(pos + num <= getNumIds() && "invalid range"); 2049 2050 // Remove constraints that are independent of these identifiers. 2051 SmallVector<unsigned, 4> nbIneqIndices, nbEqIndices; 2052 getIndependentConstraints(*this, /*pos=*/0, num, nbIneqIndices, nbEqIndices); 2053 2054 // Iterate in reverse so that indices don't have to be updated. 2055 // TODO: This method can be made more efficient (because removal of each 2056 // inequality leads to much shifting/copying in the underlying buffer). 2057 for (auto nbIndex : llvm::reverse(nbIneqIndices)) 2058 removeInequality(nbIndex); 2059 for (auto nbIndex : llvm::reverse(nbEqIndices)) 2060 removeEquality(nbIndex); 2061 } 2062 2063 void IntegerRelation::printSpace(raw_ostream &os) const { 2064 PresburgerSpace::print(os); 2065 os << getNumConstraints() << " constraints\n"; 2066 } 2067 2068 void IntegerRelation::print(raw_ostream &os) const { 2069 assert(hasConsistentState()); 2070 printSpace(os); 2071 for (unsigned i = 0, e = getNumEqualities(); i < e; ++i) { 2072 for (unsigned j = 0, f = getNumCols(); j < f; ++j) { 2073 os << atEq(i, j) << " "; 2074 } 2075 os << "= 0\n"; 2076 } 2077 for (unsigned i = 0, e = getNumInequalities(); i < e; ++i) { 2078 for (unsigned j = 0, f = getNumCols(); j < f; ++j) { 2079 os << atIneq(i, j) << " "; 2080 } 2081 os << ">= 0\n"; 2082 } 2083 os << '\n'; 2084 } 2085 2086 void IntegerRelation::dump() const { print(llvm::errs()); } 2087 2088 unsigned IntegerPolyhedron::insertId(IdKind kind, unsigned pos, unsigned num) { 2089 assert((kind != IdKind::Domain || num == 0) && 2090 "Domain has to be zero in a set"); 2091 return IntegerRelation::insertId(kind, pos, num); 2092 } 2093