mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-02-20 18:27:20 +00:00
[MLIR][Presburger] Generating functions and quasi-polynomials for Barvinok's algorithm (#75702)
Define basic types and classes for Barvinok's algorithm, including polyhedra, generating functions and quasi-polynomials. The class definitions include methods for arithmetic manipulation, printing, logical relations, etc.
This commit is contained in:
parent
01bf29b9d0
commit
1022febd9d
71
mlir/include/mlir/Analysis/Presburger/QuasiPolynomial.h
Normal file
71
mlir/include/mlir/Analysis/Presburger/QuasiPolynomial.h
Normal file
@ -0,0 +1,71 @@
|
||||
//===- 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/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
|
@ -6,6 +6,7 @@ add_mlir_library(MLIRPresburger
|
||||
PresburgerRelation.cpp
|
||||
PresburgerSpace.cpp
|
||||
PWMAFunction.cpp
|
||||
QuasiPolynomial.cpp
|
||||
Simplex.cpp
|
||||
SlowMPInt.cpp
|
||||
Utils.cpp
|
||||
|
132
mlir/lib/Analysis/Presburger/GeneratingFunction.h
Normal file
132
mlir/lib/Analysis/Presburger/GeneratingFunction.h
Normal file
@ -0,0 +1,132 @@
|
||||
//===- 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 = FracMatrix;
|
||||
|
||||
// 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 (i == 0) {
|
||||
if (signs[i] == -1)
|
||||
os << "- ";
|
||||
} else {
|
||||
if (signs[i] == 1)
|
||||
os << " + ";
|
||||
else
|
||||
os << " - ";
|
||||
}
|
||||
|
||||
os << "x^[";
|
||||
unsigned r = numerators[i].getNumRows();
|
||||
for (unsigned j = 0; j < r - 1; j++) {
|
||||
os << "[";
|
||||
for (unsigned k = 0, c = numerators[i].getNumColumns(); k < c - 1; k++)
|
||||
os << numerators[i].at(j, k) << ",";
|
||||
os << numerators[i].getRow(j).back() << "],";
|
||||
}
|
||||
os << "[";
|
||||
for (unsigned k = 0, c = numerators[i].getNumColumns(); k < c - 1; k++)
|
||||
os << numerators[i].at(r - 1, k) << ",";
|
||||
os << numerators[i].getRow(r - 1).back() << "]]/";
|
||||
|
||||
for (const Point &den : denominators[i]) {
|
||||
os << "(x^[";
|
||||
for (unsigned j = 0, e = den.size(); j < e - 1; j++)
|
||||
os << den[j] << ",";
|
||||
os << den.back() << "])";
|
||||
}
|
||||
}
|
||||
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
|
113
mlir/lib/Analysis/Presburger/QuasiPolynomial.cpp
Normal file
113
mlir/lib/Analysis/Presburger/QuasiPolynomial.cpp
Normal file
@ -0,0 +1,113 @@
|
||||
//===- 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/PresburgerSpace.h"
|
||||
#include "mlir/Analysis/Presburger/Utils.h"
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
@ -11,6 +11,7 @@ add_mlir_unittest(MLIRPresburgerTests
|
||||
PresburgerRelationTest.cpp
|
||||
PresburgerSpaceTest.cpp
|
||||
PWMAFunctionTest.cpp
|
||||
QuasiPolynomialTest.cpp
|
||||
SimplexTest.cpp
|
||||
UtilsTest.cpp
|
||||
)
|
||||
|
140
mlir/unittests/Analysis/Presburger/QuasiPolynomialTest.cpp
Normal file
140
mlir/unittests/Analysis/Presburger/QuasiPolynomialTest.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
//===- MatrixTest.cpp - Tests for QuasiPolynomial -------------------------===//
|
||||
//
|
||||
// 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 "./Utils.h"
|
||||
#include "mlir/Analysis/Presburger/Fraction.h"
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace mlir;
|
||||
using namespace presburger;
|
||||
|
||||
// Test the arithmetic operations on QuasiPolynomials;
|
||||
// addition, subtraction, multiplication, and division
|
||||
// by a constant.
|
||||
// Two QPs of 3 parameters each were generated randomly
|
||||
// and their sum, difference, and product computed by hand.
|
||||
TEST(QuasiPolynomialTest, arithmetic) {
|
||||
QuasiPolynomial qp1(
|
||||
3, {Fraction(1, 3), Fraction(1, 1), Fraction(1, 2)},
|
||||
{{{Fraction(1, 1), Fraction(-1, 2), Fraction(4, 5), Fraction(0, 1)},
|
||||
{Fraction(2, 3), Fraction(3, 4), Fraction(-1, 1), Fraction(5, 7)}},
|
||||
{{Fraction(1, 2), Fraction(1, 1), Fraction(4, 5), Fraction(1, 1)}},
|
||||
{{Fraction(-3, 2), Fraction(1, 1), Fraction(5, 6), Fraction(7, 5)},
|
||||
{Fraction(1, 4), Fraction(2, 1), Fraction(6, 5), Fraction(-9, 8)},
|
||||
{Fraction(3, 2), Fraction(2, 5), Fraction(-7, 4), Fraction(0, 1)}}});
|
||||
QuasiPolynomial qp2(
|
||||
3, {Fraction(1, 1), Fraction(2, 1)},
|
||||
{{{Fraction(1, 2), Fraction(0, 1), Fraction(-1, 3), Fraction(5, 3)},
|
||||
{Fraction(2, 1), Fraction(5, 4), Fraction(9, 7), Fraction(-1, 5)}},
|
||||
{{Fraction(1, 3), Fraction(-2, 3), Fraction(1, 1), Fraction(0, 1)}}});
|
||||
|
||||
QuasiPolynomial sum = qp1 + qp2;
|
||||
EXPECT_EQ_REPR_QUASIPOLYNOMIAL(
|
||||
sum,
|
||||
QuasiPolynomial(
|
||||
3,
|
||||
{Fraction(1, 3), Fraction(1, 1), Fraction(1, 2), Fraction(1, 1),
|
||||
Fraction(2, 1)},
|
||||
{{{Fraction(1, 1), Fraction(-1, 2), Fraction(4, 5), Fraction(0, 1)},
|
||||
{Fraction(2, 3), Fraction(3, 4), Fraction(-1, 1), Fraction(5, 7)}},
|
||||
{{Fraction(1, 2), Fraction(1, 1), Fraction(4, 5), Fraction(1, 1)}},
|
||||
{{Fraction(-3, 2), Fraction(1, 1), Fraction(5, 6), Fraction(7, 5)},
|
||||
{Fraction(1, 4), Fraction(2, 1), Fraction(6, 5), Fraction(-9, 8)},
|
||||
{Fraction(3, 2), Fraction(2, 5), Fraction(-7, 4), Fraction(0, 1)}},
|
||||
{{Fraction(1, 2), Fraction(0, 1), Fraction(-1, 3), Fraction(5, 3)},
|
||||
{Fraction(2, 1), Fraction(5, 4), Fraction(9, 7), Fraction(-1, 5)}},
|
||||
{{Fraction(1, 3), Fraction(-2, 3), Fraction(1, 1),
|
||||
Fraction(0, 1)}}}));
|
||||
|
||||
QuasiPolynomial diff = qp1 - qp2;
|
||||
EXPECT_EQ_REPR_QUASIPOLYNOMIAL(
|
||||
diff,
|
||||
QuasiPolynomial(
|
||||
3,
|
||||
{Fraction(1, 3), Fraction(1, 1), Fraction(1, 2), Fraction(-1, 1),
|
||||
Fraction(-2, 1)},
|
||||
{{{Fraction(1, 1), Fraction(-1, 2), Fraction(4, 5), Fraction(0, 1)},
|
||||
{Fraction(2, 3), Fraction(3, 4), Fraction(-1, 1), Fraction(5, 7)}},
|
||||
{{Fraction(1, 2), Fraction(1, 1), Fraction(4, 5), Fraction(1, 1)}},
|
||||
{{Fraction(-3, 2), Fraction(1, 1), Fraction(5, 6), Fraction(7, 5)},
|
||||
{Fraction(1, 4), Fraction(2, 1), Fraction(6, 5), Fraction(-9, 8)},
|
||||
{Fraction(3, 2), Fraction(2, 5), Fraction(-7, 4), Fraction(0, 1)}},
|
||||
{{Fraction(1, 2), Fraction(0, 1), Fraction(-1, 3), Fraction(5, 3)},
|
||||
{Fraction(2, 1), Fraction(5, 4), Fraction(9, 7), Fraction(-1, 5)}},
|
||||
{{Fraction(1, 3), Fraction(-2, 3), Fraction(1, 1),
|
||||
Fraction(0, 1)}}}));
|
||||
|
||||
QuasiPolynomial prod = qp1 * qp2;
|
||||
EXPECT_EQ_REPR_QUASIPOLYNOMIAL(
|
||||
prod,
|
||||
QuasiPolynomial(
|
||||
3,
|
||||
{Fraction(1, 3), Fraction(2, 3), Fraction(1, 1), Fraction(2, 1),
|
||||
Fraction(1, 2), Fraction(1, 1)},
|
||||
{{{Fraction(1, 1), Fraction(-1, 2), Fraction(4, 5), Fraction(0, 1)},
|
||||
{Fraction(2, 3), Fraction(3, 4), Fraction(-1, 1), Fraction(5, 7)},
|
||||
{Fraction(1, 2), Fraction(0, 1), Fraction(-1, 3), Fraction(5, 3)},
|
||||
{Fraction(2, 1), Fraction(5, 4), Fraction(9, 7), Fraction(-1, 5)}},
|
||||
{{Fraction(1, 1), Fraction(-1, 2), Fraction(4, 5), Fraction(0, 1)},
|
||||
{Fraction(2, 3), Fraction(3, 4), Fraction(-1, 1), Fraction(5, 7)},
|
||||
{Fraction(1, 3), Fraction(-2, 3), Fraction(1, 1), Fraction(0, 1)}},
|
||||
{{Fraction(1, 2), Fraction(1, 1), Fraction(4, 5), Fraction(1, 1)},
|
||||
{Fraction(1, 2), Fraction(0, 1), Fraction(-1, 3), Fraction(5, 3)},
|
||||
{Fraction(2, 1), Fraction(5, 4), Fraction(9, 7), Fraction(-1, 5)}},
|
||||
{{Fraction(1, 2), Fraction(1, 1), Fraction(4, 5), Fraction(1, 1)},
|
||||
{Fraction(1, 3), Fraction(-2, 3), Fraction(1, 1), Fraction(0, 1)}},
|
||||
{{Fraction(-3, 2), Fraction(1, 1), Fraction(5, 6), Fraction(7, 5)},
|
||||
{Fraction(1, 4), Fraction(2, 1), Fraction(6, 5), Fraction(-9, 8)},
|
||||
{Fraction(3, 2), Fraction(2, 5), Fraction(-7, 4), Fraction(0, 1)},
|
||||
{Fraction(1, 2), Fraction(0, 1), Fraction(-1, 3), Fraction(5, 3)},
|
||||
{Fraction(2, 1), Fraction(5, 4), Fraction(9, 7), Fraction(-1, 5)}},
|
||||
{{Fraction(-3, 2), Fraction(1, 1), Fraction(5, 6), Fraction(7, 5)},
|
||||
{Fraction(1, 4), Fraction(2, 1), Fraction(6, 5), Fraction(-9, 8)},
|
||||
{Fraction(3, 2), Fraction(2, 5), Fraction(-7, 4), Fraction(0, 1)},
|
||||
{Fraction(1, 3), Fraction(-2, 3), Fraction(1, 1),
|
||||
Fraction(0, 1)}}}));
|
||||
|
||||
QuasiPolynomial quot = qp1 / 2;
|
||||
EXPECT_EQ_REPR_QUASIPOLYNOMIAL(
|
||||
quot,
|
||||
QuasiPolynomial(
|
||||
3, {Fraction(1, 6), Fraction(1, 2), Fraction(1, 4)},
|
||||
{{{Fraction(1, 1), Fraction(-1, 2), Fraction(4, 5), Fraction(0, 1)},
|
||||
{Fraction(2, 3), Fraction(3, 4), Fraction(-1, 1), Fraction(5, 7)}},
|
||||
{{Fraction(1, 2), Fraction(1, 1), Fraction(4, 5), Fraction(1, 1)}},
|
||||
{{Fraction(-3, 2), Fraction(1, 1), Fraction(5, 6), Fraction(7, 5)},
|
||||
{Fraction(1, 4), Fraction(2, 1), Fraction(6, 5), Fraction(-9, 8)},
|
||||
{Fraction(3, 2), Fraction(2, 5), Fraction(-7, 4),
|
||||
Fraction(0, 1)}}}));
|
||||
}
|
||||
|
||||
// Test the simplify() operation on QPs, which removes terms that
|
||||
// are identically zero. A random QP was generated and terms were
|
||||
// changed to account for each condition in simplify() –
|
||||
// the term coefficient being zero, or all the coefficients in some
|
||||
// affine term in the product being zero.
|
||||
TEST(QuasiPolynomialTest, simplify) {
|
||||
QuasiPolynomial qp(2,
|
||||
{Fraction(2, 3), Fraction(0, 1), Fraction(1, 1),
|
||||
Fraction(1, 2), Fraction(0, 1)},
|
||||
{{{Fraction(1, 1), Fraction(3, 4), Fraction(5, 3)},
|
||||
{Fraction(2, 1), Fraction(0, 1), Fraction(0, 1)}},
|
||||
{{Fraction(1, 3), Fraction(8, 5), Fraction(2, 5)}},
|
||||
{{Fraction(2, 7), Fraction(9, 5), Fraction(0, 1)},
|
||||
{Fraction(0, 1), Fraction(0, 1), Fraction(0, 1)}},
|
||||
{{Fraction(1, 1), Fraction(4, 5), Fraction(6, 5)}},
|
||||
{{Fraction(1, 3), Fraction(4, 3), Fraction(7, 8)}}});
|
||||
EXPECT_EQ_REPR_QUASIPOLYNOMIAL(
|
||||
qp.simplify(),
|
||||
QuasiPolynomial(2, {Fraction(2, 3), Fraction(1, 2)},
|
||||
{{{Fraction(1, 1), Fraction(3, 4), Fraction(5, 3)},
|
||||
{Fraction(2, 1), Fraction(0, 1), Fraction(0, 1)}},
|
||||
{{Fraction(1, 1), Fraction(4, 5), Fraction(6, 5)}}}));
|
||||
}
|
@ -17,6 +17,7 @@
|
||||
#include "mlir/Analysis/Presburger/Matrix.h"
|
||||
#include "mlir/Analysis/Presburger/PWMAFunction.h"
|
||||
#include "mlir/Analysis/Presburger/PresburgerRelation.h"
|
||||
#include "mlir/Analysis/Presburger/QuasiPolynomial.h"
|
||||
#include "mlir/Analysis/Presburger/Simplex.h"
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "mlir/Support/LLVM.h"
|
||||
@ -71,6 +72,28 @@ inline void EXPECT_EQ_FRAC_MATRIX(FracMatrix a, FracMatrix b) {
|
||||
EXPECT_EQ(a(row, col), b(row, col));
|
||||
}
|
||||
|
||||
// Check the coefficients (in order) of two quasipolynomials.
|
||||
// Note that this is not a true equality check.
|
||||
inline void EXPECT_EQ_REPR_QUASIPOLYNOMIAL(QuasiPolynomial a, QuasiPolynomial b) {
|
||||
EXPECT_EQ(a.getNumInputs(), b.getNumInputs());
|
||||
|
||||
SmallVector<Fraction> aCoeffs = a.getCoefficients(),
|
||||
bCoeffs = b.getCoefficients();
|
||||
EXPECT_EQ(aCoeffs.size(), bCoeffs.size());
|
||||
for (unsigned i = 0, e = aCoeffs.size(); i < e; i++)
|
||||
EXPECT_EQ(aCoeffs[i], bCoeffs[i]);
|
||||
|
||||
std::vector<std::vector<SmallVector<Fraction>>> aAff = a.getAffine(),
|
||||
bAff = b.getAffine();
|
||||
EXPECT_EQ(aAff.size(), bAff.size());
|
||||
for (unsigned i = 0, e = aAff.size(); i < e; i++) {
|
||||
EXPECT_EQ(aAff[i].size(), bAff[i].size());
|
||||
for (unsigned j = 0, f = aAff[i].size(); j < f; j++)
|
||||
for (unsigned k = 0, g = a.getNumInputs(); k <= g; k++)
|
||||
EXPECT_EQ(aAff[i][j][k], bAff[i][j][k]);
|
||||
}
|
||||
}
|
||||
|
||||
/// lhs and rhs represent non-negative integers or positive infinity. The
|
||||
/// infinity case corresponds to when the Optional is empty.
|
||||
inline bool infinityOrUInt64LE(std::optional<MPInt> lhs,
|
||||
|
Loading…
x
Reference in New Issue
Block a user