Skip to content

Commit c4abef2

Browse files
committed
[MLIR][Presburger] support symbolicLexMin for IntegerRelation
This also changes the space of the returned lexmin for IntegerPolyhedrons; the symbols in the poly now correspond to symbols in the result rather than dims. Reviewed By: Groverkss Differential Revision: https://reviews.llvm.org/D128933
1 parent c2fcaf8 commit c4abef2

File tree

5 files changed

+106
-70
lines changed

5 files changed

+106
-70
lines changed

mlir/include/mlir/Analysis/Presburger/IntegerRelation.h

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class IntegerRelation;
2828
class IntegerPolyhedron;
2929
class PresburgerSet;
3030
class PresburgerRelation;
31+
struct SymbolicLexMin;
3132

3233
/// An IntegerRelation represents the set of points from a PresburgerSpace that
3334
/// satisfy a list of affine constraints. Affine constraints can be inequalities
@@ -583,6 +584,30 @@ class IntegerRelation {
583584
/// union of convex disjuncts.
584585
PresburgerRelation computeReprWithOnlyDivLocals() const;
585586

587+
/// Compute the symbolic integer lexmin of the relation.
588+
///
589+
/// This finds, for every assignment to the symbols and domain,
590+
/// the lexicographically minimum value attained by the range.
591+
///
592+
/// For example, the symbolic lexmin of the set
593+
///
594+
/// (x, y)[a, b, c] : (a <= x, b <= x, x <= c)
595+
///
596+
/// can be written as
597+
///
598+
/// x = a if b <= a, a <= c
599+
/// x = b if a < b, b <= c
600+
///
601+
/// This function is stored in the `lexmin` function in the result.
602+
/// Some assignments to the symbols might make the set empty.
603+
/// Such points are not part of the function's domain.
604+
/// In the above example, this happens when max(a, b) > c.
605+
///
606+
/// For some values of the symbols, the lexmin may be unbounded.
607+
/// `SymbolicLexMin` stores these parts of the symbolic domain in a separate
608+
/// `PresburgerSet`, `unboundedDomain`.
609+
SymbolicLexMin findSymbolicIntegerLexMin() const;
610+
586611
void print(raw_ostream &os) const;
587612
void dump() const;
588613

@@ -692,8 +717,6 @@ class IntegerRelation {
692717
Matrix inequalities;
693718
};
694719

695-
struct SymbolicLexMin;
696-
697720
/// An IntegerPolyhedron represents the set of points from a PresburgerSpace
698721
/// that satisfy a list of affine constraints. Affine constraints can be
699722
/// inequalities or equalities in the form:
@@ -767,28 +790,6 @@ class IntegerPolyhedron : public IntegerRelation {
767790
/// column position (i.e., not relative to the kind of variable) of the
768791
/// first added variable.
769792
unsigned insertVar(VarKind kind, unsigned pos, unsigned num = 1) override;
770-
771-
/// Compute the symbolic integer lexmin of the polyhedron.
772-
/// This finds, for every assignment to the symbols, the lexicographically
773-
/// minimum value attained by the dimensions. For example, the symbolic lexmin
774-
/// of the set
775-
///
776-
/// (x, y)[a, b, c] : (a <= x, b <= x, x <= c)
777-
///
778-
/// can be written as
779-
///
780-
/// x = a if b <= a, a <= c
781-
/// x = b if a < b, b <= c
782-
///
783-
/// This function is stored in the `lexmin` function in the result.
784-
/// Some assignments to the symbols might make the set empty.
785-
/// Such points are not part of the function's domain.
786-
/// In the above example, this happens when max(a, b) > c.
787-
///
788-
/// For some values of the symbols, the lexmin may be unbounded.
789-
/// `SymbolicLexMin` stores these parts of the symbolic domain in a separate
790-
/// `PresburgerSet`, `unboundedDomain`.
791-
SymbolicLexMin findSymbolicIntegerLexMin() const;
792793
};
793794

794795
} // namespace presburger

mlir/lib/Analysis/Presburger/IntegerRelation.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,23 @@ PresburgerRelation IntegerRelation::computeReprWithOnlyDivLocals() const {
226226
return result;
227227
}
228228

229-
SymbolicLexMin IntegerPolyhedron::findSymbolicIntegerLexMin() const {
229+
SymbolicLexMin IntegerRelation::findSymbolicIntegerLexMin() const {
230+
// Symbol and Domain vars will be used as symbols for symbolic lexmin.
231+
// In other words, for every value of the symbols and domain, return the
232+
// lexmin value of the (range, locals).
233+
llvm::SmallBitVector isSymbol(getNumVars(), false);
234+
isSymbol.set(getVarKindOffset(VarKind::Symbol),
235+
getVarKindEnd(VarKind::Symbol));
236+
isSymbol.set(getVarKindOffset(VarKind::Domain),
237+
getVarKindEnd(VarKind::Domain));
230238
// Compute the symbolic lexmin of the dims and locals, with the symbols being
231239
// the actual symbols of this set.
232240
SymbolicLexMin result =
233-
SymbolicLexSimplex(*this, IntegerPolyhedron(PresburgerSpace::getSetSpace(
234-
/*numDims=*/getNumSymbolVars())))
241+
SymbolicLexSimplex(*this,
242+
IntegerPolyhedron(PresburgerSpace::getSetSpace(
243+
/*numDims=*/getNumDomainVars(),
244+
/*numSymbols=*/getNumSymbolVars())),
245+
isSymbol)
235246
.computeSymbolicIntegerLexMin();
236247

237248
// We want to return only the lexmin over the dims, so strip the locals from

mlir/unittests/Analysis/Presburger/IntegerPolyhedronTest.cpp

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,10 +1170,11 @@ void expectSymbolicIntegerLexMin(
11701170

11711171
PWMAFunction expectedLexmin =
11721172
parsePWMAF(/*numInputs=*/poly.getNumSymbolVars(),
1173-
/*numOutputs=*/poly.getNumDimVars(), expectedLexminRepr);
1173+
/*numOutputs=*/poly.getNumDimVars(), expectedLexminRepr,
1174+
/*numSymbols=*/poly.getNumSymbolVars());
11741175

11751176
PresburgerSet expectedUnboundedDomain = parsePresburgerSetFromPolyStrings(
1176-
poly.getNumSymbolVars(), expectedUnboundedDomainRepr);
1177+
/*numDims=*/0, expectedUnboundedDomainRepr, poly.getNumSymbolVars());
11771178

11781179
SymbolicLexMin result = poly.findSymbolicIntegerLexMin();
11791180

@@ -1200,114 +1201,116 @@ void expectSymbolicIntegerLexMin(
12001201
TEST(IntegerPolyhedronTest, findSymbolicIntegerLexMin) {
12011202
expectSymbolicIntegerLexMin("(x)[a] : (x - a >= 0)",
12021203
{
1203-
{"(a) : ()", {{1, 0}}}, // a
1204+
{"()[a] : ()", {{1, 0}}}, // a
12041205
});
12051206

12061207
expectSymbolicIntegerLexMin(
12071208
"(x)[a, b] : (x - a >= 0, x - b >= 0)",
12081209
{
1209-
{"(a, b) : (a - b >= 0)", {{1, 0, 0}}}, // a
1210-
{"(a, b) : (b - a - 1 >= 0)", {{0, 1, 0}}}, // b
1210+
{"()[a, b] : (a - b >= 0)", {{1, 0, 0}}}, // a
1211+
{"()[a, b] : (b - a - 1 >= 0)", {{0, 1, 0}}}, // b
12111212
});
12121213

12131214
expectSymbolicIntegerLexMin(
12141215
"(x)[a, b, c] : (x -a >= 0, x - b >= 0, x - c >= 0)",
12151216
{
1216-
{"(a, b, c) : (a - b >= 0, a - c >= 0)", {{1, 0, 0, 0}}}, // a
1217-
{"(a, b, c) : (b - a - 1 >= 0, b - c >= 0)", {{0, 1, 0, 0}}}, // b
1218-
{"(a, b, c) : (c - a - 1 >= 0, c - b - 1 >= 0)", {{0, 0, 1, 0}}}, // c
1217+
{"()[a, b, c] : (a - b >= 0, a - c >= 0)", {{1, 0, 0, 0}}}, // a
1218+
{"()[a, b, c] : (b - a - 1 >= 0, b - c >= 0)", {{0, 1, 0, 0}}}, // b
1219+
{"()[a, b, c] : (c - a - 1 >= 0, c - b - 1 >= 0)",
1220+
{{0, 0, 1, 0}}}, // c
12191221
});
12201222

12211223
expectSymbolicIntegerLexMin("(x, y)[a] : (x - a >= 0, x + y >= 0)",
12221224
{
1223-
{"(a) : ()", {{1, 0}, {-1, 0}}}, // (a, -a)
1225+
{"()[a] : ()", {{1, 0}, {-1, 0}}}, // (a, -a)
12241226
});
12251227

12261228
expectSymbolicIntegerLexMin(
12271229
"(x, y)[a] : (x - a >= 0, x + y >= 0, y >= 0)",
12281230
{
1229-
{"(a) : (a >= 0)", {{1, 0}, {0, 0}}}, // (a, 0)
1230-
{"(a) : (-a - 1 >= 0)", {{1, 0}, {-1, 0}}}, // (a, -a)
1231+
{"()[a] : (a >= 0)", {{1, 0}, {0, 0}}}, // (a, 0)
1232+
{"()[a] : (-a - 1 >= 0)", {{1, 0}, {-1, 0}}}, // (a, -a)
12311233
});
12321234

12331235
expectSymbolicIntegerLexMin(
12341236
"(x, y)[a, b, c] : (x - a >= 0, y - b >= 0, c - x - y >= 0)",
12351237
{
1236-
{"(a, b, c) : (c - a - b >= 0)",
1238+
{"()[a, b, c] : (c - a - b >= 0)",
12371239
{{1, 0, 0, 0}, {0, 1, 0, 0}}}, // (a, b)
12381240
});
12391241

12401242
expectSymbolicIntegerLexMin(
12411243
"(x, y, z)[a, b, c] : (c - z >= 0, b - y >= 0, x + y + z - a == 0)",
12421244
{
1243-
{"(a, b, c) : ()",
1245+
{"()[a, b, c] : ()",
12441246
{{1, -1, -1, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}}}, // (a - b - c, b, c)
12451247
});
12461248

12471249
expectSymbolicIntegerLexMin(
12481250
"(x)[a, b] : (a >= 0, b >= 0, x >= 0, a + b + x - 1 >= 0)",
12491251
{
1250-
{"(a, b) : (a >= 0, b >= 0, a + b - 1 >= 0)", {{0, 0, 0}}}, // 0
1251-
{"(a, b) : (a == 0, b == 0)", {{0, 0, 1}}}, // 1
1252+
{"()[a, b] : (a >= 0, b >= 0, a + b - 1 >= 0)", {{0, 0, 0}}}, // 0
1253+
{"()[a, b] : (a == 0, b == 0)", {{0, 0, 1}}}, // 1
12521254
});
12531255

12541256
expectSymbolicIntegerLexMin(
12551257
"(x)[a, b] : (1 - a >= 0, a >= 0, 1 - b >= 0, b >= 0, 1 - x >= 0, x >= "
12561258
"0, a + b + x - 1 >= 0)",
12571259
{
1258-
{"(a, b) : (1 - a >= 0, a >= 0, 1 - b >= 0, b >= 0, a + b - 1 >= 0)",
1259-
{{0, 0, 0}}}, // 0
1260-
{"(a, b) : (a == 0, b == 0)", {{0, 0, 1}}}, // 1
1260+
{"()[a, b] : (1 - a >= 0, a >= 0, 1 - b >= 0, b >= 0, a + b - 1 >= "
1261+
"0)",
1262+
{{0, 0, 0}}}, // 0
1263+
{"()[a, b] : (a == 0, b == 0)", {{0, 0, 1}}}, // 1
12611264
});
12621265

12631266
expectSymbolicIntegerLexMin(
12641267
"(x, y, z)[a, b] : (x - a == 0, y - b == 0, x >= 0, y >= 0, z >= 0, x + "
12651268
"y + z - 1 >= 0)",
12661269
{
1267-
{"(a, b) : (a >= 0, b >= 0, 1 - a - b >= 0)",
1270+
{"()[a, b] : (a >= 0, b >= 0, 1 - a - b >= 0)",
12681271
{{1, 0, 0}, {0, 1, 0}, {-1, -1, 1}}}, // (a, b, 1 - a - b)
1269-
{"(a, b) : (a >= 0, b >= 0, a + b - 2 >= 0)",
1272+
{"()[a, b] : (a >= 0, b >= 0, a + b - 2 >= 0)",
12701273
{{1, 0, 0}, {0, 1, 0}, {0, 0, 0}}}, // (a, b, 0)
12711274
});
12721275

12731276
expectSymbolicIntegerLexMin("(x)[a, b] : (x - a == 0, x - b >= 0)",
12741277
{
1275-
{"(a, b) : (a - b >= 0)", {{1, 0, 0}}}, // a
1278+
{"()[a, b] : (a - b >= 0)", {{1, 0, 0}}}, // a
12761279
});
12771280

12781281
expectSymbolicIntegerLexMin(
12791282
"(q)[a] : (a - 1 - 3*q == 0, q >= 0)",
12801283
{
1281-
{"(a) : (a - 1 - 3*(a floordiv 3) == 0, a >= 0)",
1284+
{"()[a] : (a - 1 - 3*(a floordiv 3) == 0, a >= 0)",
12821285
{{0, 1, 0}}}, // a floordiv 3
12831286
});
12841287

12851288
expectSymbolicIntegerLexMin(
12861289
"(r, q)[a] : (a - r - 3*q == 0, q >= 0, 1 - r >= 0, r >= 0)",
12871290
{
1288-
{"(a) : (a - 0 - 3*(a floordiv 3) == 0, a >= 0)",
1291+
{"()[a] : (a - 0 - 3*(a floordiv 3) == 0, a >= 0)",
12891292
{{0, 0, 0}, {0, 1, 0}}}, // (0, a floordiv 3)
1290-
{"(a) : (a - 1 - 3*(a floordiv 3) == 0, a >= 0)",
1293+
{"()[a] : (a - 1 - 3*(a floordiv 3) == 0, a >= 0)",
12911294
{{0, 0, 1}, {0, 1, 0}}}, // (1 a floordiv 3)
12921295
});
12931296

12941297
expectSymbolicIntegerLexMin(
12951298
"(r, q)[a] : (a - r - 3*q == 0, q >= 0, 2 - r >= 0, r - 1 >= 0)",
12961299
{
1297-
{"(a) : (a - 1 - 3*(a floordiv 3) == 0, a >= 0)",
1300+
{"()[a] : (a - 1 - 3*(a floordiv 3) == 0, a >= 0)",
12981301
{{0, 0, 1}, {0, 1, 0}}}, // (1, a floordiv 3)
1299-
{"(a) : (a - 2 - 3*(a floordiv 3) == 0, a >= 0)",
1302+
{"()[a] : (a - 2 - 3*(a floordiv 3) == 0, a >= 0)",
13001303
{{0, 0, 2}, {0, 1, 0}}}, // (2, a floordiv 3)
13011304
});
13021305

13031306
expectSymbolicIntegerLexMin(
13041307
"(r, q)[a] : (a - r - 3*q == 0, q >= 0, r >= 0)",
13051308
{
1306-
{"(a) : (a - 3*(a floordiv 3) == 0, a >= 0)",
1309+
{"()[a] : (a - 3*(a floordiv 3) == 0, a >= 0)",
13071310
{{0, 0, 0}, {0, 1, 0}}}, // (0, a floordiv 3)
1308-
{"(a) : (a - 1 - 3*(a floordiv 3) == 0, a >= 0)",
1311+
{"()[a] : (a - 1 - 3*(a floordiv 3) == 0, a >= 0)",
13091312
{{0, 0, 1}, {0, 1, 0}}}, // (1, a floordiv 3)
1310-
{"(a) : (a - 2 - 3*(a floordiv 3) == 0, a >= 0)",
1313+
{"()[a] : (a - 2 - 3*(a floordiv 3) == 0, a >= 0)",
13111314
{{0, 0, 2}, {0, 1, 0}}}, // (2, a floordiv 3)
13121315
});
13131316

@@ -1323,11 +1326,11 @@ TEST(IntegerPolyhedronTest, findSymbolicIntegerLexMin) {
13231326
// What's the lexmin solution using exactly g true vars?
13241327
"g - x - y - z - w == 0)",
13251328
{
1326-
{"(g) : (g - 1 == 0)",
1329+
{"()[g] : (g - 1 == 0)",
13271330
{{0, 0}, {0, 1}, {0, 0}, {0, 0}}}, // (0, 1, 0, 0)
1328-
{"(g) : (g - 2 == 0)",
1331+
{"()[g] : (g - 2 == 0)",
13291332
{{0, 0}, {0, 0}, {0, 1}, {0, 1}}}, // (0, 0, 1, 1)
1330-
{"(g) : (g - 3 == 0)",
1333+
{"()[g] : (g - 3 == 0)",
13311334
{{0, 0}, {0, 1}, {0, 1}, {0, 1}}}, // (0, 1, 1, 1)
13321335
});
13331336

@@ -1340,19 +1343,19 @@ TEST(IntegerPolyhedronTest, findSymbolicIntegerLexMin) {
13401343
// According to Bezout's lemma, 14x + 35y can take on all multiples
13411344
// of 7 and no other values. So the solution exists iff r - a is a
13421345
// multiple of 7.
1343-
{"(a, r) : (a >= 0, r - a - 7*((r - a) floordiv 7) == 0)"});
1346+
{"()[a, r] : (a >= 0, r - a - 7*((r - a) floordiv 7) == 0)"});
13441347

13451348
// The lexmins are unbounded.
13461349
expectSymbolicIntegerLexMin("(x, y)[a] : (9*x - 4*y - 2*a >= 0)", {},
1347-
{"(a) : ()"});
1350+
{"()[a] : ()"});
13481351

13491352
// Test cases adapted from isl.
13501353
expectSymbolicIntegerLexMin(
13511354
// a = 2b - 2(c - b), c - b >= 0.
13521355
// So b is minimized when c = b.
13531356
"(b, c)[a] : (a - 4*b + 2*c == 0, c - b >= 0)",
13541357
{
1355-
{"(a) : (a - 2*(a floordiv 2) == 0)",
1358+
{"()[a] : (a - 2*(a floordiv 2) == 0)",
13561359
{{0, 1, 0}, {0, 1, 0}}}, // (a floordiv 2, a floordiv 2)
13571360
});
13581361

@@ -1362,7 +1365,7 @@ TEST(IntegerPolyhedronTest, findSymbolicIntegerLexMin) {
13621365
"(b)[a] : (255 - b >= 0, b >= 0, a - 512*b - 1 >= 0, 512*b -a + 509 >= "
13631366
"0, b + 7 - 16*((8 + b) floordiv 16) >= 0)",
13641367
{
1365-
{"(a) : (255 - (a floordiv 512) >= 0, a >= 0, a - 512*(a floordiv "
1368+
{"()[a] : (255 - (a floordiv 512) >= 0, a >= 0, a - 512*(a floordiv "
13661369
"512) - 1 >= 0, 512*(a floordiv 512) - a + 509 >= 0, (a floordiv "
13671370
"512) + 7 - 16*((8 + (a floordiv 512)) floordiv 16) >= 0)",
13681371
{{0, 1, 0, 0}}}, // (a floordiv 2, a floordiv 2)
@@ -1375,7 +1378,8 @@ TEST(IntegerPolyhedronTest, findSymbolicIntegerLexMin) {
13751378
"2*N - 3*K + a - b >= 0, 4*N - K + 1 - 3*b >= 0, b - N >= 0, a - x - 1 "
13761379
">= 0)",
13771380
{{
1378-
"(K, N, x, y) : (x + 6 - 2*N >= 0, 2*N - 5 - x >= 0, x + 1 -3*K + N "
1381+
"()[K, N, x, y] : (x + 6 - 2*N >= 0, 2*N - 5 - x >= 0, x + 1 -3*K + "
1382+
"N "
13791383
">= 0, N + K - 2 - x >= 0, x - 4 >= 0)",
13801384
{{0, 0, 1, 0, 1}, {0, 1, 0, 0, 0}} // (1 + x, N)
13811385
}});

mlir/unittests/Analysis/Presburger/IntegerRelationTest.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "mlir/Analysis/Presburger/IntegerRelation.h"
1010
#include "./Utils.h"
11+
#include "mlir/Analysis/Presburger/Simplex.h"
1112

1213
#include <gmock/gmock.h>
1314
#include <gtest/gtest.h>
@@ -122,3 +123,20 @@ TEST(IntegerRelationTest, applyDomainAndRange) {
122123
EXPECT_TRUE(map1.isEqual(map3));
123124
}
124125
}
126+
127+
TEST(IntegerRelationTest, symbolicLexmin) {
128+
SymbolicLexMin lexmin =
129+
parseRelationFromSet("(a, x)[b] : (x - a >= 0, x - b >= 0)", 1)
130+
.findSymbolicIntegerLexMin();
131+
132+
PWMAFunction expectedLexmin =
133+
parsePWMAF(/*numInputs=*/2,
134+
/*numOutputs=*/1,
135+
{
136+
{"(a)[b] : (a - b >= 0)", {{1, 0, 0}}}, // a
137+
{"(a)[b] : (b - a - 1 >= 0)", {{0, 1, 0}}}, // b
138+
},
139+
/*numSymbols=*/1);
140+
EXPECT_TRUE(lexmin.unboundedDomain.isIntegerEmpty());
141+
EXPECT_TRUE(lexmin.lexmin.isEqual(expectedLexmin));
142+
}

mlir/unittests/Analysis/Presburger/Utils.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "mlir/Analysis/Presburger/IntegerRelation.h"
1818
#include "mlir/Analysis/Presburger/PWMAFunction.h"
1919
#include "mlir/Analysis/Presburger/PresburgerRelation.h"
20+
#include "mlir/Analysis/Presburger/Simplex.h"
2021
#include "mlir/IR/MLIRContext.h"
2122
#include "mlir/Support/LLVM.h"
2223

@@ -40,9 +41,10 @@ inline IntegerPolyhedron parsePoly(StringRef str) {
4041
/// are all valid IntegerSet representation and that all of them have the same
4142
/// number of dimensions as is specified by the numDims argument.
4243
inline PresburgerSet
43-
parsePresburgerSetFromPolyStrings(unsigned numDims, ArrayRef<StringRef> strs) {
44-
PresburgerSet set =
45-
PresburgerSet::getEmpty(PresburgerSpace::getSetSpace(numDims));
44+
parsePresburgerSetFromPolyStrings(unsigned numDims, ArrayRef<StringRef> strs,
45+
unsigned numSymbols = 0) {
46+
PresburgerSet set = PresburgerSet::getEmpty(
47+
PresburgerSpace::getSetSpace(numDims, numSymbols));
4648
for (StringRef str : strs)
4749
set.unionInPlace(parsePoly(str));
4850
return set;
@@ -71,9 +73,9 @@ inline PWMAFunction parsePWMAF(
7173
unsigned numSymbols = 0) {
7274
static MLIRContext context;
7375

74-
PWMAFunction result(
75-
PresburgerSpace::getSetSpace(numInputs - numSymbols, numSymbols),
76-
numOutputs);
76+
PWMAFunction result(PresburgerSpace::getSetSpace(
77+
/*numDims=*/numInputs - numSymbols, numSymbols),
78+
numOutputs);
7779
for (const auto &pair : data) {
7880
IntegerPolyhedron domain = parsePoly(pair.first);
7981

0 commit comments

Comments
 (0)