11package liquidjava .rj_language .opt ;
22
3+ import static liquidjava .rj_language .opt .VCSimplificationUtils .containsVar ;
34import static liquidjava .rj_language .opt .VCSimplificationUtils .copyWithRefinement ;
45import static liquidjava .rj_language .opt .VCSimplificationUtils .isTrue ;
56
67import liquidjava .processor .VCImplication ;
78import liquidjava .processor .context .Context ;
89import liquidjava .rj_language .Predicate ;
9- import liquidjava .rj_language .ast .LiteralBoolean ;
1010import liquidjava .smt .SMTEvaluator ;
1111import liquidjava .smt .SMTResult ;
1212
1313/**
14- * Simplifies antecedent constraints that are implied by stronger constraints later in the VC chain
14+ * Removes antecedent constraints that are implied by another antecedent
1515 */
1616public class VCConstraintSimplification implements VCSimplificationPass {
1717
@@ -26,51 +26,73 @@ public VCImplication apply(VCImplication implication) {
2626 }
2727
2828 /**
29- * Simplifies the first antecedent implied by a later antecedent
29+ * Removes the first antecedent implied by another antecedent
3030 */
3131 private VCImplication simplify (VCImplication implication ) {
32- if (implication == null || implication .getNext () == null )
33- return null ;
32+ for (VCImplication redundant = implication ; redundant .getNext () != null ; redundant = redundant .getNext ()) {
33+ if (isTrue (redundant .getRefinement ().getExpression ()))
34+ continue ;
3435
35- if (!isTrue (implication .getRefinement ().getExpression ())) { // skip trivial constraints
36- VCImplication implying = findImplyingAntecedent (implication );
37- if (implying != null )
38- return simplifyConstraint (implication );
36+ for (VCImplication stronger = implication ; stronger .getNext () != null ; stronger = stronger .getNext ()) {
37+ if (stronger != redundant && canEliminate (implication , stronger , redundant )
38+ && implies (stronger .getRefinement (), redundant .getRefinement ()))
39+ return eliminate (implication , stronger , redundant );
40+ }
3941 }
42+ return null ;
43+ }
4044
41- // continue searching for simplifications in the suffix
42- VCImplication next = simplify (implication .getNext ());
43- if (next == null )
44- return null ;
45+ /**
46+ * Checks whether either node can be removed while preserving required binders
47+ */
48+ private boolean canEliminate (VCImplication implication , VCImplication stronger , VCImplication redundant ) {
49+ return isRemovable (implication , redundant ) || isRelocatable (implication , stronger );
50+ }
4551
46- VCImplication result = copyWithRefinement (implication , implication .getRefinement ().clone ());
47- result .setNext (next );
48- return result ;
52+ /**
53+ * Removes the redundant node, or moves the stronger refinement onto its required binder and removes the stronger
54+ * node
55+ */
56+ private VCImplication eliminate (VCImplication implication , VCImplication stronger , VCImplication redundant ) {
57+ if (isRemovable (implication , redundant ))
58+ return rewrite (implication , redundant , null , null );
59+ return rewrite (implication , stronger , redundant , stronger .getRefinement ());
4960 }
5061
5162 /**
52- * Finds a later antecedent that implies the current constraint. The final node is the conclusion and is not a
53- * candidate
63+ * Checks whether removing a node also removes every use of its binder
5464 */
55- private VCImplication findImplyingAntecedent (VCImplication implication ) {
56- for ( VCImplication candidate = implication . getNext (); candidate != null
57- && candidate . getNext () != null ; candidate = candidate . getNext ()) {
58- // ∀x. x > 0 => x > 1 -> ∀x. true => x > 1
59- if ( implies ( candidate . getRefinement (), implication . getRefinement () ))
60- return candidate ;
61- }
62- return null ;
65+ private boolean isRemovable (VCImplication implication , VCImplication node ) {
66+ if (! node . hasBinder ())
67+ return true ;
68+
69+ for ( VCImplication current = implication ; current != null ; current = current . getNext ( ))
70+ if ( current != node && containsVar ( current . getRefinement (). getExpression (), node . getName ()))
71+ return false ;
72+ return true ;
6373 }
6474
6575 /**
66- * Simplifies a redundant constraint to true
76+ * Checks whether a node can be removed while retaining its refinement elsewhere
6777 */
68- private VCImplication simplifyConstraint (VCImplication implication ) {
69- if (!implication .hasBinder ())
70- return implication .getNext ().clone ();
78+ private boolean isRelocatable (VCImplication implication , VCImplication node ) {
79+ return isRemovable (implication , node )
80+ && (!node .hasBinder () || !containsVar (node .getRefinement ().getExpression (), node .getName ()));
81+ }
82+
83+ /**
84+ * Clones a chain while removing one node and optionally replacing another node's refinement
85+ */
86+ private VCImplication rewrite (VCImplication implication , VCImplication removed , VCImplication replaced ,
87+ Predicate replacement ) {
88+ if (implication == null )
89+ return null ;
90+ if (implication == removed )
91+ return rewrite (implication .getNext (), removed , replaced , replacement );
7192
72- VCImplication result = copyWithRefinement (implication , new Predicate (new LiteralBoolean (true )));
73- result .setNext (implication .getNext ().clone ());
93+ Predicate refinement = implication == replaced ? replacement .clone () : implication .getRefinement ().clone ();
94+ VCImplication result = copyWithRefinement (implication , refinement );
95+ result .setNext (rewrite (implication .getNext (), removed , replaced , replacement ));
7496 return result ;
7597 }
7698
0 commit comments