-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[MLIR][Presburger] Generating functions and quasi-polynomials for Barvinok's algorithm #75702
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 39 commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
b65a078
Definitions for gf and qp classes
Abhinav271828 6101acb
Comments
Abhinav271828 5d425bd
Miscellaneous reformatting
Abhinav271828 883e993
Remove superfluous == operator
Abhinav271828 2812e75
Use SmallVector::append() instead of insert()
Abhinav271828 625b1b1
Refactor numParam as private attribute
Abhinav271828 94b5996
Formatting fixes
Abhinav271828 f005fdc
Add type instead of auto
Abhinav271828 34da1b2
Pass numParam
Abhinav271828 07e5be7
Use range-based loop
Abhinav271828 f255ad1
Formatting
Abhinav271828 ef899d9
Use llvm::any_of and llvm::all_of
Abhinav271828 9bc0cb5
Make data private
Abhinav271828 d1e6b24
Define getters
Abhinav271828 c04f6d9
Refactor headers
Abhinav271828 ebccab2
Define equality of QPs
Abhinav271828 e89e96b
Formatting
Abhinav271828 dcc0bf4
Fix arith operators
Abhinav271828 7b5a469
Formatting
Abhinav271828 deca816
Formatting
Abhinav271828 fb8a772
Fix multiplication operator
Abhinav271828 bb52a35
Arithmetic tests for QP
Abhinav271828 8803dbf
Test for division
Abhinav271828 5666b5c
Fix test and add simplify test
Abhinav271828 47cbb94
Fix GF addition
Abhinav271828 419c410
Formatting
Abhinav271828 c46cb86
Fix comments
Abhinav271828 5bbd0f2
Use const
Abhinav271828 dee486f
Fix vector definitions
Abhinav271828 ab1d130
Comments on tests
Abhinav271828 1a3575e
Fix name of test
Abhinav271828 712404b
Break down condition
Abhinav271828 22b8429
Check all terms in assert
Abhinav271828 e6e05e1
Move getters to header and operators to cpp
Abhinav271828 94ec54b
Fix QP initialization
Abhinav271828 59f697a
Return const refs in getters
Abhinav271828 3eb698b
Fix loop braces
Abhinav271828 1bada4e
Shift -1 to +1 on unsigned int
Abhinav271828 1a06ac0
Inherit QP from PresburgerSpace and replace numParam with numVars
Abhinav271828 933c365
Avoid copying
Abhinav271828 1281960
Fix formatting of GF
Abhinav271828 0ea156f
Remove extra includes and use FracMatrix
Abhinav271828 d921aa4
Fix numerator printing for GF
Abhinav271828 8b4dd2f
Rename EXPECT_EQ_QUASIPOLYNOMIAL
Abhinav271828 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
//===- QuasiPolynomial.h - QuasiPolynomial Class ----------------*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Definition of the QuasiPolynomial class for Barvinok's algorithm, | ||
// which represents a single-valued function on a set of parameters. | ||
// It is an expression of the form | ||
// f(x) = \sum_i c_i * \prod_j ⌊g_{ij}(x)⌋ | ||
// where c_i \in Q and | ||
// g_{ij} : Q^d -> Q are affine functionals over d parameters. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef MLIR_ANALYSIS_PRESBURGER_QUASIPOLYNOMIAL_H | ||
#define MLIR_ANALYSIS_PRESBURGER_QUASIPOLYNOMIAL_H | ||
|
||
#include "mlir/Analysis/Presburger/Fraction.h" | ||
#include "mlir/Analysis/Presburger/Matrix.h" | ||
#include "mlir/Analysis/Presburger/PresburgerSpace.h" | ||
|
||
namespace mlir { | ||
namespace presburger { | ||
|
||
// A class to describe quasi-polynomials. | ||
// A quasipolynomial consists of a set of terms. | ||
// The ith term is a constant `coefficients[i]`, multiplied | ||
// by the product of a set of affine functions on n parameters. | ||
// Represents functions f : Q^n -> Q of the form | ||
// | ||
// f(x) = \sum_i c_i * \prod_j ⌊g_{ij}(x)⌋ | ||
// | ||
// where c_i \in Q and | ||
// g_{ij} : Q^n -> Q are affine functionals. | ||
class QuasiPolynomial : public PresburgerSpace { | ||
public: | ||
QuasiPolynomial(unsigned numVars, SmallVector<Fraction> coeffs = {}, | ||
std::vector<std::vector<SmallVector<Fraction>>> aff = {}); | ||
|
||
// Find the number of inputs (numDomain) to the polynomial. | ||
// numSymbols is set to zero. | ||
unsigned getNumInputs() const { | ||
return getNumDomainVars() + getNumSymbolVars(); | ||
} | ||
|
||
const SmallVector<Fraction> &getCoefficients() const { return coefficients; } | ||
|
||
const std::vector<std::vector<SmallVector<Fraction>>> &getAffine() const { | ||
return affine; | ||
} | ||
|
||
// Arithmetic operations. | ||
QuasiPolynomial operator+(const QuasiPolynomial &x) const; | ||
QuasiPolynomial operator-(const QuasiPolynomial &x) const; | ||
QuasiPolynomial operator*(const QuasiPolynomial &x) const; | ||
QuasiPolynomial operator/(const Fraction x) const; | ||
|
||
// Removes terms which evaluate to zero from the expression. | ||
QuasiPolynomial simplify(); | ||
|
||
private: | ||
SmallVector<Fraction> coefficients; | ||
std::vector<std::vector<SmallVector<Fraction>>> affine; | ||
}; | ||
|
||
} // namespace presburger | ||
} // namespace mlir | ||
|
||
#endif // MLIR_ANALYSIS_PRESBURGER_QUASIPOLYNOMIAL_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
//===- GeneratingFunction.h - Generating Functions over Q^d -----*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// Definition of the GeneratingFunction class for Barvinok's algorithm, | ||
// which represents a function over Q^n, parameterized by d parameters. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef MLIR_ANALYSIS_PRESBURGER_GENERATINGFUNCTION_H | ||
#define MLIR_ANALYSIS_PRESBURGER_GENERATINGFUNCTION_H | ||
|
||
#include "mlir/Analysis/Presburger/Fraction.h" | ||
#include "mlir/Analysis/Presburger/Matrix.h" | ||
|
||
namespace mlir { | ||
namespace presburger { | ||
|
||
// A parametric point is a vector, each of whose elements | ||
// is an affine function of n parameters. Each row | ||
// in the matrix represents the affine function and | ||
// has n+1 elements. | ||
using ParamPoint = Matrix<Fraction>; | ||
|
||
// A point is simply a vector. | ||
using Point = SmallVector<Fraction>; | ||
|
||
// A class to describe the type of generating function | ||
// used to enumerate the integer points in a polytope. | ||
// Consists of a set of terms, where the ith term has | ||
// * a sign, ±1, stored in `signs[i]` | ||
// * a numerator, of the form x^{n}, | ||
// where n, stored in `numerators[i]`, | ||
// is a parametric point. | ||
// * a denominator, of the form (1 - x^{d1})...(1 - x^{dn}), | ||
// where each dj, stored in `denominators[i][j]`, | ||
// is a vector. | ||
// | ||
// Represents functions f_p : Q^n -> Q of the form | ||
// | ||
// f_p(x) = \sum_i s_i * (x^n_i(p)) / (\prod_j (1 - x^d_{ij}) | ||
// | ||
// where s_i is ±1, | ||
// n_i \in Q^d -> Q^n is an n-vector of affine functions on d parameters, and | ||
// g_{ij} \in Q^n are vectors. | ||
class GeneratingFunction { | ||
public: | ||
GeneratingFunction(unsigned numParam, SmallVector<int, 8> signs, | ||
std::vector<ParamPoint> nums, | ||
std::vector<std::vector<Point>> dens) | ||
: numParam(numParam), signs(signs), numerators(nums), denominators(dens) { | ||
for (const ParamPoint &term : numerators) | ||
assert(term.getNumColumns() == numParam + 1 && | ||
"dimensionality of numerator exponents does not match number of " | ||
"parameters!"); | ||
} | ||
|
||
unsigned getNumParams() { return numParam; } | ||
|
||
SmallVector<int> getSigns() { return signs; } | ||
|
||
std::vector<ParamPoint> getNumerators() { return numerators; } | ||
|
||
std::vector<std::vector<Point>> getDenominators() { return denominators; } | ||
|
||
GeneratingFunction operator+(const GeneratingFunction &gf) const { | ||
assert(numParam == gf.getNumParams() && | ||
"two generating functions with different numbers of parameters " | ||
"cannot be added!"); | ||
SmallVector<int> sumSigns = signs; | ||
sumSigns.append(gf.signs); | ||
|
||
std::vector<ParamPoint> sumNumerators = numerators; | ||
sumNumerators.insert(sumNumerators.end(), gf.numerators.begin(), | ||
gf.numerators.end()); | ||
|
||
std::vector<std::vector<Point>> sumDenominators = denominators; | ||
sumDenominators.insert(sumDenominators.end(), gf.denominators.begin(), | ||
gf.denominators.end()); | ||
return GeneratingFunction(sumSigns, sumNumerators, sumDenominators); | ||
} | ||
|
||
llvm::raw_ostream &print(llvm::raw_ostream &os) const { | ||
for (unsigned i = 0, e = signs.size(); i < e; i++) { | ||
if (signs[i] == 1) | ||
os << " + "; | ||
else | ||
os << " - "; | ||
Abhinav271828 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
os << "x^["; | ||
for (unsigned j = 0, e = numerators[i].size(); j < e - 1; j++) | ||
os << numerators[i][j] << ","; | ||
os << numerators[i].back() << "]/"; | ||
|
||
for (Point den : denominators[i]) { | ||
Abhinav271828 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
os << "(x^["; | ||
for (unsigned j = 0, e = den.size(); j < e - 1; j++) | ||
os << den[j] << ","; | ||
os << den[den.size() - 1] << "])"; | ||
} | ||
} | ||
return os; | ||
} | ||
|
||
private: | ||
unsigned numParam; | ||
SmallVector<int, 8> signs; | ||
std::vector<ParamPoint> numerators; | ||
std::vector<std::vector<Point>> denominators; | ||
}; | ||
|
||
} // namespace presburger | ||
} // namespace mlir | ||
|
||
#endif // MLIR_ANALYSIS_PRESBURGER_GENERATINGFUNCTION_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
//===- QuasiPolynomial.cpp - Quasipolynomial Class --------------*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "mlir/Analysis/Presburger/QuasiPolynomial.h" | ||
#include "mlir/Analysis/Presburger/Fraction.h" | ||
#include "mlir/Analysis/Presburger/IntegerRelation.h" | ||
#include "mlir/Analysis/Presburger/Matrix.h" | ||
#include "mlir/Analysis/Presburger/PresburgerSpace.h" | ||
#include "mlir/Analysis/Presburger/Utils.h" | ||
#include "mlir/Support/LogicalResult.h" | ||
#include <optional> | ||
|
||
using namespace mlir; | ||
using namespace presburger; | ||
|
||
QuasiPolynomial::QuasiPolynomial( | ||
unsigned numVars, SmallVector<Fraction> coeffs, | ||
std::vector<std::vector<SmallVector<Fraction>>> aff) | ||
: PresburgerSpace(/*numDomain=*/numVars, /*numRange=*/1, /*numSymbols=*/0, | ||
/*numLocals=*/0), | ||
coefficients(coeffs), affine(aff) { | ||
// For each term which involves at least one affine function, | ||
for (const std::vector<SmallVector<Fraction>> &term : affine) { | ||
if (term.size() == 0) | ||
continue; | ||
// the number of elements in each affine function is | ||
// one more than the number of symbols. | ||
for (const SmallVector<Fraction> &aff : term) { | ||
assert(aff.size() == getNumInputs() + 1 && | ||
"dimensionality of affine functions does not match number of " | ||
"symbols!"); | ||
} | ||
} | ||
} | ||
|
||
QuasiPolynomial QuasiPolynomial::operator+(const QuasiPolynomial &x) const { | ||
assert(getNumInputs() == x.getNumInputs() && | ||
"two quasi-polynomials with different numbers of symbols cannot " | ||
"be added!"); | ||
SmallVector<Fraction> sumCoeffs = coefficients; | ||
sumCoeffs.append(x.coefficients); | ||
std::vector<std::vector<SmallVector<Fraction>>> sumAff = affine; | ||
sumAff.insert(sumAff.end(), x.affine.begin(), x.affine.end()); | ||
return QuasiPolynomial(getNumInputs(), sumCoeffs, sumAff); | ||
} | ||
|
||
QuasiPolynomial QuasiPolynomial::operator-(const QuasiPolynomial &x) const { | ||
assert(getNumInputs() == x.getNumInputs() && | ||
"two quasi-polynomials with different numbers of symbols cannot " | ||
"be subtracted!"); | ||
QuasiPolynomial qp(getNumInputs(), x.coefficients, x.affine); | ||
for (Fraction &coeff : qp.coefficients) | ||
coeff = -coeff; | ||
return *this + qp; | ||
} | ||
|
||
QuasiPolynomial QuasiPolynomial::operator*(const QuasiPolynomial &x) const { | ||
assert(getNumInputs() == x.getNumInputs() && | ||
"two quasi-polynomials with different numbers of " | ||
"symbols cannot be multiplied!"); | ||
|
||
SmallVector<Fraction> coeffs; | ||
coeffs.reserve(coefficients.size() * x.coefficients.size()); | ||
for (const Fraction &coeff : coefficients) | ||
for (const Fraction &xcoeff : x.coefficients) | ||
coeffs.push_back(coeff * xcoeff); | ||
|
||
std::vector<SmallVector<Fraction>> product; | ||
std::vector<std::vector<SmallVector<Fraction>>> aff; | ||
aff.reserve(affine.size() * x.affine.size()); | ||
for (const std::vector<SmallVector<Fraction>> &term : affine) { | ||
Abhinav271828 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
for (const std::vector<SmallVector<Fraction>> &xterm : x.affine) { | ||
product.clear(); | ||
product.insert(product.end(), term.begin(), term.end()); | ||
product.insert(product.end(), xterm.begin(), xterm.end()); | ||
aff.push_back(product); | ||
} | ||
} | ||
|
||
return QuasiPolynomial(getNumInputs(), coeffs, aff); | ||
} | ||
|
||
QuasiPolynomial QuasiPolynomial::operator/(const Fraction x) const { | ||
assert(x != 0 && "division by zero!"); | ||
QuasiPolynomial qp(*this); | ||
for (Fraction &coeff : qp.coefficients) | ||
coeff /= x; | ||
return qp; | ||
} | ||
|
||
// Removes terms which evaluate to zero from the expression. | ||
QuasiPolynomial QuasiPolynomial::simplify() { | ||
SmallVector<Fraction> newCoeffs({}); | ||
std::vector<std::vector<SmallVector<Fraction>>> newAffine({}); | ||
for (unsigned i = 0, e = coefficients.size(); i < e; i++) { | ||
// A term is zero if its coefficient is zero, or | ||
if (coefficients[i] == Fraction(0, 1)) | ||
continue; | ||
bool product_is_zero = | ||
// if any of the affine functions in the product | ||
llvm::any_of(affine[i], [](const SmallVector<Fraction> &affine_ij) { | ||
// has all its coefficients as zero. | ||
return llvm::all_of(affine_ij, | ||
[](const Fraction &f) { return f == 0; }); | ||
}); | ||
if (product_is_zero) | ||
continue; | ||
newCoeffs.push_back(coefficients[i]); | ||
newAffine.push_back(affine[i]); | ||
} | ||
return QuasiPolynomial(getNumInputs(), newCoeffs, newAffine); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.