14c8dbb68SAbhinav271828 #include "mlir/Analysis/Presburger/Barvinok.h"
24c8dbb68SAbhinav271828 #include "./Utils.h"
3*562790f3SAbhinav271828 #include "Parser.h"
44c8dbb68SAbhinav271828 #include <gmock/gmock.h>
54c8dbb68SAbhinav271828 #include <gtest/gtest.h>
64c8dbb68SAbhinav271828
74c8dbb68SAbhinav271828 using namespace mlir;
84c8dbb68SAbhinav271828 using namespace presburger;
94c8dbb68SAbhinav271828 using namespace mlir::presburger::detail;
104c8dbb68SAbhinav271828
114c8dbb68SAbhinav271828 /// The following are 3 randomly generated vectors with 4
124c8dbb68SAbhinav271828 /// entries each and define a cone's H-representation
134c8dbb68SAbhinav271828 /// using these numbers. We check that the dual contains
144c8dbb68SAbhinav271828 /// the same numbers.
154c8dbb68SAbhinav271828 /// We do the same in the reverse case.
TEST(BarvinokTest,getDual)164c8dbb68SAbhinav271828 TEST(BarvinokTest, getDual) {
174c8dbb68SAbhinav271828 ConeH cone1 = defineHRep(4);
184c8dbb68SAbhinav271828 cone1.addInequality({1, 2, 3, 4, 0});
194c8dbb68SAbhinav271828 cone1.addInequality({3, 4, 2, 5, 0});
204c8dbb68SAbhinav271828 cone1.addInequality({6, 2, 6, 1, 0});
214c8dbb68SAbhinav271828
224c8dbb68SAbhinav271828 ConeV dual1 = getDual(cone1);
234c8dbb68SAbhinav271828
244c8dbb68SAbhinav271828 EXPECT_EQ_INT_MATRIX(
254c8dbb68SAbhinav271828 dual1, makeIntMatrix(3, 4, {{1, 2, 3, 4}, {3, 4, 2, 5}, {6, 2, 6, 1}}));
264c8dbb68SAbhinav271828
274c8dbb68SAbhinav271828 ConeV cone2 = makeIntMatrix(3, 4, {{3, 6, 1, 5}, {3, 1, 7, 2}, {9, 3, 2, 7}});
284c8dbb68SAbhinav271828
294c8dbb68SAbhinav271828 ConeH dual2 = getDual(cone2);
304c8dbb68SAbhinav271828
314c8dbb68SAbhinav271828 ConeH expected = defineHRep(4);
324c8dbb68SAbhinav271828 expected.addInequality({3, 6, 1, 5, 0});
334c8dbb68SAbhinav271828 expected.addInequality({3, 1, 7, 2, 0});
344c8dbb68SAbhinav271828 expected.addInequality({9, 3, 2, 7, 0});
354c8dbb68SAbhinav271828
364c8dbb68SAbhinav271828 EXPECT_TRUE(dual2.isEqual(expected));
374c8dbb68SAbhinav271828 }
384c8dbb68SAbhinav271828
394c8dbb68SAbhinav271828 /// We randomly generate a nxn matrix to use as a cone
404c8dbb68SAbhinav271828 /// with n inequalities in n variables and check for
414c8dbb68SAbhinav271828 /// the determinant being equal to the index.
TEST(BarvinokTest,getIndex)424c8dbb68SAbhinav271828 TEST(BarvinokTest, getIndex) {
434c8dbb68SAbhinav271828 ConeV cone = makeIntMatrix(3, 3, {{4, 2, 1}, {5, 2, 7}, {4, 1, 6}});
444c8dbb68SAbhinav271828 EXPECT_EQ(getIndex(cone), cone.determinant());
454c8dbb68SAbhinav271828
464c8dbb68SAbhinav271828 cone = makeIntMatrix(
474c8dbb68SAbhinav271828 4, 4, {{4, 2, 5, 1}, {4, 1, 3, 6}, {8, 2, 5, 6}, {5, 2, 5, 7}});
484c8dbb68SAbhinav271828 EXPECT_EQ(getIndex(cone), cone.determinant());
494c8dbb68SAbhinav271828 }
502dde029dSAbhinav271828
512dde029dSAbhinav271828 // The following cones and vertices are randomly generated
522dde029dSAbhinav271828 // (s.t. the cones are unimodular) and the generating functions
532dde029dSAbhinav271828 // are computed. We check that the results contain the correct
542dde029dSAbhinav271828 // matrices.
TEST(BarvinokTest,unimodularConeGeneratingFunction)552dde029dSAbhinav271828 TEST(BarvinokTest, unimodularConeGeneratingFunction) {
562dde029dSAbhinav271828 ConeH cone = defineHRep(2);
572dde029dSAbhinav271828 cone.addInequality({0, -1, 0});
582dde029dSAbhinav271828 cone.addInequality({-1, -2, 0});
592dde029dSAbhinav271828
602dde029dSAbhinav271828 ParamPoint vertex =
612dde029dSAbhinav271828 makeFracMatrix(2, 3, {{2, 2, 0}, {-1, -Fraction(1, 2), 1}});
622dde029dSAbhinav271828
63*562790f3SAbhinav271828 GeneratingFunction gf =
64*562790f3SAbhinav271828 computeUnimodularConeGeneratingFunction(vertex, 1, cone);
652dde029dSAbhinav271828
662dde029dSAbhinav271828 EXPECT_EQ_REPR_GENERATINGFUNCTION(
672dde029dSAbhinav271828 gf, GeneratingFunction(
682dde029dSAbhinav271828 2, {1},
692dde029dSAbhinav271828 {makeFracMatrix(3, 2, {{-1, 0}, {-Fraction(1, 2), 1}, {1, 2}})},
702dde029dSAbhinav271828 {{{2, -1}, {-1, 0}}}));
712dde029dSAbhinav271828
722dde029dSAbhinav271828 cone = defineHRep(3);
732dde029dSAbhinav271828 cone.addInequality({7, 1, 6, 0});
742dde029dSAbhinav271828 cone.addInequality({9, 1, 7, 0});
752dde029dSAbhinav271828 cone.addInequality({8, -1, 1, 0});
762dde029dSAbhinav271828
772dde029dSAbhinav271828 vertex = makeFracMatrix(3, 2, {{5, 2}, {6, 2}, {7, 1}});
782dde029dSAbhinav271828
79*562790f3SAbhinav271828 gf = computeUnimodularConeGeneratingFunction(vertex, 1, cone);
802dde029dSAbhinav271828
812dde029dSAbhinav271828 EXPECT_EQ_REPR_GENERATINGFUNCTION(
822dde029dSAbhinav271828 gf,
832dde029dSAbhinav271828 GeneratingFunction(
842dde029dSAbhinav271828 1, {1}, {makeFracMatrix(2, 3, {{-83, -100, -41}, {-22, -27, -15}})},
852dde029dSAbhinav271828 {{{8, 47, -17}, {-7, -41, 15}, {1, 5, -2}}}));
862dde029dSAbhinav271828 }
87850f713eSAbhinav271828
88850f713eSAbhinav271828 // The following vectors are randomly generated.
89850f713eSAbhinav271828 // We then check that the output of the function has non-zero
90850f713eSAbhinav271828 // dot product with all non-null vectors.
TEST(BarvinokTest,getNonOrthogonalVector)91850f713eSAbhinav271828 TEST(BarvinokTest, getNonOrthogonalVector) {
92850f713eSAbhinav271828 std::vector<Point> vectors = {Point({1, 2, 3, 4}), Point({-1, 0, 1, 1}),
93850f713eSAbhinav271828 Point({2, 7, 0, 0}), Point({0, 0, 0, 0})};
94850f713eSAbhinav271828 Point nonOrth = getNonOrthogonalVector(vectors);
95850f713eSAbhinav271828
96850f713eSAbhinav271828 for (unsigned i = 0; i < 3; i++)
97850f713eSAbhinav271828 EXPECT_NE(dotProduct(nonOrth, vectors[i]), 0);
98850f713eSAbhinav271828
99850f713eSAbhinav271828 vectors = {Point({0, 1, 3}), Point({-2, -1, 1}), Point({6, 3, 0}),
100850f713eSAbhinav271828 Point({0, 0, -3}), Point({5, 0, -1})};
101850f713eSAbhinav271828 nonOrth = getNonOrthogonalVector(vectors);
102850f713eSAbhinav271828
103850f713eSAbhinav271828 for (const Point &vector : vectors)
104850f713eSAbhinav271828 EXPECT_NE(dotProduct(nonOrth, vector), 0);
105850f713eSAbhinav271828 }
106850f713eSAbhinav271828
107850f713eSAbhinav271828 // The following polynomials are randomly generated and the
108850f713eSAbhinav271828 // coefficients are computed by hand.
109850f713eSAbhinav271828 // Although the function allows the coefficients of the numerator
110850f713eSAbhinav271828 // to be arbitrary quasipolynomials, we stick to constants for simplicity,
111850f713eSAbhinav271828 // as the relevant arithmetic operations on quasipolynomials
112850f713eSAbhinav271828 // are tested separately.
TEST(BarvinokTest,getCoefficientInRationalFunction)113850f713eSAbhinav271828 TEST(BarvinokTest, getCoefficientInRationalFunction) {
114850f713eSAbhinav271828 std::vector<QuasiPolynomial> numerator = {
115850f713eSAbhinav271828 QuasiPolynomial(0, 2), QuasiPolynomial(0, 3), QuasiPolynomial(0, 5)};
116850f713eSAbhinav271828 std::vector<Fraction> denominator = {Fraction(1), Fraction(0), Fraction(4),
117850f713eSAbhinav271828 Fraction(3)};
118850f713eSAbhinav271828 QuasiPolynomial coeff =
119850f713eSAbhinav271828 getCoefficientInRationalFunction(1, numerator, denominator);
120850f713eSAbhinav271828 EXPECT_EQ(coeff.getConstantTerm(), 3);
121850f713eSAbhinav271828
122850f713eSAbhinav271828 numerator = {QuasiPolynomial(0, -1), QuasiPolynomial(0, 4),
123850f713eSAbhinav271828 QuasiPolynomial(0, -2), QuasiPolynomial(0, 5),
124850f713eSAbhinav271828 QuasiPolynomial(0, 6)};
125850f713eSAbhinav271828 denominator = {Fraction(8), Fraction(4), Fraction(0), Fraction(-2)};
126850f713eSAbhinav271828 coeff = getCoefficientInRationalFunction(3, numerator, denominator);
127850f713eSAbhinav271828 EXPECT_EQ(coeff.getConstantTerm(), Fraction(55, 64));
128850f713eSAbhinav271828 }
12968a5261dSAbhinav271828
TEST(BarvinokTest,computeNumTermsCone)130*562790f3SAbhinav271828 TEST(BarvinokTest, computeNumTermsCone) {
13168a5261dSAbhinav271828 // The following test is taken from
13268a5261dSAbhinav271828 // Verdoolaege, Sven, et al. "Counting integer points in parametric
13368a5261dSAbhinav271828 // polytopes using Barvinok's rational functions." Algorithmica 48 (2007):
13468a5261dSAbhinav271828 // 37-66.
13568a5261dSAbhinav271828 // It represents a right-angled triangle with right angle at the origin,
13668a5261dSAbhinav271828 // with height and base lengths (p/2).
13768a5261dSAbhinav271828 GeneratingFunction gf(
13868a5261dSAbhinav271828 1, {1, 1, 1},
13968a5261dSAbhinav271828 {makeFracMatrix(2, 2, {{0, Fraction(1, 2)}, {0, 0}}),
14068a5261dSAbhinav271828 makeFracMatrix(2, 2, {{0, Fraction(1, 2)}, {0, 0}}),
14168a5261dSAbhinav271828 makeFracMatrix(2, 2, {{0, 0}, {0, 0}})},
14268a5261dSAbhinav271828 {{{-1, 1}, {-1, 0}}, {{1, -1}, {0, -1}}, {{1, 0}, {0, 1}}});
14368a5261dSAbhinav271828
14468a5261dSAbhinav271828 QuasiPolynomial numPoints = computeNumTerms(gf).collectTerms();
14568a5261dSAbhinav271828
14668a5261dSAbhinav271828 // First, we make sure that all the affine functions are of the form ⌊p/2⌋.
14768a5261dSAbhinav271828 for (const std::vector<SmallVector<Fraction>> &term : numPoints.getAffine()) {
14868a5261dSAbhinav271828 for (const SmallVector<Fraction> &aff : term) {
14968a5261dSAbhinav271828 EXPECT_EQ(aff.size(), 2u);
15068a5261dSAbhinav271828 EXPECT_EQ(aff[0], Fraction(1, 2));
15168a5261dSAbhinav271828 EXPECT_EQ(aff[1], Fraction(0, 1));
15268a5261dSAbhinav271828 }
15368a5261dSAbhinav271828 }
15468a5261dSAbhinav271828
15568a5261dSAbhinav271828 // Now, we can gather the like terms because we know there's only
15668a5261dSAbhinav271828 // either ⌊p/2⌋^2, ⌊p/2⌋, or constants.
15768a5261dSAbhinav271828 // The total coefficient of ⌊p/2⌋^2 is the sum of coefficients of all
15868a5261dSAbhinav271828 // terms with 2 affine functions, and
15968a5261dSAbhinav271828 // the coefficient of total ⌊p/2⌋ is the sum of coefficients of all
16068a5261dSAbhinav271828 // terms with 1 affine function,
16168a5261dSAbhinav271828 Fraction pSquaredCoeff = 0, pCoeff = 0, constantTerm = 0;
16268a5261dSAbhinav271828 SmallVector<Fraction> coefficients = numPoints.getCoefficients();
16368a5261dSAbhinav271828 for (unsigned i = 0; i < numPoints.getCoefficients().size(); i++)
16468a5261dSAbhinav271828 if (numPoints.getAffine()[i].size() == 2)
16568a5261dSAbhinav271828 pSquaredCoeff = pSquaredCoeff + coefficients[i];
16668a5261dSAbhinav271828 else if (numPoints.getAffine()[i].size() == 1)
16768a5261dSAbhinav271828 pCoeff = pCoeff + coefficients[i];
16868a5261dSAbhinav271828
16968a5261dSAbhinav271828 // We expect the answer to be (1/2)⌊p/2⌋^2 + (3/2)⌊p/2⌋ + 1.
17068a5261dSAbhinav271828 EXPECT_EQ(pSquaredCoeff, Fraction(1, 2));
17168a5261dSAbhinav271828 EXPECT_EQ(pCoeff, Fraction(3, 2));
17268a5261dSAbhinav271828 EXPECT_EQ(numPoints.getConstantTerm(), Fraction(1, 1));
17368a5261dSAbhinav271828
17468a5261dSAbhinav271828 // The following generating function corresponds to a cuboid
17568a5261dSAbhinav271828 // with length M (x-axis), width N (y-axis), and height P (z-axis).
17668a5261dSAbhinav271828 // There are eight terms.
17768a5261dSAbhinav271828 gf = GeneratingFunction(
17868a5261dSAbhinav271828 3, {1, 1, 1, 1, 1, 1, 1, 1},
17968a5261dSAbhinav271828 {makeFracMatrix(4, 3, {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}),
18068a5261dSAbhinav271828 makeFracMatrix(4, 3, {{1, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}}),
18168a5261dSAbhinav271828 makeFracMatrix(4, 3, {{0, 0, 0}, {0, 1, 0}, {0, 0, 0}, {0, 0, 0}}),
18268a5261dSAbhinav271828 makeFracMatrix(4, 3, {{0, 0, 0}, {0, 0, 0}, {0, 0, 1}, {0, 0, 0}}),
18368a5261dSAbhinav271828 makeFracMatrix(4, 3, {{1, 0, 0}, {0, 1, 0}, {0, 0, 0}, {0, 0, 0}}),
18468a5261dSAbhinav271828 makeFracMatrix(4, 3, {{1, 0, 0}, {0, 0, 0}, {0, 0, 1}, {0, 0, 0}}),
18568a5261dSAbhinav271828 makeFracMatrix(4, 3, {{0, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, 0}}),
18668a5261dSAbhinav271828 makeFracMatrix(4, 3, {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, 0}})},
18768a5261dSAbhinav271828 {{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
18868a5261dSAbhinav271828 {{-1, 0, 0}, {0, 1, 0}, {0, 0, 1}},
18968a5261dSAbhinav271828 {{1, 0, 0}, {0, -1, 0}, {0, 0, 1}},
19068a5261dSAbhinav271828 {{1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
19168a5261dSAbhinav271828 {{-1, 0, 0}, {0, -1, 0}, {0, 0, 1}},
19268a5261dSAbhinav271828 {{-1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
19368a5261dSAbhinav271828 {{1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
19468a5261dSAbhinav271828 {{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}}});
19568a5261dSAbhinav271828
19668a5261dSAbhinav271828 numPoints = computeNumTerms(gf);
19768a5261dSAbhinav271828 numPoints = numPoints.collectTerms().simplify();
19868a5261dSAbhinav271828
19968a5261dSAbhinav271828 // First, we make sure all the affine functions are either
20068a5261dSAbhinav271828 // M, N, P, or 1.
20168a5261dSAbhinav271828 for (const std::vector<SmallVector<Fraction>> &term : numPoints.getAffine()) {
20268a5261dSAbhinav271828 for (const SmallVector<Fraction> &aff : term) {
20368a5261dSAbhinav271828 // First, ensure that the coefficients are all nonnegative integers.
20468a5261dSAbhinav271828 for (const Fraction &c : aff) {
20568a5261dSAbhinav271828 EXPECT_TRUE(c >= 0);
20668a5261dSAbhinav271828 EXPECT_EQ(c, c.getAsInteger());
20768a5261dSAbhinav271828 }
20868a5261dSAbhinav271828 // Now, if the coefficients add up to 1, we can be sure the term is
20968a5261dSAbhinav271828 // either M, N, P, or 1.
21068a5261dSAbhinav271828 EXPECT_EQ(aff[0] + aff[1] + aff[2] + aff[3], 1);
21168a5261dSAbhinav271828 }
21268a5261dSAbhinav271828 }
21368a5261dSAbhinav271828
21468a5261dSAbhinav271828 // We store the coefficients of M, N and P in this array.
21568a5261dSAbhinav271828 Fraction count[2][2][2];
21668a5261dSAbhinav271828 coefficients = numPoints.getCoefficients();
21768a5261dSAbhinav271828 for (unsigned i = 0, e = coefficients.size(); i < e; i++) {
21868a5261dSAbhinav271828 unsigned mIndex = 0, nIndex = 0, pIndex = 0;
21968a5261dSAbhinav271828 for (const SmallVector<Fraction> &aff : numPoints.getAffine()[i]) {
22068a5261dSAbhinav271828 if (aff[0] == 1)
22168a5261dSAbhinav271828 mIndex = 1;
22268a5261dSAbhinav271828 if (aff[1] == 1)
22368a5261dSAbhinav271828 nIndex = 1;
22468a5261dSAbhinav271828 if (aff[2] == 1)
22568a5261dSAbhinav271828 pIndex = 1;
22668a5261dSAbhinav271828 EXPECT_EQ(aff[3], 0);
22768a5261dSAbhinav271828 }
22868a5261dSAbhinav271828 count[mIndex][nIndex][pIndex] += coefficients[i];
22968a5261dSAbhinav271828 }
23068a5261dSAbhinav271828
23168a5261dSAbhinav271828 // We expect the answer to be
23268a5261dSAbhinav271828 // (⌊M⌋ + 1)(⌊N⌋ + 1)(⌊P⌋ + 1) =
23368a5261dSAbhinav271828 // ⌊M⌋⌊N⌋⌊P⌋ + ⌊M⌋⌊N⌋ + ⌊N⌋⌊P⌋ + ⌊M⌋⌊P⌋ + ⌊M⌋ + ⌊N⌋ + ⌊P⌋ + 1.
23468a5261dSAbhinav271828 for (unsigned i = 0; i < 2; i++)
23568a5261dSAbhinav271828 for (unsigned j = 0; j < 2; j++)
23668a5261dSAbhinav271828 for (unsigned k = 0; k < 2; k++)
23768a5261dSAbhinav271828 EXPECT_EQ(count[i][j][k], 1);
23868a5261dSAbhinav271828 }
239*562790f3SAbhinav271828
240*562790f3SAbhinav271828 /// We define some simple polyhedra with unimodular tangent cones and verify
241*562790f3SAbhinav271828 /// that the returned generating functions correspond to those calculated by
242*562790f3SAbhinav271828 /// hand.
TEST(BarvinokTest,computeNumTermsPolytope)243*562790f3SAbhinav271828 TEST(BarvinokTest, computeNumTermsPolytope) {
244*562790f3SAbhinav271828 // A cube of side 1.
245*562790f3SAbhinav271828 PolyhedronH poly =
246*562790f3SAbhinav271828 parseRelationFromSet("(x, y, z) : (x >= 0, y >= 0, z >= 0, -x + 1 >= 0, "
247*562790f3SAbhinav271828 "-y + 1 >= 0, -z + 1 >= 0)",
248*562790f3SAbhinav271828 0);
249*562790f3SAbhinav271828
250*562790f3SAbhinav271828 std::vector<std::pair<PresburgerSet, GeneratingFunction>> count =
251*562790f3SAbhinav271828 computePolytopeGeneratingFunction(poly);
252*562790f3SAbhinav271828 // There is only one chamber, as it is non-parametric.
253*562790f3SAbhinav271828 EXPECT_EQ(count.size(), 9u);
254*562790f3SAbhinav271828
255*562790f3SAbhinav271828 GeneratingFunction gf = count[0].second;
256*562790f3SAbhinav271828 EXPECT_EQ_REPR_GENERATINGFUNCTION(
257*562790f3SAbhinav271828 gf,
258*562790f3SAbhinav271828 GeneratingFunction(
259*562790f3SAbhinav271828 0, {1, 1, 1, 1, 1, 1, 1, 1},
260*562790f3SAbhinav271828 {makeFracMatrix(1, 3, {{1, 1, 1}}), makeFracMatrix(1, 3, {{0, 1, 1}}),
261*562790f3SAbhinav271828 makeFracMatrix(1, 3, {{0, 1, 1}}), makeFracMatrix(1, 3, {{0, 0, 1}}),
262*562790f3SAbhinav271828 makeFracMatrix(1, 3, {{0, 1, 1}}), makeFracMatrix(1, 3, {{0, 0, 1}}),
263*562790f3SAbhinav271828 makeFracMatrix(1, 3, {{0, 0, 1}}),
264*562790f3SAbhinav271828 makeFracMatrix(1, 3, {{0, 0, 0}})},
265*562790f3SAbhinav271828 {{{-1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
266*562790f3SAbhinav271828 {{0, 0, 1}, {-1, 0, 0}, {0, -1, 0}},
267*562790f3SAbhinav271828 {{0, 1, 0}, {-1, 0, 0}, {0, 0, -1}},
268*562790f3SAbhinav271828 {{0, 1, 0}, {0, 0, 1}, {-1, 0, 0}},
269*562790f3SAbhinav271828 {{1, 0, 0}, {0, -1, 0}, {0, 0, -1}},
270*562790f3SAbhinav271828 {{1, 0, 0}, {0, 0, 1}, {0, -1, 0}},
271*562790f3SAbhinav271828 {{1, 0, 0}, {0, 1, 0}, {0, 0, -1}},
272*562790f3SAbhinav271828 {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}}));
273*562790f3SAbhinav271828
274*562790f3SAbhinav271828 // A right-angled triangle with side p.
275*562790f3SAbhinav271828 poly =
276*562790f3SAbhinav271828 parseRelationFromSet("(x, y)[N] : (x >= 0, y >= 0, -x - y + N >= 0)", 0);
277*562790f3SAbhinav271828
278*562790f3SAbhinav271828 count = computePolytopeGeneratingFunction(poly);
279*562790f3SAbhinav271828 // There is only one chamber: p ≥ 0
280*562790f3SAbhinav271828 EXPECT_EQ(count.size(), 4u);
281*562790f3SAbhinav271828
282*562790f3SAbhinav271828 gf = count[0].second;
283*562790f3SAbhinav271828 EXPECT_EQ_REPR_GENERATINGFUNCTION(
284*562790f3SAbhinav271828 gf, GeneratingFunction(
285*562790f3SAbhinav271828 1, {1, 1, 1},
286*562790f3SAbhinav271828 {makeFracMatrix(2, 2, {{0, 1}, {0, 0}}),
287*562790f3SAbhinav271828 makeFracMatrix(2, 2, {{0, 1}, {0, 0}}),
288*562790f3SAbhinav271828 makeFracMatrix(2, 2, {{0, 0}, {0, 0}})},
289*562790f3SAbhinav271828 {{{-1, 1}, {-1, 0}}, {{1, -1}, {0, -1}}, {{1, 0}, {0, 1}}}));
290*562790f3SAbhinav271828
291*562790f3SAbhinav271828 // Cartesian product of a cube with side M and a right triangle with side N.
292*562790f3SAbhinav271828 poly = parseRelationFromSet(
293*562790f3SAbhinav271828 "(x, y, z, w, a)[M, N] : (x >= 0, y >= 0, z >= 0, -x + M >= 0, -y + M >= "
294*562790f3SAbhinav271828 "0, -z + M >= 0, w >= 0, a >= 0, -w - a + N >= 0)",
295*562790f3SAbhinav271828 0);
296*562790f3SAbhinav271828
297*562790f3SAbhinav271828 count = computePolytopeGeneratingFunction(poly);
298*562790f3SAbhinav271828
299*562790f3SAbhinav271828 EXPECT_EQ(count.size(), 25u);
300*562790f3SAbhinav271828
301*562790f3SAbhinav271828 gf = count[0].second;
302*562790f3SAbhinav271828 EXPECT_EQ(gf.getNumerators().size(), 24u);
303*562790f3SAbhinav271828 }
304