xref: /llvm-project/mlir/lib/Analysis/Presburger/QuasiPolynomial.cpp (revision 266a5a9cb9daa96c1eeaebc18e10f5a37d638734)
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