11022febdSAbhinav271828 //===- QuasiPolynomial.cpp - Quasipolynomial Class --------------*- C++ -*-===// 21022febdSAbhinav271828 // 31022febdSAbhinav271828 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 41022febdSAbhinav271828 // See https://llvm.org/LICENSE.txt for license information. 51022febdSAbhinav271828 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61022febdSAbhinav271828 // 71022febdSAbhinav271828 //===----------------------------------------------------------------------===// 81022febdSAbhinav271828 91022febdSAbhinav271828 #include "mlir/Analysis/Presburger/QuasiPolynomial.h" 101022febdSAbhinav271828 #include "mlir/Analysis/Presburger/Fraction.h" 111022febdSAbhinav271828 #include "mlir/Analysis/Presburger/PresburgerSpace.h" 121022febdSAbhinav271828 131022febdSAbhinav271828 using namespace mlir; 141022febdSAbhinav271828 using namespace presburger; 151022febdSAbhinav271828 161022febdSAbhinav271828 QuasiPolynomial::QuasiPolynomial( 17*266a5a9cSRamkumar Ramachandra unsigned numVars, ArrayRef<Fraction> coeffs, 18*266a5a9cSRamkumar Ramachandra ArrayRef<std::vector<SmallVector<Fraction>>> aff) 191022febdSAbhinav271828 : PresburgerSpace(/*numDomain=*/numVars, /*numRange=*/1, /*numSymbols=*/0, 201022febdSAbhinav271828 /*numLocals=*/0), 211022febdSAbhinav271828 coefficients(coeffs), affine(aff) { 22c86fe3eeSJie Fu #ifndef NDEBUG 231022febdSAbhinav271828 // For each term which involves at least one affine function, 241022febdSAbhinav271828 for (const std::vector<SmallVector<Fraction>> &term : affine) { 25b238a0d9SAdrian Kuegel if (term.empty()) 261022febdSAbhinav271828 continue; 271022febdSAbhinav271828 // the number of elements in each affine function is 281022febdSAbhinav271828 // one more than the number of symbols. 291022febdSAbhinav271828 for (const SmallVector<Fraction> &aff : term) { 301022febdSAbhinav271828 assert(aff.size() == getNumInputs() + 1 && 311022febdSAbhinav271828 "dimensionality of affine functions does not match number of " 321022febdSAbhinav271828 "symbols!"); 331022febdSAbhinav271828 } 341022febdSAbhinav271828 } 35c86fe3eeSJie Fu #endif // NDEBUG 361022febdSAbhinav271828 } 371022febdSAbhinav271828 38850f713eSAbhinav271828 /// Define a quasipolynomial which is a single constant. 39*266a5a9cSRamkumar Ramachandra QuasiPolynomial::QuasiPolynomial(unsigned numVars, const Fraction &constant) 40850f713eSAbhinav271828 : PresburgerSpace(/*numDomain=*/numVars, /*numRange=*/1, /*numSymbols=*/0, 41850f713eSAbhinav271828 /*numLocals=*/0), 42850f713eSAbhinav271828 coefficients({constant}), affine({{}}) {} 43850f713eSAbhinav271828 441022febdSAbhinav271828 QuasiPolynomial QuasiPolynomial::operator+(const QuasiPolynomial &x) const { 451022febdSAbhinav271828 assert(getNumInputs() == x.getNumInputs() && 461022febdSAbhinav271828 "two quasi-polynomials with different numbers of symbols cannot " 471022febdSAbhinav271828 "be added!"); 481022febdSAbhinav271828 SmallVector<Fraction> sumCoeffs = coefficients; 491022febdSAbhinav271828 sumCoeffs.append(x.coefficients); 501022febdSAbhinav271828 std::vector<std::vector<SmallVector<Fraction>>> sumAff = affine; 511022febdSAbhinav271828 sumAff.insert(sumAff.end(), x.affine.begin(), x.affine.end()); 521022febdSAbhinav271828 return QuasiPolynomial(getNumInputs(), sumCoeffs, sumAff); 531022febdSAbhinav271828 } 541022febdSAbhinav271828 551022febdSAbhinav271828 QuasiPolynomial QuasiPolynomial::operator-(const QuasiPolynomial &x) const { 561022febdSAbhinav271828 assert(getNumInputs() == x.getNumInputs() && 571022febdSAbhinav271828 "two quasi-polynomials with different numbers of symbols cannot " 581022febdSAbhinav271828 "be subtracted!"); 591022febdSAbhinav271828 QuasiPolynomial qp(getNumInputs(), x.coefficients, x.affine); 601022febdSAbhinav271828 for (Fraction &coeff : qp.coefficients) 611022febdSAbhinav271828 coeff = -coeff; 621022febdSAbhinav271828 return *this + qp; 631022febdSAbhinav271828 } 641022febdSAbhinav271828 651022febdSAbhinav271828 QuasiPolynomial QuasiPolynomial::operator*(const QuasiPolynomial &x) const { 661022febdSAbhinav271828 assert(getNumInputs() == x.getNumInputs() && 671022febdSAbhinav271828 "two quasi-polynomials with different numbers of " 681022febdSAbhinav271828 "symbols cannot be multiplied!"); 691022febdSAbhinav271828 701022febdSAbhinav271828 SmallVector<Fraction> coeffs; 711022febdSAbhinav271828 coeffs.reserve(coefficients.size() * x.coefficients.size()); 721022febdSAbhinav271828 for (const Fraction &coeff : coefficients) 731022febdSAbhinav271828 for (const Fraction &xcoeff : x.coefficients) 74*266a5a9cSRamkumar Ramachandra coeffs.emplace_back(coeff * xcoeff); 751022febdSAbhinav271828 761022febdSAbhinav271828 std::vector<SmallVector<Fraction>> product; 771022febdSAbhinav271828 std::vector<std::vector<SmallVector<Fraction>>> aff; 781022febdSAbhinav271828 aff.reserve(affine.size() * x.affine.size()); 791022febdSAbhinav271828 for (const std::vector<SmallVector<Fraction>> &term : affine) { 801022febdSAbhinav271828 for (const std::vector<SmallVector<Fraction>> &xterm : x.affine) { 811022febdSAbhinav271828 product.clear(); 821022febdSAbhinav271828 product.insert(product.end(), term.begin(), term.end()); 831022febdSAbhinav271828 product.insert(product.end(), xterm.begin(), xterm.end()); 84*266a5a9cSRamkumar Ramachandra aff.emplace_back(product); 851022febdSAbhinav271828 } 861022febdSAbhinav271828 } 871022febdSAbhinav271828 881022febdSAbhinav271828 return QuasiPolynomial(getNumInputs(), coeffs, aff); 891022febdSAbhinav271828 } 901022febdSAbhinav271828 91*266a5a9cSRamkumar Ramachandra QuasiPolynomial QuasiPolynomial::operator/(const Fraction &x) const { 921022febdSAbhinav271828 assert(x != 0 && "division by zero!"); 931022febdSAbhinav271828 QuasiPolynomial qp(*this); 941022febdSAbhinav271828 for (Fraction &coeff : qp.coefficients) 951022febdSAbhinav271828 coeff /= x; 961022febdSAbhinav271828 return qp; 971022febdSAbhinav271828 } 981022febdSAbhinav271828 9968a5261dSAbhinav271828 // Removes terms which evaluate to zero from the expression and 10068a5261dSAbhinav271828 // integrate affine functions which are constants into the 10168a5261dSAbhinav271828 // coefficients. 1021022febdSAbhinav271828 QuasiPolynomial QuasiPolynomial::simplify() { 10368a5261dSAbhinav271828 Fraction newCoeff = 0; 1041022febdSAbhinav271828 SmallVector<Fraction> newCoeffs({}); 10568a5261dSAbhinav271828 10668a5261dSAbhinav271828 std::vector<SmallVector<Fraction>> newAffineTerm({}); 1071022febdSAbhinav271828 std::vector<std::vector<SmallVector<Fraction>>> newAffine({}); 10868a5261dSAbhinav271828 10968a5261dSAbhinav271828 unsigned numParam = getNumInputs(); 11068a5261dSAbhinav271828 1111022febdSAbhinav271828 for (unsigned i = 0, e = coefficients.size(); i < e; i++) { 1121022febdSAbhinav271828 // A term is zero if its coefficient is zero, or 1131022febdSAbhinav271828 if (coefficients[i] == Fraction(0, 1)) 1141022febdSAbhinav271828 continue; 1151022febdSAbhinav271828 bool product_is_zero = 1161022febdSAbhinav271828 // if any of the affine functions in the product 1171022febdSAbhinav271828 llvm::any_of(affine[i], [](const SmallVector<Fraction> &affine_ij) { 1181022febdSAbhinav271828 // has all its coefficients as zero. 1191022febdSAbhinav271828 return llvm::all_of(affine_ij, 1201022febdSAbhinav271828 [](const Fraction &f) { return f == 0; }); 1211022febdSAbhinav271828 }); 1221022febdSAbhinav271828 if (product_is_zero) 1231022febdSAbhinav271828 continue; 12468a5261dSAbhinav271828 12568a5261dSAbhinav271828 // Now, we know the term is nonzero. 12668a5261dSAbhinav271828 12768a5261dSAbhinav271828 // We now eliminate the affine functions which are constant 12868a5261dSAbhinav271828 // by merging them into the coefficients. 12968a5261dSAbhinav271828 newAffineTerm = {}; 13068a5261dSAbhinav271828 newCoeff = coefficients[i]; 13168a5261dSAbhinav271828 for (ArrayRef<Fraction> term : affine[i]) { 13268a5261dSAbhinav271828 bool allCoeffsZero = llvm::all_of( 133*266a5a9cSRamkumar Ramachandra term.slice(0, numParam), [](const Fraction &c) { return c == 0; }); 13468a5261dSAbhinav271828 if (allCoeffsZero) 13568a5261dSAbhinav271828 newCoeff *= term[numParam]; 13668a5261dSAbhinav271828 else 137*266a5a9cSRamkumar Ramachandra newAffineTerm.emplace_back(term); 13868a5261dSAbhinav271828 } 13968a5261dSAbhinav271828 140*266a5a9cSRamkumar Ramachandra newCoeffs.emplace_back(newCoeff); 141*266a5a9cSRamkumar Ramachandra newAffine.emplace_back(newAffineTerm); 14268a5261dSAbhinav271828 } 14368a5261dSAbhinav271828 return QuasiPolynomial(getNumInputs(), newCoeffs, newAffine); 14468a5261dSAbhinav271828 } 14568a5261dSAbhinav271828 14668a5261dSAbhinav271828 QuasiPolynomial QuasiPolynomial::collectTerms() { 14768a5261dSAbhinav271828 SmallVector<Fraction> newCoeffs({}); 14868a5261dSAbhinav271828 std::vector<std::vector<SmallVector<Fraction>>> newAffine({}); 14968a5261dSAbhinav271828 15068a5261dSAbhinav271828 for (unsigned i = 0, e = affine.size(); i < e; i++) { 15168a5261dSAbhinav271828 bool alreadyPresent = false; 15268a5261dSAbhinav271828 for (unsigned j = 0, f = newAffine.size(); j < f; j++) { 15368a5261dSAbhinav271828 if (affine[i] == newAffine[j]) { 15468a5261dSAbhinav271828 newCoeffs[j] += coefficients[i]; 15568a5261dSAbhinav271828 alreadyPresent = true; 15668a5261dSAbhinav271828 } 15768a5261dSAbhinav271828 } 15868a5261dSAbhinav271828 if (alreadyPresent) 15968a5261dSAbhinav271828 continue; 160*266a5a9cSRamkumar Ramachandra newCoeffs.emplace_back(coefficients[i]); 161*266a5a9cSRamkumar Ramachandra newAffine.emplace_back(affine[i]); 1621022febdSAbhinav271828 } 16368a5261dSAbhinav271828 1641022febdSAbhinav271828 return QuasiPolynomial(getNumInputs(), newCoeffs, newAffine); 1651022febdSAbhinav271828 } 166850f713eSAbhinav271828 167850f713eSAbhinav271828 Fraction QuasiPolynomial::getConstantTerm() { 168850f713eSAbhinav271828 Fraction constTerm = 0; 169850f713eSAbhinav271828 for (unsigned i = 0, e = coefficients.size(); i < e; ++i) 170*266a5a9cSRamkumar Ramachandra if (affine[i].empty()) 171850f713eSAbhinav271828 constTerm += coefficients[i]; 172850f713eSAbhinav271828 return constTerm; 173850f713eSAbhinav271828 } 174