Skip to content

Commit 22d2d3b

Browse files
committed
fuzzyAnd, and make it drop new ones automatically, as suggested
1 parent e4a2a49 commit 22d2d3b

3 files changed

Lines changed: 61 additions & 23 deletions

File tree

src/ir/constraint.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,17 @@ Result AndedConstraintSet::proves(const AndedConstraintSet& other) const {
113113
return hasUnknown ? Unknown : True;
114114
}
115115

116+
void AndedConstraintSet::fuzzyAnd(const Constraint& c) {
117+
if (size() < MaxConstraints) {
118+
push_back(c);
119+
return;
120+
}
121+
122+
// Otherwise, just do not add this one.
123+
// TODO: We could try to be clever and see if one of the existing ones makes
124+
// more sense to drop.
125+
}
126+
116127
void AndedConstraintSet::fuzzyOr(const AndedConstraintSet& other) {
117128
// If one is empty (no constraints, everything is true, and we can prove
118129
// nothing useful) then it does not add anything to the other.

src/ir/constraint.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,12 @@ struct AndedConstraintSet : inplace_vector<Constraint, MaxConstraints> {
7171
// Check an entire other set.
7272
Result proves(const AndedConstraintSet& other) const;
7373

74-
bool full() const { return size() == MaxConstraints; }
75-
76-
// Add a constraint to the set, ANDed with the others. The caller must make
77-
// sure not to add too many (i.e. it is invalid to call this when full()).
78-
void and_(const Constraint& c) {
79-
assert(!full());
80-
push_back(c);
81-
}
74+
// Add a constraint to the set, ANDed with the others. This is a fuzzy
75+
// operation because our capacity is bounded - we cannot have more than
76+
// MaxConstraints. If too many are added, we will drop some, which means we
77+
// will be able to prove less things (but we will never prove anything
78+
// incorrectly).
79+
void fuzzyAnd(const Constraint& c);
8280

8381
// Merge constraints using OR. We cannot represent such a thing directly
8482
// (we only use AND), so we approximate it in a fuzzy way. For example, this

test/gtest/constraint.cpp

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ TEST(ConstraintTest, TestEq) {
1919
EXPECT_EQ(s.proves(c), Unknown);
2020

2121
// If we add it, then things check out: a thing always proves itself true.
22-
s.and_(c);
22+
s.fuzzyAnd(c);
2323
EXPECT_EQ(s.size(), 1);
2424
EXPECT_EQ(s.proves(c), True);
2525

@@ -37,7 +37,7 @@ TEST(ConstraintTest, TestNe) {
3737
AndedConstraintSet s;
3838
// x != 5
3939
Constraint c{Ne, {Literal(int32_t(5))}};
40-
s.and_(c);
40+
s.fuzzyAnd(c);
4141

4242
// Checks out versus itself.
4343
EXPECT_EQ(s.proves(c), True);
@@ -57,8 +57,8 @@ TEST(ConstraintTest, TestMulti) {
5757
// x != 5 && x != 10
5858
Constraint c{Ne, {Literal(int32_t(5))}};
5959
Constraint d{Ne, {Literal(int32_t(10))}};
60-
s.and_(c);
61-
s.and_(d);
60+
s.fuzzyAnd(c);
61+
s.fuzzyAnd(d);
6262

6363
// Each checks out versus itself.
6464
EXPECT_EQ(s.proves(c), True);
@@ -87,7 +87,7 @@ TEST(ConstraintTest, TestSets) {
8787
EXPECT_EQ(s.proves(s), True);
8888

8989
// Ditto after adding something.
90-
s.and_(c);
90+
s.fuzzyAnd(c);
9191
EXPECT_EQ(s.proves(s), True);
9292

9393
// Another set, empty.
@@ -97,17 +97,17 @@ TEST(ConstraintTest, TestSets) {
9797
EXPECT_EQ(s.proves(t), True);
9898

9999
// Make both sets contain the same stuff.
100-
t.and_(c);
100+
t.fuzzyAnd(c);
101101
EXPECT_EQ(s.proves(t), True);
102102

103103
// Now t has *different* stuff, x == 10, which given s is false.
104104
t.clear();
105-
t.and_(Constraint{Eq, {Literal(int32_t(10))}});
105+
t.fuzzyAnd(Constraint{Eq, {Literal(int32_t(10))}});
106106
EXPECT_EQ(s.proves(t), False);
107107

108108
// Same, with x != 10. Now we know it is true.
109109
t.clear();
110-
t.and_(Constraint{Ne, {Literal(int32_t(10))}});
110+
t.fuzzyAnd(Constraint{Ne, {Literal(int32_t(10))}});
111111
EXPECT_EQ(s.proves(t), True);
112112

113113
// In reverse, we can infer nothing: knowing x != 10 does not say if x == 5.
@@ -118,23 +118,23 @@ TEST(ConstraintTest, TestSetsUnknown) {
118118
// x != 5
119119
// x != 10
120120
AndedConstraintSet s;
121-
s.and_(Constraint{Ne, {Literal(int32_t(5))}});
122-
s.and_(Constraint{Ne, {Literal(int32_t(10))}});
121+
s.fuzzyAnd(Constraint{Ne, {Literal(int32_t(5))}});
122+
s.fuzzyAnd(Constraint{Ne, {Literal(int32_t(10))}});
123123

124124
// x != 20, which is unknown by s.
125125
AndedConstraintSet t;
126-
t.and_(Constraint{Ne, {Literal(int32_t(20))}});
126+
t.fuzzyAnd(Constraint{Ne, {Literal(int32_t(20))}});
127127
EXPECT_EQ(s.proves(t), Unknown);
128128

129129
// Add x == 10, which is false by s, and so the whole thing is false.
130-
t.and_(Constraint{Eq, {Literal(int32_t(10))}});
130+
t.fuzzyAnd(Constraint{Eq, {Literal(int32_t(10))}});
131131
EXPECT_EQ(s.proves(t), False);
132132
}
133133

134134
TEST(ConstraintTest, TestOrTrivial) {
135135
// { x == 5 }
136136
AndedConstraintSet s;
137-
s.and_(Constraint{Eq, {Literal(int32_t(5))}});
137+
s.fuzzyAnd(Constraint{Eq, {Literal(int32_t(5))}});
138138

139139
// { }
140140
AndedConstraintSet empty;
@@ -158,11 +158,11 @@ TEST(ConstraintTest, TestOrTrivial) {
158158
TEST(ConstraintTest, TestOrImplies) {
159159
// { x == 5 }
160160
AndedConstraintSet s;
161-
s.and_(Constraint{Eq, {Literal(int32_t(5))}});
161+
s.fuzzyAnd(Constraint{Eq, {Literal(int32_t(5))}});
162162

163163
// { x != 10 }
164164
AndedConstraintSet t;
165-
t.and_(Constraint{Ne, {Literal(int32_t(10))}});
165+
t.fuzzyAnd(Constraint{Ne, {Literal(int32_t(10))}});
166166

167167
// ORing these leaves us with x != 10.
168168
auto u = s;
@@ -175,5 +175,34 @@ TEST(ConstraintTest, TestOrImplies) {
175175
EXPECT_EQ(u, t);
176176
}
177177

178+
TEST(ConstraintTest, TestMaxCapacity) {
179+
EXPECT_EQ(MaxConstraints, 3);
180+
181+
// Max out with x != 10, 20, 30
182+
Constraint not10{Ne, {Literal(int32_t(10))}};
183+
Constraint not20{Ne, {Literal(int32_t(20))}};
184+
Constraint not30{Ne, {Literal(int32_t(30))}};
185+
186+
AndedConstraintSet s;
187+
s.fuzzyAnd(not10);
188+
s.fuzzyAnd(not20);
189+
s.fuzzyAnd(not30);
190+
191+
// We can prove all those.
192+
EXPECT_EQ(s.proves(not10), True);
193+
EXPECT_EQ(s.proves(not20), True);
194+
EXPECT_EQ(s.proves(not30), True);
195+
196+
// Add another, exceeding the capacity.
197+
Constraint not40{Ne, {Literal(int32_t(40))}};
198+
s.fuzzyAnd(not40);
199+
200+
// We can prove the old ones but not the new.
201+
EXPECT_EQ(s.proves(not10), True);
202+
EXPECT_EQ(s.proves(not20), True);
203+
EXPECT_EQ(s.proves(not30), True);
204+
EXPECT_EQ(s.proves(not40), Unknown);
205+
}
206+
178207
// TODO: test a fuzzyOr of { x = 10 } and { x >= 0 }, once we support
179208
// inequalities

0 commit comments

Comments
 (0)