#include "mlir/Analysis/Presburger/Barvinok.h"
#include "./Utils.h"
#include "Parser.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using namespace mlir;
using namespace presburger;
using namespace mlir::presburger::detail;
TEST(BarvinokTest, getDual) {
ConeH cone1 = defineHRep(4);
cone1.addInequality({1, 2, 3, 4, 0});
cone1.addInequality({3, 4, 2, 5, 0});
cone1.addInequality({6, 2, 6, 1, 0});
ConeV dual1 = getDual(cone1);
EXPECT_EQ_INT_MATRIX(
dual1, makeIntMatrix(3, 4, {{1, 2, 3, 4}, {3, 4, 2, 5}, {6, 2, 6, 1}}));
ConeV cone2 = makeIntMatrix(3, 4, {{3, 6, 1, 5}, {3, 1, 7, 2}, {9, 3, 2, 7}});
ConeH dual2 = getDual(cone2);
ConeH expected = defineHRep(4);
expected.addInequality({3, 6, 1, 5, 0});
expected.addInequality({3, 1, 7, 2, 0});
expected.addInequality({9, 3, 2, 7, 0});
EXPECT_TRUE(dual2.isEqual(expected));
}
TEST(BarvinokTest, getIndex) {
ConeV cone = makeIntMatrix(3, 3, {{4, 2, 1}, {5, 2, 7}, {4, 1, 6}});
EXPECT_EQ(getIndex(cone), cone.determinant());
cone = makeIntMatrix(
4, 4, {{4, 2, 5, 1}, {4, 1, 3, 6}, {8, 2, 5, 6}, {5, 2, 5, 7}});
EXPECT_EQ(getIndex(cone), cone.determinant());
}
TEST(BarvinokTest, unimodularConeGeneratingFunction) {
ConeH cone = defineHRep(2);
cone.addInequality({0, -1, 0});
cone.addInequality({-1, -2, 0});
ParamPoint vertex =
makeFracMatrix(2, 3, {{2, 2, 0}, {-1, -Fraction(1, 2), 1}});
GeneratingFunction gf =
computeUnimodularConeGeneratingFunction(vertex, 1, cone);
EXPECT_EQ_REPR_GENERATINGFUNCTION(
gf, GeneratingFunction(
2, {1},
{makeFracMatrix(3, 2, {{-1, 0}, {-Fraction(1, 2), 1}, {1, 2}})},
{{{2, -1}, {-1, 0}}}));
cone = defineHRep(3);
cone.addInequality({7, 1, 6, 0});
cone.addInequality({9, 1, 7, 0});
cone.addInequality({8, -1, 1, 0});
vertex = makeFracMatrix(3, 2, {{5, 2}, {6, 2}, {7, 1}});
gf = computeUnimodularConeGeneratingFunction(vertex, 1, cone);
EXPECT_EQ_REPR_GENERATINGFUNCTION(
gf,
GeneratingFunction(
1, {1}, {makeFracMatrix(2, 3, {{-83, -100, -41}, {-22, -27, -15}})},
{{{8, 47, -17}, {-7, -41, 15}, {1, 5, -2}}}));
}
TEST(BarvinokTest, getNonOrthogonalVector) {
std::vector<Point> vectors = {Point({1, 2, 3, 4}), Point({-1, 0, 1, 1}),
Point({2, 7, 0, 0}), Point({0, 0, 0, 0})};
Point nonOrth = getNonOrthogonalVector(vectors);
for (unsigned i = 0; i < 3; i++)
EXPECT_NE(dotProduct(nonOrth, vectors[i]), 0);
vectors = {Point({0, 1, 3}), Point({-2, -1, 1}), Point({6, 3, 0}),
Point({0, 0, -3}), Point({5, 0, -1})};
nonOrth = getNonOrthogonalVector(vectors);
for (const Point &vector : vectors)
EXPECT_NE(dotProduct(nonOrth, vector), 0);
}
TEST(BarvinokTest, getCoefficientInRationalFunction) {
std::vector<QuasiPolynomial> numerator = {
QuasiPolynomial(0, 2), QuasiPolynomial(0, 3), QuasiPolynomial(0, 5)};
std::vector<Fraction> denominator = {Fraction(1), Fraction(0), Fraction(4),
Fraction(3)};
QuasiPolynomial coeff =
getCoefficientInRationalFunction(1, numerator, denominator);
EXPECT_EQ(coeff.getConstantTerm(), 3);
numerator = {QuasiPolynomial(0, -1), QuasiPolynomial(0, 4),
QuasiPolynomial(0, -2), QuasiPolynomial(0, 5),
QuasiPolynomial(0, 6)};
denominator = {Fraction(8), Fraction(4), Fraction(0), Fraction(-2)};
coeff = getCoefficientInRationalFunction(3, numerator, denominator);
EXPECT_EQ(coeff.getConstantTerm(), Fraction(55, 64));
}
TEST(BarvinokTest, computeNumTermsCone) {
GeneratingFunction gf(
1, {1, 1, 1},
{makeFracMatrix(2, 2, {{0, Fraction(1, 2)}, {0, 0}}),
makeFracMatrix(2, 2, {{0, Fraction(1, 2)}, {0, 0}}),
makeFracMatrix(2, 2, {{0, 0}, {0, 0}})},
{{{-1, 1}, {-1, 0}}, {{1, -1}, {0, -1}}, {{1, 0}, {0, 1}}});
QuasiPolynomial numPoints = computeNumTerms(gf).collectTerms();
for (const std::vector<SmallVector<Fraction>> &term : numPoints.getAffine()) {
for (const SmallVector<Fraction> &aff : term) {
EXPECT_EQ(aff.size(), 2u);
EXPECT_EQ(aff[0], Fraction(1, 2));
EXPECT_EQ(aff[1], Fraction(0, 1));
}
}
Fraction pSquaredCoeff = 0, pCoeff = 0, constantTerm = 0;
SmallVector<Fraction> coefficients = numPoints.getCoefficients();
for (unsigned i = 0; i < numPoints.getCoefficients().size(); i++)
if (numPoints.getAffine()[i].size() == 2)
pSquaredCoeff = pSquaredCoeff + coefficients[i];
else if (numPoints.getAffine()[i].size() == 1)
pCoeff = pCoeff + coefficients[i];
EXPECT_EQ(pSquaredCoeff, Fraction(1, 2));
EXPECT_EQ(pCoeff, Fraction(3, 2));
EXPECT_EQ(numPoints.getConstantTerm(), Fraction(1, 1));
gf = GeneratingFunction(
3, {1, 1, 1, 1, 1, 1, 1, 1},
{makeFracMatrix(4, 3, {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}),
makeFracMatrix(4, 3, {{1, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}),
makeFracMatrix(4, 3, {{0, 0, 0}, {0, 1, 0}, {0, 0, 0}, {0, 0, 0}}),
makeFracMatrix(4, 3, {{0, 0, 0}, {0, 0, 0}, {0, 0, 1}, {0, 0, 0}}),
makeFracMatrix(4, 3, {{1, 0, 0}, {0, 1, 0}, {0, 0, 0}, {0, 0, 0}}),
makeFracMatrix(4, 3, {{1, 0, 0}, {0, 0, 0}, {0, 0, 1}, {0, 0, 0}}),
makeFracMatrix(4, 3, {{0, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, 0}}),
makeFracMatrix(4, 3, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, 0}})},
{{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
{{-1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
{{1, 0, 0}, {0, -1, 0}, {0, 0, 1}},
{{1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
{{-1, 0, 0}, {0, -1, 0}, {0, 0, 1}},
{{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
{{1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}});
numPoints = computeNumTerms(gf);
numPoints = numPoints.collectTerms().simplify();
for (const std::vector<SmallVector<Fraction>> &term : numPoints.getAffine()) {
for (const SmallVector<Fraction> &aff : term) {
for (const Fraction &c : aff) {
EXPECT_TRUE(c >= 0);
EXPECT_EQ(c, c.getAsInteger());
}
EXPECT_EQ(aff[0] + aff[1] + aff[2] + aff[3], 1);
}
}
Fraction count[2][2][2];
coefficients = numPoints.getCoefficients();
for (unsigned i = 0, e = coefficients.size(); i < e; i++) {
unsigned mIndex = 0, nIndex = 0, pIndex = 0;
for (const SmallVector<Fraction> &aff : numPoints.getAffine()[i]) {
if (aff[0] == 1)
mIndex = 1;
if (aff[1] == 1)
nIndex = 1;
if (aff[2] == 1)
pIndex = 1;
EXPECT_EQ(aff[3], 0);
}
count[mIndex][nIndex][pIndex] += coefficients[i];
}
for (unsigned i = 0; i < 2; i++)
for (unsigned j = 0; j < 2; j++)
for (unsigned k = 0; k < 2; k++)
EXPECT_EQ(count[i][j][k], 1);
}
TEST(BarvinokTest, computeNumTermsPolytope) {
PolyhedronH poly =
parseRelationFromSet("(x, y, z) : (x >= 0, y >= 0, z >= 0, -x + 1 >= 0, "
"-y + 1 >= 0, -z + 1 >= 0)",
0);
std::vector<std::pair<PresburgerSet, GeneratingFunction>> count =
computePolytopeGeneratingFunction(poly);
EXPECT_EQ(count.size(), 9u);
GeneratingFunction gf = count[0].second;
EXPECT_EQ_REPR_GENERATINGFUNCTION(
gf,
GeneratingFunction(
0, {1, 1, 1, 1, 1, 1, 1, 1},
{makeFracMatrix(1, 3, {{1, 1, 1}}), makeFracMatrix(1, 3, {{0, 1, 1}}),
makeFracMatrix(1, 3, {{0, 1, 1}}), makeFracMatrix(1, 3, {{0, 0, 1}}),
makeFracMatrix(1, 3, {{0, 1, 1}}), makeFracMatrix(1, 3, {{0, 0, 1}}),
makeFracMatrix(1, 3, {{0, 0, 1}}),
makeFracMatrix(1, 3, {{0, 0, 0}})},
{{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
{{0, 0, 1}, {-1, 0, 0}, {0, -1, 0}},
{{0, 1, 0}, {-1, 0, 0}, {0, 0, -1}},
{{0, 1, 0}, {0, 0, 1}, {-1, 0, 0}},
{{1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
{{1, 0, 0}, {0, 0, 1}, {0, -1, 0}},
{{1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}}));
poly =
parseRelationFromSet("(x, y)[N] : (x >= 0, y >= 0, -x - y + N >= 0)", 0);
count = computePolytopeGeneratingFunction(poly);
EXPECT_EQ(count.size(), 4u);
gf = count[0].second;
EXPECT_EQ_REPR_GENERATINGFUNCTION(
gf, GeneratingFunction(
1, {1, 1, 1},
{makeFracMatrix(2, 2, {{0, 1}, {0, 0}}),
makeFracMatrix(2, 2, {{0, 1}, {0, 0}}),
makeFracMatrix(2, 2, {{0, 0}, {0, 0}})},
{{{-1, 1}, {-1, 0}}, {{1, -1}, {0, -1}}, {{1, 0}, {0, 1}}}));
poly = parseRelationFromSet(
"(x, y, z, w, a)[M, N] : (x >= 0, y >= 0, z >= 0, -x + M >= 0, -y + M >= "
"0, -z + M >= 0, w >= 0, a >= 0, -w - a + N >= 0)",
0);
count = computePolytopeGeneratingFunction(poly);
EXPECT_EQ(count.size(), 25u);
gf = count[0].second;
EXPECT_EQ(gf.getNumerators().size(), 24u);
}