Skip to content

Commit 921136a

Browse files
committed
Simplify Until Fixed Point
1 parent 9761ced commit 921136a

File tree

3 files changed

+58
-6
lines changed

3 files changed

+58
-6
lines changed

liquidjava-verifier/src/main/java/liquidjava/diagnostics/errors/RefinementError.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ public class RefinementError extends LJError {
1717

1818
public RefinementError(SourcePosition position, ValDerivationNode expected, ValDerivationNode found,
1919
TranslationTable translationTable) {
20-
super("Refinement Error",
21-
String.format("%s is not a subtype of %s", found.getValue(), expected.getValue()), position,
22-
translationTable);
20+
super("Refinement Error", String.format("%s is not a subtype of %s", found.getValue(), expected.getValue()),
21+
position, translationTable);
2322
this.expected = expected;
2423
this.found = found;
2524
}

liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ExpressionSimplifier.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,33 @@ public class ExpressionSimplifier {
1414
* Returns a derivation node representing the tree of simplifications applied
1515
*/
1616
public static ValDerivationNode simplify(Expression exp) {
17-
ValDerivationNode prop = ConstantPropagation.propagate(exp);
17+
ValDerivationNode fixedPoint = simplifyToFixedPoint(null, null, exp);
18+
return simplifyDerivationTree(fixedPoint);
19+
}
20+
21+
/**
22+
* Recursively applies propagation and folding until the expression stops changing (fixed point) Stops early if the
23+
* expression simplifies to 'true', which means we've simplified too much
24+
*/
25+
private static ValDerivationNode simplifyToFixedPoint(ValDerivationNode current, ValDerivationNode previous,
26+
Expression prevExp) {
27+
// apply propagation and folding
28+
ValDerivationNode prop = ConstantPropagation.propagate(prevExp);
1829
ValDerivationNode fold = ConstantFolding.fold(prop);
19-
return simplifyDerivationTree(fold);
30+
Expression currExp = fold.getValue();
31+
32+
// fixed point reached
33+
if (current != null && currExp.equals(current.getValue())) {
34+
return current;
35+
}
36+
37+
// stop if simplified to 'true'
38+
if (current != null && currExp instanceof LiteralBoolean && currExp.isBooleanTrue()) {
39+
return current;
40+
}
41+
42+
// continue simplifying
43+
return simplifyToFixedPoint(fold, current, fold.getValue());
2044
}
2145

2246
/**

liquidjava-verifier/src/test/java/liquidjava/rj_language/opt/ExpressionSimplifierTest.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ void testComplexArithmeticWithMultipleOperations() {
305305
}
306306

307307
@Test
308-
void testSingleEqualityNotSimplifiedToTrue() {
308+
void testSingleEqualityShouldNotSimplify() {
309309
// Given: x == 1
310310
// Expected: x == 1 (should not be simplified to "true")
311311

@@ -329,6 +329,35 @@ void testSingleEqualityNotSimplifiedToTrue() {
329329
assertEquals("1", resultExpr.getSecondOperand().toString(), "Right operand should be 1");
330330
}
331331

332+
@Test
333+
void testFixedPointSimplification() {
334+
// Given: x == -y && y == a / b && a == 6 && b == 3
335+
// Expected: x == -2
336+
Expression varX = new Var("x");
337+
Expression varY = new Var("y");
338+
Expression varA = new Var("a");
339+
Expression varB = new Var("b");
340+
341+
Expression aDivB = new BinaryExpression(varA, "/", varB);
342+
Expression yEqualsADivB = new BinaryExpression(varY, "==", aDivB);
343+
Expression negY = new UnaryExpression("-", varY);
344+
Expression xEqualsNegY = new BinaryExpression(varX, "==", negY);
345+
Expression six = new LiteralInt(6);
346+
Expression aEquals6 = new BinaryExpression(varA, "==", six);
347+
Expression three = new LiteralInt(3);
348+
Expression bEquals3 = new BinaryExpression(varB, "==", three);
349+
Expression firstAnd = new BinaryExpression(xEqualsNegY, "&&", yEqualsADivB);
350+
Expression secondAnd = new BinaryExpression(aEquals6, "&&", bEquals3);
351+
Expression fullExpression = new BinaryExpression(firstAnd, "&&", secondAnd);
352+
353+
// When
354+
ValDerivationNode result = ExpressionSimplifier.simplify(fullExpression);
355+
356+
// Then
357+
assertNotNull(result, "Result should not be null");
358+
assertEquals("x == -2", result.getValue().toString(), "Expected result to be x == -2");
359+
}
360+
332361
/**
333362
* Helper method to compare two derivation nodes recursively
334363
*/

0 commit comments

Comments
 (0)