xref: /llvm-project/mlir/unittests/Analysis/Presburger/SimplexTest.cpp (revision 1a0e67d73023e7ad9e7e79f66afb43a6f2561d04)
110a898b3SArjun P //===- SimplexTest.cpp - Tests for Simplex --------------------------------===//
210a898b3SArjun P //
310a898b3SArjun P // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
410a898b3SArjun P // See https://llvm.org/LICENSE.txt for license information.
510a898b3SArjun P // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610a898b3SArjun P //
710a898b3SArjun P //===----------------------------------------------------------------------===//
810a898b3SArjun P 
98c867f78SGroverkss #include "Parser.h"
108c867f78SGroverkss #include "Utils.h"
116472546fSArjun P 
1210a898b3SArjun P #include "mlir/Analysis/Presburger/Simplex.h"
136472546fSArjun P #include "mlir/IR/MLIRContext.h"
1410a898b3SArjun P 
1510a898b3SArjun P #include <gmock/gmock.h>
1610a898b3SArjun P #include <gtest/gtest.h>
17a1fe1f5fSKazu Hirata #include <optional>
1810a898b3SArjun P 
190c1f6865SGroverkss using namespace mlir;
200c1f6865SGroverkss using namespace presburger;
2110a898b3SArjun P 
226d6f6c4dSArjun P /// Convenience functions to pass literals to Simplex.
addInequality(SimplexBase & simplex,ArrayRef<int64_t> coeffs)236d6f6c4dSArjun P void addInequality(SimplexBase &simplex, ArrayRef<int64_t> coeffs) {
24*1a0e67d7SRamkumar Ramachandra   simplex.addInequality(getDynamicAPIntVec(coeffs));
256d6f6c4dSArjun P }
addEquality(SimplexBase & simplex,ArrayRef<int64_t> coeffs)266d6f6c4dSArjun P void addEquality(SimplexBase &simplex, ArrayRef<int64_t> coeffs) {
27*1a0e67d7SRamkumar Ramachandra   simplex.addEquality(getDynamicAPIntVec(coeffs));
286d6f6c4dSArjun P }
isRedundantInequality(Simplex & simplex,ArrayRef<int64_t> coeffs)296d6f6c4dSArjun P bool isRedundantInequality(Simplex &simplex, ArrayRef<int64_t> coeffs) {
30*1a0e67d7SRamkumar Ramachandra   return simplex.isRedundantInequality(getDynamicAPIntVec(coeffs));
316d6f6c4dSArjun P }
isRedundantInequality(LexSimplex & simplex,ArrayRef<int64_t> coeffs)326d6f6c4dSArjun P bool isRedundantInequality(LexSimplex &simplex, ArrayRef<int64_t> coeffs) {
33*1a0e67d7SRamkumar Ramachandra   return simplex.isRedundantInequality(getDynamicAPIntVec(coeffs));
346d6f6c4dSArjun P }
isRedundantEquality(Simplex & simplex,ArrayRef<int64_t> coeffs)356d6f6c4dSArjun P bool isRedundantEquality(Simplex &simplex, ArrayRef<int64_t> coeffs) {
36*1a0e67d7SRamkumar Ramachandra   return simplex.isRedundantEquality(getDynamicAPIntVec(coeffs));
376d6f6c4dSArjun P }
isSeparateInequality(LexSimplex & simplex,ArrayRef<int64_t> coeffs)386d6f6c4dSArjun P bool isSeparateInequality(LexSimplex &simplex, ArrayRef<int64_t> coeffs) {
39*1a0e67d7SRamkumar Ramachandra   return simplex.isSeparateInequality(getDynamicAPIntVec(coeffs));
406d6f6c4dSArjun P }
416d6f6c4dSArjun P 
findIneqType(Simplex & simplex,ArrayRef<int64_t> coeffs)426d6f6c4dSArjun P Simplex::IneqType findIneqType(Simplex &simplex, ArrayRef<int64_t> coeffs) {
43*1a0e67d7SRamkumar Ramachandra   return simplex.findIneqType(getDynamicAPIntVec(coeffs));
446d6f6c4dSArjun P }
456d6f6c4dSArjun P 
4610a898b3SArjun P /// Take a snapshot, add constraints making the set empty, and rollback.
47ad34ce94SArjun P /// The set should not be empty after rolling back. We add additional
48ad34ce94SArjun P /// constraints after the set is already empty and roll back the addition
49ad34ce94SArjun P /// of these. The set should be marked non-empty only once we rollback
50ad34ce94SArjun P /// past the addition of the first constraint that made it empty.
TEST(SimplexTest,emptyRollback)5110a898b3SArjun P TEST(SimplexTest, emptyRollback) {
5210a898b3SArjun P   Simplex simplex(2);
5310a898b3SArjun P   // (u - v) >= 0
546d6f6c4dSArjun P   addInequality(simplex, {1, -1, 0});
55ad34ce94SArjun P   ASSERT_FALSE(simplex.isEmpty());
5610a898b3SArjun P 
5710a898b3SArjun P   unsigned snapshot = simplex.getSnapshot();
5810a898b3SArjun P   // (u - v) <= -1
596d6f6c4dSArjun P   addInequality(simplex, {-1, 1, -1});
60ad34ce94SArjun P   ASSERT_TRUE(simplex.isEmpty());
61ad34ce94SArjun P 
62ad34ce94SArjun P   unsigned snapshot2 = simplex.getSnapshot();
63ad34ce94SArjun P   // (u - v) <= -3
646d6f6c4dSArjun P   addInequality(simplex, {-1, 1, -3});
65ad34ce94SArjun P   ASSERT_TRUE(simplex.isEmpty());
66ad34ce94SArjun P 
67ad34ce94SArjun P   simplex.rollback(snapshot2);
68ad34ce94SArjun P   ASSERT_TRUE(simplex.isEmpty());
69ad34ce94SArjun P 
7010a898b3SArjun P   simplex.rollback(snapshot);
71ad34ce94SArjun P   ASSERT_FALSE(simplex.isEmpty());
7210a898b3SArjun P }
7310a898b3SArjun P 
7410a898b3SArjun P /// Check that the set gets marked as empty when we add contradictory
7510a898b3SArjun P /// constraints.
TEST(SimplexTest,addEquality_separate)7610a898b3SArjun P TEST(SimplexTest, addEquality_separate) {
7710a898b3SArjun P   Simplex simplex(1);
786d6f6c4dSArjun P   addInequality(simplex, {1, -1}); // x >= 1.
7910a898b3SArjun P   ASSERT_FALSE(simplex.isEmpty());
806d6f6c4dSArjun P   addEquality(simplex, {1, 0}); // x == 0.
8110a898b3SArjun P   EXPECT_TRUE(simplex.isEmpty());
8210a898b3SArjun P }
8310a898b3SArjun P 
expectInequalityMakesSetEmpty(Simplex & simplex,ArrayRef<int64_t> coeffs,bool expect)8410a898b3SArjun P void expectInequalityMakesSetEmpty(Simplex &simplex, ArrayRef<int64_t> coeffs,
8510a898b3SArjun P                                    bool expect) {
8610a898b3SArjun P   ASSERT_FALSE(simplex.isEmpty());
8710a898b3SArjun P   unsigned snapshot = simplex.getSnapshot();
886d6f6c4dSArjun P   addInequality(simplex, coeffs);
8910a898b3SArjun P   EXPECT_EQ(simplex.isEmpty(), expect);
9010a898b3SArjun P   simplex.rollback(snapshot);
9110a898b3SArjun P }
9210a898b3SArjun P 
TEST(SimplexTest,addInequality_rollback)9310a898b3SArjun P TEST(SimplexTest, addInequality_rollback) {
9410a898b3SArjun P   Simplex simplex(3);
9510a898b3SArjun P   SmallVector<int64_t, 4> coeffs[]{{1, 0, 0, 0},   // u >= 0.
9610a898b3SArjun P                                    {-1, 0, 0, 0},  // u <= 0.
9710a898b3SArjun P                                    {1, -1, 1, 0},  // u - v + w >= 0.
9810a898b3SArjun P                                    {1, 1, -1, 0}}; // u + v - w >= 0.
9910a898b3SArjun P   // The above constraints force u = 0 and v = w.
10010a898b3SArjun P   // The constraints below violate v = w.
10110a898b3SArjun P   SmallVector<int64_t, 4> checkCoeffs[]{{0, 1, -1, -1},  // v - w >= 1.
10210a898b3SArjun P                                         {0, -1, 1, -1}}; // v - w <= -1.
10310a898b3SArjun P 
10410a898b3SArjun P   for (int run = 0; run < 4; run++) {
10510a898b3SArjun P     unsigned snapshot = simplex.getSnapshot();
10610a898b3SArjun P 
10710a898b3SArjun P     expectInequalityMakesSetEmpty(simplex, checkCoeffs[0], false);
10810a898b3SArjun P     expectInequalityMakesSetEmpty(simplex, checkCoeffs[1], false);
10910a898b3SArjun P 
11010a898b3SArjun P     for (int i = 0; i < 4; i++)
1116d6f6c4dSArjun P       addInequality(simplex, coeffs[(run + i) % 4]);
11210a898b3SArjun P 
11310a898b3SArjun P     expectInequalityMakesSetEmpty(simplex, checkCoeffs[0], true);
11410a898b3SArjun P     expectInequalityMakesSetEmpty(simplex, checkCoeffs[1], true);
11510a898b3SArjun P 
11610a898b3SArjun P     simplex.rollback(snapshot);
11733afea54SArjun P     EXPECT_EQ(simplex.getNumConstraints(), 0u);
11810a898b3SArjun P 
11910a898b3SArjun P     expectInequalityMakesSetEmpty(simplex, checkCoeffs[0], false);
12010a898b3SArjun P     expectInequalityMakesSetEmpty(simplex, checkCoeffs[1], false);
12110a898b3SArjun P   }
12210a898b3SArjun P }
12310a898b3SArjun P 
simplexFromConstraints(unsigned nDim,ArrayRef<SmallVector<int64_t,8>> ineqs,ArrayRef<SmallVector<int64_t,8>> eqs)12410a898b3SArjun P Simplex simplexFromConstraints(unsigned nDim,
1251fc096afSMehdi Amini                                ArrayRef<SmallVector<int64_t, 8>> ineqs,
1261fc096afSMehdi Amini                                ArrayRef<SmallVector<int64_t, 8>> eqs) {
12710a898b3SArjun P   Simplex simplex(nDim);
12810a898b3SArjun P   for (const auto &ineq : ineqs)
1296d6f6c4dSArjun P     addInequality(simplex, ineq);
13010a898b3SArjun P   for (const auto &eq : eqs)
1316d6f6c4dSArjun P     addEquality(simplex, eq);
13210a898b3SArjun P   return simplex;
13310a898b3SArjun P }
13410a898b3SArjun P 
TEST(SimplexTest,isUnbounded)13510a898b3SArjun P TEST(SimplexTest, isUnbounded) {
13610a898b3SArjun P   EXPECT_FALSE(simplexFromConstraints(
13710a898b3SArjun P                    2, {{1, 1, 0}, {-1, -1, 0}, {1, -1, 5}, {-1, 1, -5}}, {})
13810a898b3SArjun P                    .isUnbounded());
13910a898b3SArjun P 
14010a898b3SArjun P   EXPECT_TRUE(
14110a898b3SArjun P       simplexFromConstraints(2, {{1, 1, 0}, {1, -1, 5}, {-1, 1, -5}}, {})
14210a898b3SArjun P           .isUnbounded());
14310a898b3SArjun P 
14410a898b3SArjun P   EXPECT_TRUE(
14510a898b3SArjun P       simplexFromConstraints(2, {{-1, -1, 0}, {1, -1, 5}, {-1, 1, -5}}, {})
14610a898b3SArjun P           .isUnbounded());
14710a898b3SArjun P 
14810a898b3SArjun P   EXPECT_TRUE(simplexFromConstraints(2, {}, {}).isUnbounded());
14910a898b3SArjun P 
15010a898b3SArjun P   EXPECT_FALSE(simplexFromConstraints(3,
15110a898b3SArjun P                                       {
15210a898b3SArjun P                                           {2, 0, 0, -1},
15310a898b3SArjun P                                           {-2, 0, 0, 1},
15410a898b3SArjun P                                           {0, 2, 0, -1},
15510a898b3SArjun P                                           {0, -2, 0, 1},
15610a898b3SArjun P                                           {0, 0, 2, -1},
15710a898b3SArjun P                                           {0, 0, -2, 1},
15810a898b3SArjun P                                       },
15910a898b3SArjun P                                       {})
16010a898b3SArjun P                    .isUnbounded());
16110a898b3SArjun P 
16210a898b3SArjun P   EXPECT_TRUE(simplexFromConstraints(3,
16310a898b3SArjun P                                      {
16410a898b3SArjun P                                          {2, 0, 0, -1},
16510a898b3SArjun P                                          {-2, 0, 0, 1},
16610a898b3SArjun P                                          {0, 2, 0, -1},
16710a898b3SArjun P                                          {0, -2, 0, 1},
16810a898b3SArjun P                                          {0, 0, -2, 1},
16910a898b3SArjun P                                      },
17010a898b3SArjun P                                      {})
17110a898b3SArjun P                   .isUnbounded());
17210a898b3SArjun P 
17310a898b3SArjun P   EXPECT_TRUE(simplexFromConstraints(3,
17410a898b3SArjun P                                      {
17510a898b3SArjun P                                          {2, 0, 0, -1},
17610a898b3SArjun P                                          {-2, 0, 0, 1},
17710a898b3SArjun P                                          {0, 2, 0, -1},
17810a898b3SArjun P                                          {0, -2, 0, 1},
17910a898b3SArjun P                                          {0, 0, 2, -1},
18010a898b3SArjun P                                      },
18110a898b3SArjun P                                      {})
18210a898b3SArjun P                   .isUnbounded());
18310a898b3SArjun P 
18410a898b3SArjun P   // Bounded set with equalities.
18510a898b3SArjun P   EXPECT_FALSE(simplexFromConstraints(2,
18610a898b3SArjun P                                       {{1, 1, 1},    // x + y >= -1.
18710a898b3SArjun P                                        {-1, -1, 1}}, // x + y <=  1.
18810a898b3SArjun P                                       {{1, -1, 0}}   // x = y.
18910a898b3SArjun P                                       )
19010a898b3SArjun P                    .isUnbounded());
19110a898b3SArjun P 
19210a898b3SArjun P   // Unbounded set with equalities.
19310a898b3SArjun P   EXPECT_TRUE(simplexFromConstraints(3,
19410a898b3SArjun P                                      {{1, 1, 1, 1},     // x + y + z >= -1.
19510a898b3SArjun P                                       {-1, -1, -1, 1}}, // x + y + z <=  1.
19610a898b3SArjun P                                      {{1, -1, -1, 0}}   // x = y + z.
19710a898b3SArjun P                                      )
19810a898b3SArjun P                   .isUnbounded());
19910a898b3SArjun P 
20010a898b3SArjun P   // Rational empty set.
20110a898b3SArjun P   EXPECT_FALSE(simplexFromConstraints(3,
20210a898b3SArjun P                                       {
20310a898b3SArjun P                                           {2, 0, 0, -1},
20410a898b3SArjun P                                           {-2, 0, 0, 1},
20510a898b3SArjun P                                           {0, 2, 2, -1},
20610a898b3SArjun P                                           {0, -2, -2, 1},
20710a898b3SArjun P                                           {3, 3, 3, -4},
20810a898b3SArjun P                                       },
20910a898b3SArjun P                                       {})
21010a898b3SArjun P                    .isUnbounded());
21110a898b3SArjun P }
21210a898b3SArjun P 
TEST(SimplexTest,getSamplePointIfIntegral)21310a898b3SArjun P TEST(SimplexTest, getSamplePointIfIntegral) {
21410a898b3SArjun P   // Empty set.
21510a898b3SArjun P   EXPECT_FALSE(simplexFromConstraints(3,
21610a898b3SArjun P                                       {
21710a898b3SArjun P                                           {2, 0, 0, -1},
21810a898b3SArjun P                                           {-2, 0, 0, 1},
21910a898b3SArjun P                                           {0, 2, 2, -1},
22010a898b3SArjun P                                           {0, -2, -2, 1},
22110a898b3SArjun P                                           {3, 3, 3, -4},
22210a898b3SArjun P                                       },
22310a898b3SArjun P                                       {})
22410a898b3SArjun P                    .getSamplePointIfIntegral()
225491d2701SKazu Hirata                    .has_value());
22610a898b3SArjun P 
22710a898b3SArjun P   auto maybeSample = simplexFromConstraints(2,
22810a898b3SArjun P                                             {// x = y - 2.
22910a898b3SArjun P                                              {1, -1, 2},
23010a898b3SArjun P                                              {-1, 1, -2},
23110a898b3SArjun P                                              // x + y = 2.
23210a898b3SArjun P                                              {1, 1, -2},
23310a898b3SArjun P                                              {-1, -1, 2}},
23410a898b3SArjun P                                             {})
23510a898b3SArjun P                          .getSamplePointIfIntegral();
23610a898b3SArjun P 
237491d2701SKazu Hirata   EXPECT_TRUE(maybeSample.has_value());
23810a898b3SArjun P   EXPECT_THAT(*maybeSample, testing::ElementsAre(0, 2));
23910a898b3SArjun P 
24010a898b3SArjun P   auto maybeSample2 = simplexFromConstraints(2,
24110a898b3SArjun P                                              {
24210a898b3SArjun P                                                  {1, 0, 0},  // x >= 0.
24310a898b3SArjun P                                                  {-1, 0, 0}, // x <= 0.
24410a898b3SArjun P                                              },
24510a898b3SArjun P                                              {
24610a898b3SArjun P                                                  {0, 1, -2} // y = 2.
24710a898b3SArjun P                                              })
24810a898b3SArjun P                           .getSamplePointIfIntegral();
249491d2701SKazu Hirata   EXPECT_TRUE(maybeSample2.has_value());
25010a898b3SArjun P   EXPECT_THAT(*maybeSample2, testing::ElementsAre(0, 2));
25110a898b3SArjun P 
25210a898b3SArjun P   EXPECT_FALSE(simplexFromConstraints(1,
25310a898b3SArjun P                                       {// 2x = 1. (no integer solutions)
25410a898b3SArjun P                                        {2, -1},
25510a898b3SArjun P                                        {-2, +1}},
25610a898b3SArjun P                                       {})
25710a898b3SArjun P                    .getSamplePointIfIntegral()
258491d2701SKazu Hirata                    .has_value());
25910a898b3SArjun P }
26010a898b3SArjun P 
26133f57467SArjun P /// Some basic sanity checks involving zero or one variables.
TEST(SimplexTest,isMarkedRedundant_no_var_ge_zero)26233f57467SArjun P TEST(SimplexTest, isMarkedRedundant_no_var_ge_zero) {
26333f57467SArjun P   Simplex simplex(0);
2646d6f6c4dSArjun P   addInequality(simplex, {0}); // 0 >= 0.
26533f57467SArjun P 
26633f57467SArjun P   simplex.detectRedundant();
26733f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
26833f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(0));
26933f57467SArjun P }
27033f57467SArjun P 
TEST(SimplexTest,isMarkedRedundant_no_var_eq)27133f57467SArjun P TEST(SimplexTest, isMarkedRedundant_no_var_eq) {
27233f57467SArjun P   Simplex simplex(0);
2736d6f6c4dSArjun P   addEquality(simplex, {0}); // 0 == 0.
27433f57467SArjun P   simplex.detectRedundant();
27533f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
27633f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(0));
27733f57467SArjun P }
27833f57467SArjun P 
TEST(SimplexTest,isMarkedRedundant_pos_var_eq)27933f57467SArjun P TEST(SimplexTest, isMarkedRedundant_pos_var_eq) {
28033f57467SArjun P   Simplex simplex(1);
2816d6f6c4dSArjun P   addEquality(simplex, {1, 0}); // x == 0.
28233f57467SArjun P 
28333f57467SArjun P   simplex.detectRedundant();
28433f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
28533f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(0));
28633f57467SArjun P }
28733f57467SArjun P 
TEST(SimplexTest,isMarkedRedundant_zero_var_eq)28833f57467SArjun P TEST(SimplexTest, isMarkedRedundant_zero_var_eq) {
28933f57467SArjun P   Simplex simplex(1);
2906d6f6c4dSArjun P   addEquality(simplex, {0, 0}); // 0x == 0.
29133f57467SArjun P   simplex.detectRedundant();
29233f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
29333f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(0));
29433f57467SArjun P }
29533f57467SArjun P 
TEST(SimplexTest,isMarkedRedundant_neg_var_eq)29633f57467SArjun P TEST(SimplexTest, isMarkedRedundant_neg_var_eq) {
29733f57467SArjun P   Simplex simplex(1);
2986d6f6c4dSArjun P   addEquality(simplex, {-1, 0}); // -x == 0.
29933f57467SArjun P   simplex.detectRedundant();
30033f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
30133f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(0));
30233f57467SArjun P }
30333f57467SArjun P 
TEST(SimplexTest,isMarkedRedundant_pos_var_ge)30433f57467SArjun P TEST(SimplexTest, isMarkedRedundant_pos_var_ge) {
30533f57467SArjun P   Simplex simplex(1);
3066d6f6c4dSArjun P   addInequality(simplex, {1, 0}); // x >= 0.
30733f57467SArjun P   simplex.detectRedundant();
30833f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
30933f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(0));
31033f57467SArjun P }
31133f57467SArjun P 
TEST(SimplexTest,isMarkedRedundant_zero_var_ge)31233f57467SArjun P TEST(SimplexTest, isMarkedRedundant_zero_var_ge) {
31333f57467SArjun P   Simplex simplex(1);
3146d6f6c4dSArjun P   addInequality(simplex, {0, 0}); // 0x >= 0.
31533f57467SArjun P   simplex.detectRedundant();
31633f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
31733f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(0));
31833f57467SArjun P }
31933f57467SArjun P 
TEST(SimplexTest,isMarkedRedundant_neg_var_ge)32033f57467SArjun P TEST(SimplexTest, isMarkedRedundant_neg_var_ge) {
32133f57467SArjun P   Simplex simplex(1);
3226d6f6c4dSArjun P   addInequality(simplex, {-1, 0}); // x <= 0.
32333f57467SArjun P   simplex.detectRedundant();
32433f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
32533f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(0));
32633f57467SArjun P }
32733f57467SArjun P 
32833f57467SArjun P /// None of the constraints are redundant. Slightly more complicated test
32933f57467SArjun P /// involving an equality.
TEST(SimplexTest,isMarkedRedundant_no_redundant)33033f57467SArjun P TEST(SimplexTest, isMarkedRedundant_no_redundant) {
33133f57467SArjun P   Simplex simplex(3);
33233f57467SArjun P 
3336d6f6c4dSArjun P   addEquality(simplex, {-1, 0, 1, 0});     // u = w.
3346d6f6c4dSArjun P   addInequality(simplex, {-1, 16, 0, 15}); // 15 - (u - 16v) >= 0.
3356d6f6c4dSArjun P   addInequality(simplex, {1, -16, 0, 0});  //      (u - 16v) >= 0.
33633f57467SArjun P 
33733f57467SArjun P   simplex.detectRedundant();
33833f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
33933f57467SArjun P 
34033afea54SArjun P   for (unsigned i = 0; i < simplex.getNumConstraints(); ++i)
34133f57467SArjun P     EXPECT_FALSE(simplex.isMarkedRedundant(i)) << "i = " << i << "\n";
34233f57467SArjun P }
34333f57467SArjun P 
TEST(SimplexTest,isMarkedRedundant_repeated_constraints)34433f57467SArjun P TEST(SimplexTest, isMarkedRedundant_repeated_constraints) {
34533f57467SArjun P   Simplex simplex(3);
34633f57467SArjun P 
34733f57467SArjun P   // [4] to [7] are repeats of [0] to [3].
3486d6f6c4dSArjun P   addInequality(simplex, {0, -1, 0, 1}); // [0]: y <= 1.
3496d6f6c4dSArjun P   addInequality(simplex, {-1, 0, 8, 7}); // [1]: 8z >= x - 7.
3506d6f6c4dSArjun P   addInequality(simplex, {1, 0, -8, 0}); // [2]: 8z <= x.
3516d6f6c4dSArjun P   addInequality(simplex, {0, 1, 0, 0});  // [3]: y >= 0.
3526d6f6c4dSArjun P   addInequality(simplex, {-1, 0, 8, 7}); // [4]: 8z >= 7 - x.
3536d6f6c4dSArjun P   addInequality(simplex, {1, 0, -8, 0}); // [5]: 8z <= x.
3546d6f6c4dSArjun P   addInequality(simplex, {0, 1, 0, 0});  // [6]: y >= 0.
3556d6f6c4dSArjun P   addInequality(simplex, {0, -1, 0, 1}); // [7]: y <= 1.
35633f57467SArjun P 
35733f57467SArjun P   simplex.detectRedundant();
35833f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
35933f57467SArjun P 
36033f57467SArjun P   EXPECT_EQ(simplex.isMarkedRedundant(0), true);
36133f57467SArjun P   EXPECT_EQ(simplex.isMarkedRedundant(1), true);
36233f57467SArjun P   EXPECT_EQ(simplex.isMarkedRedundant(2), true);
36333f57467SArjun P   EXPECT_EQ(simplex.isMarkedRedundant(3), true);
36433f57467SArjun P   EXPECT_EQ(simplex.isMarkedRedundant(4), false);
36533f57467SArjun P   EXPECT_EQ(simplex.isMarkedRedundant(5), false);
36633f57467SArjun P   EXPECT_EQ(simplex.isMarkedRedundant(6), false);
36733f57467SArjun P   EXPECT_EQ(simplex.isMarkedRedundant(7), false);
36833f57467SArjun P }
36933f57467SArjun P 
TEST(SimplexTest,isMarkedRedundant)37033f57467SArjun P TEST(SimplexTest, isMarkedRedundant) {
37133f57467SArjun P   Simplex simplex(3);
3726d6f6c4dSArjun P   addInequality(simplex, {0, -1, 0, 1}); // [0]: y <= 1.
3736d6f6c4dSArjun P   addInequality(simplex, {1, 0, 0, -1}); // [1]: x >= 1.
3746d6f6c4dSArjun P   addInequality(simplex, {-1, 0, 0, 2}); // [2]: x <= 2.
3756d6f6c4dSArjun P   addInequality(simplex, {-1, 0, 2, 7}); // [3]: 2z >= x - 7.
3766d6f6c4dSArjun P   addInequality(simplex, {1, 0, -2, 0}); // [4]: 2z <= x.
3776d6f6c4dSArjun P   addInequality(simplex, {0, 1, 0, 0});  // [5]: y >= 0.
3786d6f6c4dSArjun P   addInequality(simplex, {0, 1, -2, 1}); // [6]: y >= 2z - 1.
3796d6f6c4dSArjun P   addInequality(simplex, {-1, 1, 0, 1}); // [7]: y >= x - 1.
38033f57467SArjun P 
38133f57467SArjun P   simplex.detectRedundant();
38233f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
38333f57467SArjun P 
38433f57467SArjun P   // [0], [1], [3], [4], [7] together imply [2], [5], [6] must hold.
38533f57467SArjun P   //
38633f57467SArjun P   // From [7], [0]: x <= y + 1 <= 2, so we have [2].
38733f57467SArjun P   // From [7], [1]: y >= x - 1 >= 0, so we have [5].
38833f57467SArjun P   // From [4], [7]: 2z - 1 <= x - 1 <= y, so we have [6].
38933f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(0));
39033f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(1));
39133f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(2));
39233f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(3));
39333f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(4));
39433f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(5));
39533f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(6));
39633f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(7));
39733f57467SArjun P }
39833f57467SArjun P 
TEST(SimplexTest,isMarkedRedundantTiledLoopNestConstraints)39933f57467SArjun P TEST(SimplexTest, isMarkedRedundantTiledLoopNestConstraints) {
40033f57467SArjun P   Simplex simplex(3);                     // Variables are x, y, N.
4016d6f6c4dSArjun P   addInequality(simplex, {1, 0, 0, 0});   // [0]: x >= 0.
4026d6f6c4dSArjun P   addInequality(simplex, {-32, 0, 1, -1}); // [1]: 32x <= N - 1.
4036d6f6c4dSArjun P   addInequality(simplex, {0, 1, 0, 0});    // [2]: y >= 0.
4046d6f6c4dSArjun P   addInequality(simplex, {-32, 1, 0, 0});  // [3]: y >= 32x.
4056d6f6c4dSArjun P   addInequality(simplex, {32, -1, 0, 31}); // [4]: y <= 32x + 31.
4066d6f6c4dSArjun P   addInequality(simplex, {0, -1, 1, -1});  // [5]: y <= N - 1.
40733f57467SArjun P   // [3] and [0] imply [2], as we have y >= 32x >= 0.
40833f57467SArjun P   // [3] and [5] imply [1], as we have 32x <= y <= N - 1.
40933f57467SArjun P   simplex.detectRedundant();
41033f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(0));
41133f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(1));
41233f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(2));
41333f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(3));
41433f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(4));
41533f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(5));
41633f57467SArjun P }
41733f57467SArjun P 
TEST(SimplexTest,pivotRedundantRegressionTest)4186761dd7dSArjun P TEST(SimplexTest, pivotRedundantRegressionTest) {
419f074bbb0SArjun P   Simplex simplex(2);
4206d6f6c4dSArjun P   addInequality(simplex, {-1, 0, -1}); // x <= -1.
421f074bbb0SArjun P   unsigned snapshot = simplex.getSnapshot();
422f074bbb0SArjun P 
4236d6f6c4dSArjun P   addInequality(simplex, {-1, 0, -2}); // x <= -2.
4246d6f6c4dSArjun P   addInequality(simplex, {-3, 0, -6});
425f074bbb0SArjun P 
426f074bbb0SArjun P   // This first marks x <= -1 as redundant. Then it performs some more pivots
427f074bbb0SArjun P   // to check if the other constraints are redundant. Pivot must update the
428f074bbb0SArjun P   // non-redundant rows as well, otherwise these pivots result in an incorrect
429f074bbb0SArjun P   // tableau state. In particular, after the rollback below, some rows that are
430f074bbb0SArjun P   // NOT marked redundant will have an incorrect state.
431f074bbb0SArjun P   simplex.detectRedundant();
432f074bbb0SArjun P 
433f074bbb0SArjun P   // After the rollback, the only remaining constraint is x <= -1.
434f074bbb0SArjun P   // The maximum value of x should be -1.
435f074bbb0SArjun P   simplex.rollback(snapshot);
436*1a0e67d7SRamkumar Ramachandra   MaybeOptimum<Fraction> maxX = simplex.computeOptimum(
437*1a0e67d7SRamkumar Ramachandra       Simplex::Direction::Up, getDynamicAPIntVec({1, 0, 0}));
4388e799588SArjun P   EXPECT_TRUE(maxX.isBounded() && *maxX == Fraction(-1, 1));
439f074bbb0SArjun P }
440f074bbb0SArjun P 
TEST(SimplexTest,addInequality_already_redundant)44133f57467SArjun P TEST(SimplexTest, addInequality_already_redundant) {
44233f57467SArjun P   Simplex simplex(1);
4436d6f6c4dSArjun P   addInequality(simplex, {1, -1}); // x >= 1.
4446d6f6c4dSArjun P   addInequality(simplex, {1, 0});  // x >= 0.
44533f57467SArjun P   simplex.detectRedundant();
44633f57467SArjun P   ASSERT_FALSE(simplex.isEmpty());
44733f57467SArjun P   EXPECT_FALSE(simplex.isMarkedRedundant(0));
44833f57467SArjun P   EXPECT_TRUE(simplex.isMarkedRedundant(1));
44933f57467SArjun P }
45033f57467SArjun P 
TEST(SimplexTest,appendVariable)4512b44a732SArjun P TEST(SimplexTest, appendVariable) {
4522b44a732SArjun P   Simplex simplex(1);
4532b44a732SArjun P 
4542b44a732SArjun P   unsigned snapshot1 = simplex.getSnapshot();
4552b44a732SArjun P   simplex.appendVariable();
45676cb8765SArjun P   simplex.appendVariable(0);
45733afea54SArjun P   EXPECT_EQ(simplex.getNumVariables(), 2u);
4582b44a732SArjun P 
4592b44a732SArjun P   int64_t yMin = 2, yMax = 5;
4606d6f6c4dSArjun P   addInequality(simplex, {0, 1, -yMin}); // y >= 2.
4616d6f6c4dSArjun P   addInequality(simplex, {0, -1, yMax}); // y <= 5.
4622b44a732SArjun P 
4632b44a732SArjun P   unsigned snapshot2 = simplex.getSnapshot();
4642b44a732SArjun P   simplex.appendVariable(2);
46533afea54SArjun P   EXPECT_EQ(simplex.getNumVariables(), 4u);
4662b44a732SArjun P   simplex.rollback(snapshot2);
4672b44a732SArjun P 
46833afea54SArjun P   EXPECT_EQ(simplex.getNumVariables(), 2u);
46933afea54SArjun P   EXPECT_EQ(simplex.getNumConstraints(), 2u);
470*1a0e67d7SRamkumar Ramachandra   EXPECT_EQ(simplex.computeIntegerBounds(getDynamicAPIntVec({0, 1, 0})),
471*1a0e67d7SRamkumar Ramachandra             std::make_pair(MaybeOptimum<DynamicAPInt>(DynamicAPInt(yMin)),
472*1a0e67d7SRamkumar Ramachandra                            MaybeOptimum<DynamicAPInt>(DynamicAPInt(yMax))));
4732b44a732SArjun P 
4742b44a732SArjun P   simplex.rollback(snapshot1);
47533afea54SArjun P   EXPECT_EQ(simplex.getNumVariables(), 1u);
47633afea54SArjun P   EXPECT_EQ(simplex.getNumConstraints(), 0u);
4772b44a732SArjun P }
4782b44a732SArjun P 
TEST(SimplexTest,isRedundantInequality)47945ea542dSMichel Weber TEST(SimplexTest, isRedundantInequality) {
48045ea542dSMichel Weber   Simplex simplex(2);
4816d6f6c4dSArjun P   addInequality(simplex, {0, -1, 2}); // y <= 2.
4826d6f6c4dSArjun P   addInequality(simplex, {1, 0, 0});  // x >= 0.
4836d6f6c4dSArjun P   addEquality(simplex, {-1, 1, 0});   // y = x.
48445ea542dSMichel Weber 
4856d6f6c4dSArjun P   EXPECT_TRUE(isRedundantInequality(simplex, {-1, 0, 2})); // x <= 2.
4866d6f6c4dSArjun P   EXPECT_TRUE(isRedundantInequality(simplex, {0, 1, 0}));  // y >= 0.
48745ea542dSMichel Weber 
4886d6f6c4dSArjun P   EXPECT_FALSE(isRedundantInequality(simplex, {-1, 0, -1})); // x <= -1.
4896d6f6c4dSArjun P   EXPECT_FALSE(isRedundantInequality(simplex, {0, 1, -2}));  // y >= 2.
4906d6f6c4dSArjun P   EXPECT_FALSE(isRedundantInequality(simplex, {0, 1, -1}));  // y >= 1.
49145ea542dSMichel Weber }
49245ea542dSMichel Weber 
TEST(SimplexTest,ineqType)49356bc8732SMichel Weber TEST(SimplexTest, ineqType) {
49456bc8732SMichel Weber   Simplex simplex(2);
4956d6f6c4dSArjun P   addInequality(simplex, {0, -1, 2}); // y <= 2.
4966d6f6c4dSArjun P   addInequality(simplex, {1, 0, 0});  // x >= 0.
4976d6f6c4dSArjun P   addEquality(simplex, {-1, 1, 0});   // y = x.
49856bc8732SMichel Weber 
4996d6f6c4dSArjun P   EXPECT_EQ(findIneqType(simplex, {-1, 0, 2}),
50056bc8732SMichel Weber             Simplex::IneqType::Redundant); // x <= 2.
5016d6f6c4dSArjun P   EXPECT_EQ(findIneqType(simplex, {0, 1, 0}),
50256bc8732SMichel Weber             Simplex::IneqType::Redundant); // y >= 0.
50356bc8732SMichel Weber 
5046d6f6c4dSArjun P   EXPECT_EQ(findIneqType(simplex, {0, 1, -1}),
50556bc8732SMichel Weber             Simplex::IneqType::Cut); // y >= 1.
5066d6f6c4dSArjun P   EXPECT_EQ(findIneqType(simplex, {-1, 0, 1}),
50756bc8732SMichel Weber             Simplex::IneqType::Cut); // x <= 1.
5086d6f6c4dSArjun P   EXPECT_EQ(findIneqType(simplex, {0, 1, -2}),
50956bc8732SMichel Weber             Simplex::IneqType::Cut); // y >= 2.
51056bc8732SMichel Weber 
5116d6f6c4dSArjun P   EXPECT_EQ(findIneqType(simplex, {-1, 0, -1}),
51256bc8732SMichel Weber             Simplex::IneqType::Separate); // x <= -1.
51356bc8732SMichel Weber }
51456bc8732SMichel Weber 
TEST(SimplexTest,isRedundantEquality)51545ea542dSMichel Weber TEST(SimplexTest, isRedundantEquality) {
51645ea542dSMichel Weber   Simplex simplex(2);
5176d6f6c4dSArjun P   addInequality(simplex, {0, -1, 2}); // y <= 2.
5186d6f6c4dSArjun P   addInequality(simplex, {1, 0, 0});  // x >= 0.
5196d6f6c4dSArjun P   addEquality(simplex, {-1, 1, 0});   // y = x.
52045ea542dSMichel Weber 
5216d6f6c4dSArjun P   EXPECT_TRUE(isRedundantEquality(simplex, {-1, 1, 0})); // y = x.
5226d6f6c4dSArjun P   EXPECT_TRUE(isRedundantEquality(simplex, {1, -1, 0})); // x = y.
52345ea542dSMichel Weber 
5246d6f6c4dSArjun P   EXPECT_FALSE(isRedundantEquality(simplex, {0, 1, -1})); // y = 1.
52545ea542dSMichel Weber 
5266d6f6c4dSArjun P   addEquality(simplex, {0, -1, 2}); // y = 2.
52745ea542dSMichel Weber 
5286d6f6c4dSArjun P   EXPECT_TRUE(isRedundantEquality(simplex, {-1, 0, 2})); // x = 2.
52945ea542dSMichel Weber }
53045ea542dSMichel Weber 
TEST(SimplexTest,IsRationalSubsetOf)53145ea542dSMichel Weber TEST(SimplexTest, IsRationalSubsetOf) {
5328c867f78SGroverkss   IntegerPolyhedron univ = parseIntegerPolyhedron("(x) : ()");
5338c867f78SGroverkss   IntegerPolyhedron empty =
5348c867f78SGroverkss       parseIntegerPolyhedron("(x) : (x + 0 >= 0, -x - 1 >= 0)");
5358c867f78SGroverkss   IntegerPolyhedron s1 = parseIntegerPolyhedron("(x) : ( x >= 0, -x + 4 >= 0)");
5368c867f78SGroverkss   IntegerPolyhedron s2 =
5378c867f78SGroverkss       parseIntegerPolyhedron("(x) : (x - 1 >= 0, -x + 3 >= 0)");
53845ea542dSMichel Weber 
53945ea542dSMichel Weber   Simplex simUniv(univ);
54045ea542dSMichel Weber   Simplex simEmpty(empty);
54145ea542dSMichel Weber   Simplex sim1(s1);
54245ea542dSMichel Weber   Simplex sim2(s2);
54345ea542dSMichel Weber 
54445ea542dSMichel Weber   EXPECT_TRUE(simUniv.isRationalSubsetOf(univ));
54545ea542dSMichel Weber   EXPECT_TRUE(simEmpty.isRationalSubsetOf(empty));
54645ea542dSMichel Weber   EXPECT_TRUE(sim1.isRationalSubsetOf(s1));
54745ea542dSMichel Weber   EXPECT_TRUE(sim2.isRationalSubsetOf(s2));
54845ea542dSMichel Weber 
54945ea542dSMichel Weber   EXPECT_TRUE(simEmpty.isRationalSubsetOf(univ));
55045ea542dSMichel Weber   EXPECT_TRUE(simEmpty.isRationalSubsetOf(s1));
55145ea542dSMichel Weber   EXPECT_TRUE(simEmpty.isRationalSubsetOf(s2));
55245ea542dSMichel Weber   EXPECT_TRUE(simEmpty.isRationalSubsetOf(empty));
55345ea542dSMichel Weber 
55445ea542dSMichel Weber   EXPECT_TRUE(simUniv.isRationalSubsetOf(univ));
55545ea542dSMichel Weber   EXPECT_FALSE(simUniv.isRationalSubsetOf(s1));
55645ea542dSMichel Weber   EXPECT_FALSE(simUniv.isRationalSubsetOf(s2));
55745ea542dSMichel Weber   EXPECT_FALSE(simUniv.isRationalSubsetOf(empty));
55845ea542dSMichel Weber 
55945ea542dSMichel Weber   EXPECT_TRUE(sim1.isRationalSubsetOf(univ));
56045ea542dSMichel Weber   EXPECT_TRUE(sim1.isRationalSubsetOf(s1));
56145ea542dSMichel Weber   EXPECT_FALSE(sim1.isRationalSubsetOf(s2));
56245ea542dSMichel Weber   EXPECT_FALSE(sim1.isRationalSubsetOf(empty));
56345ea542dSMichel Weber 
56445ea542dSMichel Weber   EXPECT_TRUE(sim2.isRationalSubsetOf(univ));
56545ea542dSMichel Weber   EXPECT_TRUE(sim2.isRationalSubsetOf(s1));
56645ea542dSMichel Weber   EXPECT_TRUE(sim2.isRationalSubsetOf(s2));
56745ea542dSMichel Weber   EXPECT_FALSE(sim2.isRationalSubsetOf(empty));
56845ea542dSMichel Weber }
569ff447604SArjun P 
TEST(SimplexTest,addDivisionVariable)570ff447604SArjun P TEST(SimplexTest, addDivisionVariable) {
571ff447604SArjun P   Simplex simplex(/*nVar=*/1);
572*1a0e67d7SRamkumar Ramachandra   simplex.addDivisionVariable(getDynamicAPIntVec({1, 0}), DynamicAPInt(2));
5736d6f6c4dSArjun P   addInequality(simplex, {1, 0, -3}); // x >= 3.
5746d6f6c4dSArjun P   addInequality(simplex, {-1, 0, 9}); // x <= 9.
575*1a0e67d7SRamkumar Ramachandra   std::optional<SmallVector<DynamicAPInt, 8>> sample =
576*1a0e67d7SRamkumar Ramachandra       simplex.findIntegerSample();
577491d2701SKazu Hirata   ASSERT_TRUE(sample.has_value());
578ff447604SArjun P   EXPECT_EQ((*sample)[0] / 2, (*sample)[1]);
579ff447604SArjun P }
580fbeb0db5SArjun P 
TEST(SimplexTest,LexIneqType)581fbeb0db5SArjun P TEST(SimplexTest, LexIneqType) {
582fbeb0db5SArjun P   LexSimplex simplex(/*nVar=*/1);
5836d6f6c4dSArjun P   addInequality(simplex, {2, -1}); // x >= 1/2.
584fbeb0db5SArjun P 
585fbeb0db5SArjun P   // Redundant inequality x >= 2/3.
5866d6f6c4dSArjun P   EXPECT_TRUE(isRedundantInequality(simplex, {3, -2}));
5876d6f6c4dSArjun P   EXPECT_FALSE(isSeparateInequality(simplex, {3, -2}));
588fbeb0db5SArjun P 
589fbeb0db5SArjun P   // Separate inequality x <= 2/3.
5906d6f6c4dSArjun P   EXPECT_FALSE(isRedundantInequality(simplex, {-3, 2}));
5916d6f6c4dSArjun P   EXPECT_TRUE(isSeparateInequality(simplex, {-3, 2}));
592fbeb0db5SArjun P 
593fbeb0db5SArjun P   // Cut inequality x <= 1.
5946d6f6c4dSArjun P   EXPECT_FALSE(isRedundantInequality(simplex, {-1, 1}));
5956d6f6c4dSArjun P   EXPECT_FALSE(isSeparateInequality(simplex, {-1, 1}));
596fbeb0db5SArjun P }
597