16472546fSArjun P //===- Utils.h - Utils for Presburger Tests ---------------------*- C++ -*-===//
26472546fSArjun P //
36472546fSArjun P // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46472546fSArjun P // See https://llvm.org/LICENSE.txt for license information.
56472546fSArjun P // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66472546fSArjun P //
76472546fSArjun P //===----------------------------------------------------------------------===//
86472546fSArjun P //
96472546fSArjun P // This file defines helper functions for Presburger unittests.
106472546fSArjun P //
116472546fSArjun P //===----------------------------------------------------------------------===//
126472546fSArjun P
136472546fSArjun P #ifndef MLIR_UNITTESTS_ANALYSIS_PRESBURGER_UTILS_H
146472546fSArjun P #define MLIR_UNITTESTS_ANALYSIS_PRESBURGER_UTILS_H
156472546fSArjun P
16bd0dc357SAbhinav271828 #include "mlir/Analysis/Presburger/GeneratingFunction.h"
17bb901355SGroverkss #include "mlir/Analysis/Presburger/IntegerRelation.h"
18f08fe1f1SAbhinav271828 #include "mlir/Analysis/Presburger/Matrix.h"
191022febdSAbhinav271828 #include "mlir/Analysis/Presburger/QuasiPolynomial.h"
206472546fSArjun P
216472546fSArjun P #include <gtest/gtest.h>
22a1fe1f5fSKazu Hirata #include <optional>
236472546fSArjun P
246472546fSArjun P namespace mlir {
250c1f6865SGroverkss namespace presburger {
26*1a0e67d7SRamkumar Ramachandra using llvm::dynamicAPIntFromInt64;
270c1f6865SGroverkss
makeIntMatrix(unsigned numRow,unsigned numColumns,ArrayRef<SmallVector<int,8>> matrix)28c1b99746SAbhinav271828 inline IntMatrix makeIntMatrix(unsigned numRow, unsigned numColumns,
29c1b99746SAbhinav271828 ArrayRef<SmallVector<int, 8>> matrix) {
30c1b99746SAbhinav271828 IntMatrix results(numRow, numColumns);
31c1b99746SAbhinav271828 assert(matrix.size() == numRow);
32c1b99746SAbhinav271828 for (unsigned i = 0; i < numRow; ++i) {
33c1b99746SAbhinav271828 assert(matrix[i].size() == numColumns &&
34c1b99746SAbhinav271828 "Output expression has incorrect dimensionality!");
35c1b99746SAbhinav271828 for (unsigned j = 0; j < numColumns; ++j)
36*1a0e67d7SRamkumar Ramachandra results(i, j) = DynamicAPInt(matrix[i][j]);
37c1b99746SAbhinav271828 }
38c1b99746SAbhinav271828 return results;
39c1b99746SAbhinav271828 }
40c1b99746SAbhinav271828
makeFracMatrix(unsigned numRow,unsigned numColumns,ArrayRef<SmallVector<Fraction,8>> matrix)41f08fe1f1SAbhinav271828 inline FracMatrix makeFracMatrix(unsigned numRow, unsigned numColumns,
42c1b99746SAbhinav271828 ArrayRef<SmallVector<Fraction, 8>> matrix) {
43f08fe1f1SAbhinav271828 FracMatrix results(numRow, numColumns);
440239976bSArjun P assert(matrix.size() == numRow);
450239976bSArjun P for (unsigned i = 0; i < numRow; ++i) {
460239976bSArjun P assert(matrix[i].size() == numColumns &&
470239976bSArjun P "Output expression has incorrect dimensionality!");
480239976bSArjun P for (unsigned j = 0; j < numColumns; ++j)
490239976bSArjun P results(i, j) = matrix[i][j];
500239976bSArjun P }
510239976bSArjun P return results;
520239976bSArjun P }
530239976bSArjun P
EXPECT_EQ_INT_MATRIX(IntMatrix a,IntMatrix b)54f08fe1f1SAbhinav271828 inline void EXPECT_EQ_INT_MATRIX(IntMatrix a, IntMatrix b) {
55f08fe1f1SAbhinav271828 EXPECT_EQ(a.getNumRows(), b.getNumRows());
56f08fe1f1SAbhinav271828 EXPECT_EQ(a.getNumColumns(), b.getNumColumns());
57f08fe1f1SAbhinav271828
58f08fe1f1SAbhinav271828 for (unsigned row = 0; row < a.getNumRows(); row++)
59f08fe1f1SAbhinav271828 for (unsigned col = 0; col < a.getNumColumns(); col++)
60f08fe1f1SAbhinav271828 EXPECT_EQ(a(row, col), b(row, col));
61f08fe1f1SAbhinav271828 }
62f08fe1f1SAbhinav271828
EXPECT_EQ_FRAC_MATRIX(FracMatrix a,FracMatrix b)63f08fe1f1SAbhinav271828 inline void EXPECT_EQ_FRAC_MATRIX(FracMatrix a, FracMatrix b) {
64f08fe1f1SAbhinav271828 EXPECT_EQ(a.getNumRows(), b.getNumRows());
65f08fe1f1SAbhinav271828 EXPECT_EQ(a.getNumColumns(), b.getNumColumns());
66f08fe1f1SAbhinav271828
67f08fe1f1SAbhinav271828 for (unsigned row = 0; row < a.getNumRows(); row++)
68f08fe1f1SAbhinav271828 for (unsigned col = 0; col < a.getNumColumns(); col++)
69f08fe1f1SAbhinav271828 EXPECT_EQ(a(row, col), b(row, col));
70f08fe1f1SAbhinav271828 }
71f08fe1f1SAbhinav271828
72bd0dc357SAbhinav271828 // Check the coefficients (in order) of two generating functions.
73bd0dc357SAbhinav271828 // Note that this is not a true equality check.
EXPECT_EQ_REPR_GENERATINGFUNCTION(detail::GeneratingFunction a,detail::GeneratingFunction b)74bd0dc357SAbhinav271828 inline void EXPECT_EQ_REPR_GENERATINGFUNCTION(detail::GeneratingFunction a,
75bd0dc357SAbhinav271828 detail::GeneratingFunction b) {
76bd0dc357SAbhinav271828 EXPECT_EQ(a.getNumParams(), b.getNumParams());
77bd0dc357SAbhinav271828
78bd0dc357SAbhinav271828 SmallVector<int> aSigns = a.getSigns();
79bd0dc357SAbhinav271828 SmallVector<int> bSigns = b.getSigns();
80bd0dc357SAbhinav271828 EXPECT_EQ(aSigns.size(), bSigns.size());
81bd0dc357SAbhinav271828 for (unsigned i = 0, e = aSigns.size(); i < e; i++)
82bd0dc357SAbhinav271828 EXPECT_EQ(aSigns[i], bSigns[i]);
83bd0dc357SAbhinav271828
84bd0dc357SAbhinav271828 std::vector<detail::ParamPoint> aNums = a.getNumerators();
85bd0dc357SAbhinav271828 std::vector<detail::ParamPoint> bNums = b.getNumerators();
86bd0dc357SAbhinav271828 EXPECT_EQ(aNums.size(), bNums.size());
87bd0dc357SAbhinav271828 for (unsigned i = 0, e = aNums.size(); i < e; i++)
88bd0dc357SAbhinav271828 EXPECT_EQ_FRAC_MATRIX(aNums[i], bNums[i]);
89bd0dc357SAbhinav271828
90bd0dc357SAbhinav271828 std::vector<std::vector<detail::Point>> aDens = a.getDenominators();
91bd0dc357SAbhinav271828 std::vector<std::vector<detail::Point>> bDens = b.getDenominators();
92bd0dc357SAbhinav271828 EXPECT_EQ(aDens.size(), bDens.size());
93bd0dc357SAbhinav271828 for (unsigned i = 0, e = aDens.size(); i < e; i++) {
94bd0dc357SAbhinav271828 EXPECT_EQ(aDens[i].size(), bDens[i].size());
95bd0dc357SAbhinav271828 for (unsigned j = 0, f = aDens[i].size(); j < f; j++) {
96bd0dc357SAbhinav271828 EXPECT_EQ(aDens[i][j].size(), bDens[i][j].size());
97bd0dc357SAbhinav271828 for (unsigned k = 0, g = aDens[i][j].size(); k < g; k++) {
98bd0dc357SAbhinav271828 EXPECT_EQ(aDens[i][j][k], bDens[i][j][k]);
99bd0dc357SAbhinav271828 }
100bd0dc357SAbhinav271828 }
101bd0dc357SAbhinav271828 }
102bd0dc357SAbhinav271828 }
103bd0dc357SAbhinav271828
1041022febdSAbhinav271828 // Check the coefficients (in order) of two quasipolynomials.
1051022febdSAbhinav271828 // Note that this is not a true equality check.
EXPECT_EQ_REPR_QUASIPOLYNOMIAL(QuasiPolynomial a,QuasiPolynomial b)106bd0dc357SAbhinav271828 inline void EXPECT_EQ_REPR_QUASIPOLYNOMIAL(QuasiPolynomial a,
107bd0dc357SAbhinav271828 QuasiPolynomial b) {
1081022febdSAbhinav271828 EXPECT_EQ(a.getNumInputs(), b.getNumInputs());
1091022febdSAbhinav271828
1101022febdSAbhinav271828 SmallVector<Fraction> aCoeffs = a.getCoefficients(),
1111022febdSAbhinav271828 bCoeffs = b.getCoefficients();
1121022febdSAbhinav271828 EXPECT_EQ(aCoeffs.size(), bCoeffs.size());
1131022febdSAbhinav271828 for (unsigned i = 0, e = aCoeffs.size(); i < e; i++)
1141022febdSAbhinav271828 EXPECT_EQ(aCoeffs[i], bCoeffs[i]);
1151022febdSAbhinav271828
1161022febdSAbhinav271828 std::vector<std::vector<SmallVector<Fraction>>> aAff = a.getAffine(),
1171022febdSAbhinav271828 bAff = b.getAffine();
1181022febdSAbhinav271828 EXPECT_EQ(aAff.size(), bAff.size());
1191022febdSAbhinav271828 for (unsigned i = 0, e = aAff.size(); i < e; i++) {
1201022febdSAbhinav271828 EXPECT_EQ(aAff[i].size(), bAff[i].size());
1211022febdSAbhinav271828 for (unsigned j = 0, f = aAff[i].size(); j < f; j++)
1221022febdSAbhinav271828 for (unsigned k = 0, g = a.getNumInputs(); k <= g; k++)
1231022febdSAbhinav271828 EXPECT_EQ(aAff[i][j][k], bAff[i][j][k]);
1241022febdSAbhinav271828 }
1251022febdSAbhinav271828 }
1261022febdSAbhinav271828
1271096fcffSArjun P /// lhs and rhs represent non-negative integers or positive infinity. The
1281096fcffSArjun P /// infinity case corresponds to when the Optional is empty.
infinityOrUInt64LE(std::optional<DynamicAPInt> lhs,std::optional<DynamicAPInt> rhs)129*1a0e67d7SRamkumar Ramachandra inline bool infinityOrUInt64LE(std::optional<DynamicAPInt> lhs,
130*1a0e67d7SRamkumar Ramachandra std::optional<DynamicAPInt> rhs) {
1311096fcffSArjun P // No constraint.
1321096fcffSArjun P if (!rhs)
1331096fcffSArjun P return true;
1341096fcffSArjun P // Finite rhs provided so lhs has to be finite too.
1351096fcffSArjun P if (!lhs)
1361096fcffSArjun P return false;
1371096fcffSArjun P return *lhs <= *rhs;
1381096fcffSArjun P }
1391096fcffSArjun P
1401096fcffSArjun P /// Expect that the computed volume is a valid overapproximation of
1411096fcffSArjun P /// the true volume `trueVolume`, while also being at least as good an
1421096fcffSArjun P /// approximation as `resultBound`.
expectComputedVolumeIsValidOverapprox(const std::optional<DynamicAPInt> & computedVolume,const std::optional<DynamicAPInt> & trueVolume,const std::optional<DynamicAPInt> & resultBound)1430a81ace0SKazu Hirata inline void expectComputedVolumeIsValidOverapprox(
144*1a0e67d7SRamkumar Ramachandra const std::optional<DynamicAPInt> &computedVolume,
145*1a0e67d7SRamkumar Ramachandra const std::optional<DynamicAPInt> &trueVolume,
146*1a0e67d7SRamkumar Ramachandra const std::optional<DynamicAPInt> &resultBound) {
1471096fcffSArjun P assert(infinityOrUInt64LE(trueVolume, resultBound) &&
1481096fcffSArjun P "can't expect result to be less than the true volume");
1491096fcffSArjun P EXPECT_TRUE(infinityOrUInt64LE(trueVolume, computedVolume));
1501096fcffSArjun P EXPECT_TRUE(infinityOrUInt64LE(computedVolume, resultBound));
1511096fcffSArjun P }
1520c1f6865SGroverkss
expectComputedVolumeIsValidOverapprox(const std::optional<DynamicAPInt> & computedVolume,std::optional<int64_t> trueVolume,std::optional<int64_t> resultBound)1530a81ace0SKazu Hirata inline void expectComputedVolumeIsValidOverapprox(
154*1a0e67d7SRamkumar Ramachandra const std::optional<DynamicAPInt> &computedVolume,
1550a81ace0SKazu Hirata std::optional<int64_t> trueVolume, std::optional<int64_t> resultBound) {
15610041de9SKazu Hirata expectComputedVolumeIsValidOverapprox(
157*1a0e67d7SRamkumar Ramachandra computedVolume,
158*1a0e67d7SRamkumar Ramachandra llvm::transformOptional(trueVolume, dynamicAPIntFromInt64),
159*1a0e67d7SRamkumar Ramachandra llvm::transformOptional(resultBound, dynamicAPIntFromInt64));
1606d6f6c4dSArjun P }
1616d6f6c4dSArjun P
1620c1f6865SGroverkss } // namespace presburger
1636472546fSArjun P } // namespace mlir
1646472546fSArjun P
1656472546fSArjun P #endif // MLIR_UNITTESTS_ANALYSIS_PRESBURGER_UTILS_H
166