001package daikon.simplify;
002
003import daikon.inv.Invariant;
004import java.util.ArrayList;
005import java.util.List;
006import org.checkerframework.checker.lock.qual.GuardSatisfied;
007import org.checkerframework.checker.nullness.qual.Nullable;
008import org.checkerframework.dataflow.qual.Pure;
009
010/**
011 * A lemma is an object that wraps a Simplify formula representing some logical statement. The only
012 * other thing it adds is a short human-readable description, suitable for debugging.
013 *
014 * <p>Members of the Lemma class proper represent general theorems, which we give to Simplify as
015 * background, with hand-written descriptions.
016 */
017public class Lemma implements Comparable<Lemma> {
018  public String summary;
019  public String formula;
020
021  public Lemma(String summary, String formula) {
022    this.summary = summary;
023    this.formula = formula;
024  }
025
026  /** Return a human-readable description. */
027  public String summarize(@GuardSatisfied Lemma this) {
028    return summary;
029  }
030
031  /** If this lemma came from an invariant, get its class. */
032  public @Nullable Class<? extends Invariant> invClass() {
033    return null;
034  }
035
036  @Pure
037  @Override
038  public int compareTo(@GuardSatisfied Lemma this, Lemma other) {
039    return summarize().compareTo(other.summarize());
040  }
041
042  /** Convenience function to give you lemmas[], but as a vector. */
043  public static List<Lemma> lemmasList() {
044    List<Lemma> v = new ArrayList<>();
045    for (int i = 0; i < lemmas.length; i++) {
046      v.add(lemmas[i]);
047    }
048    return v;
049  }
050
051  /**
052   * All the theorems we give Simplify (without proof) to help it reason about predicates,
053   * functions, and constants that aren't built-in.
054   */
055  public static Lemma[] lemmas = {
056    new Lemma("null has type T_null", "(EQ (typeof null) |T_null|)"),
057    new Lemma(
058        "objects with null hashes have type T_null",
059        "(FORALL (x) (IMPLIES (EQ (hash x) null) (EQ (typeof x) |T_null|)))"),
060    new Lemma(
061        "hashcodes other than 0 are not null",
062        "(FORALL (x) (IMPLIES (NEQ x 0) (NEQ (hashcode x) null)))"),
063    new Lemma("'this' is always unchanged", "(EQ (hash |this|) (hash |__orig__this|))"),
064    new Lemma("arrayLength is non-negative", "(FORALL (a) (>= (arrayLength a) 0))"),
065    new Lemma("true != false", "(NEQ |@true| |@false|)"),
066    new Lemma(
067        "definition of lexical-> in terms of lexical-<",
068        "(FORALL (a i j b ip jp) (IFF (|lexical->| a i j b ip jp) (|lexical-<| b ip jp a i j)))"),
069    new Lemma(
070        "definition of lexical-==",
071        "(FORALL (a i j b ip jp) (IFF (|lexical-==| a i j b ip jp) (AND (EQ (- j i) (- jp ip)) (<="
072            + " 0 i) (< j (arrayLength a)) (<= 0 ip) (< jp (arrayLength b)) (FORALL (x xp)"
073            + " (IMPLIES (AND (<= i x) (<= x j) (<= ip xp) (<= xp jp) (EQ (- x i) (- xp ip))) (EQ"
074            + " (select (select elems a) x) (select (select elems b) xp)))))))"),
075    new Lemma(
076        "definition of lexical-<= as a disjunction",
077        "(FORALL (a i j b ip jp) (IFF (|lexical-<=| a i j b ip jp) (OR (|lexical-<| a i j b ip jp)"
078            + " (|lexical-==| a i j b ip jp))))"),
079    new Lemma(
080        "definition of lexical->= as a disjunction",
081        "(FORALL (a i j b ip jp) (IFF (|lexical->=| a i j b ip jp) (OR (|lexical->| a i j b ip jp)"
082            + " (|lexical-==| a i j b ip jp))))"),
083    new Lemma(
084        "definition of lexical-!= as a negation",
085        "(FORALL (a i j b ip jp) (IFF (|lexical-!=| a i j b ip jp) (NOT (|lexical-==| a i j b ip"
086            + " jp))))"),
087    new Lemma(
088        "simplify lexical-== with matching bounds",
089        "(FORALL (a i j b ip jp) (IMPLIES (AND (|lexical-==| a i j b ip jp) (EQ i ip) (EQ j jp))"
090            + " (FORALL (x) (IMPLIES (AND (<= i x) (<= x j)) (EQ (select (select elems a) x)"
091            + " (select (select elems b) x))))))"),
092    new Lemma(
093        "lexical comparison with a matching prefix (general)",
094        "(FORALL (a i j k b ip jp kp) (IMPLIES (AND (<= i k) (<= ip kp) (< k j) (< kp jp)"
095            + " (|lexical-==| a i k b ip kp)) (IFF (|lexical-<| a i j b ip jp)(|lexical-<| a (+ k"
096            + " 1) j b (+ kp 1) jp))))"),
097    new Lemma(
098        "lexical->= comparison to a singleton sequence",
099        "(FORALL (a i j b ip) (IMPLIES (AND (EQ (select (select elems a) i) (select (select elems"
100            + " b) ip)) (>= j (+ i 1))) (|lexical->=| a i j b ip ip)))"),
101    new Lemma(
102        "lexical-> comparison to a singleton sequence",
103        "(FORALL (a i j b ip) (IMPLIES (AND (EQ (select (select elems a) i) (select (select elems"
104            + " b) ip)) (> j (+ i 1))) (|lexical->| a i j b ip ip)))"),
105    new Lemma(
106        "lexical-== comparison to a singleton sequence",
107        "(FORALL (a i j b ip) (IMPLIES (AND (EQ (select (select elems a) i) (select (select elems"
108            + " b) ip)) (> j (+ i 1))) (|lexical-==| a i j b ip ip)))"),
109    new Lemma(
110        "the empty sequence is less than any non-empty sequence",
111        "(FORALL (a i j b ip jp) (IMPLIES (AND (<= 0 i) (<= 0 ip) (< j (arrayLength a)) (< jp"
112            + " (arrayLength b)) (< j i) (>= jp ip)) (|lexical-<| a i j b ip jp)))"),
113    new Lemma(
114        "lexical comparison with matching prefix (one-way)",
115        "(FORALL (a i j k b ip jp kp) (IMPLIES (AND (<= i k) (<= ip kp) (< k j) (< kp jp)"
116            + " (|lexical-==| a i k b ip kp)) (IMPLIES (< (select (select elems a) (+ k 1))"
117            + " (select (select elems b) (+ kp 1))) (|lexical-<| a i j b ip jp))))"),
118    new Lemma(
119        "lexical comparison with matching prefix (one-way, reindexed)",
120        "(FORALL (a i j k b ip jp kp) (IMPLIES (AND (<= i k) (<= ip kp) (<= k j) (<= kp jp)"
121            + " (|lexical-==| a i (- k 1) b ip (- kp 1))) (IMPLIES (< (select (select elems a) k)"
122            + " (select (select elems b) kp))(|lexical-<| a i j b ip jp))))"),
123    new Lemma(
124        "lexical comparison with matching prefix (and matching indexes)",
125        "(FORALL (a i j b jp) (IMPLIES (AND (< i j) (<= j jp) (|lexical-==| a i (- j 1) b i (- j"
126            + " 1)) (< (select (select elems a) j) (select (select elems b) j))) (|lexical-<| a i"
127            + " j b i jp)))"),
128    // ;; (BG_PUSH
129    // ;;  (FORALL (a i j k b ip jp kp)
130    // ;;    (IMPLIES (AND (<= i k) (<= ip kp) (EQ k j) (< kp jp)
131    // ;;            (|lexical-==| a i k b ip kp))
132    // ;;       (|lexical-<| a i j b ip jp))))
133    //  A simplifed version of the above, specialized to matching indexes
134    new Lemma(
135        "comparison with a strict prefix (matching indexes)",
136        "(FORALL (a i j b jp) (IMPLIES (AND (< jp (arrayLength b)) (< j jp) (|lexical-==| a i j b"
137            + " i j)) (|lexical-<| a i j b i jp)))"),
138    new Lemma(
139        "lexical equality of singleton sequences",
140        "(FORALL (a i b ip) (IFF (|lexical-==| a i i b ip ip) (EQ (select (select elems a) i)"
141            + " (select (select elems b) ip))))"),
142    new Lemma(
143        "lexical-< of singleton sequences",
144        "(FORALL (a i b ip) (IFF (|lexical-<| a i i b ip ip) (< (select (select elems a) i)"
145            + " (select (select elems b) ip))))"),
146    new Lemma(
147        "lexical-< by < of initial elements",
148        "(FORALL (a i j b ip jp) (IMPLIES (AND (<= 0 i) (<= 0 ip) (<= i j) (<= ip jp) (< j"
149            + " (arrayLength a)) (< jp (arrayLength b)) (< (select (select elems a) i) (select"
150            + " (select elems b) ip))) (|lexical-<| a i j b ip jp)))"),
151    new Lemma(
152        "elementwise <= implies lexical-<=",
153        "(FORALL (a i j b ip jp) (IMPLIES (AND (EQ (- j i) (- jp ip)) (FORALL (x y) (IMPLIES (AND"
154            + " (<= i x) (<= x j)(<= ip y) (<= y jp) (EQ (- x i) (- y ip))) (<= (select (select"
155            + " elems a) x) (select (select elems b) y))))) (|lexical-<=| a i j b ip jp)))"),
156    new Lemma(
157        "definition of subsequence in terms of lexical-==",
158        "(FORALL (a start end b i j) (IFF (subsequence a start end b i j) (OR (EQ start (+ end 1))"
159            + " (EXISTS (ip jp) (AND (<= i ip) (<= ip jp) (<= jp j) (|lexical-==| a start end b ip"
160            + " jp))))))"),
161    new Lemma(
162        "definition of is-reverse-of",
163        "(FORALL (a i j b ip jp) (IFF (|is-reverse-of| a i j b ip jp) (AND (EQ (- j i) (- jp ip))"
164            + " (<= 0 i) (< j (arrayLength a)) (<= 0 ip) (< jp (arrayLength b)) (FORALL (x)"
165            + " (IMPLIES (AND (<= 0 x) (< x (- j i))) (EQ (select (select elems a) (+ i x))"
166            + " (select (select elems b) (- jp x))))))))"),
167    new Lemma(
168        "definition of subset",
169        "(FORALL (a i j b ip jp) (IFF (subset a i j b ip jp) (FORALL (x) (IMPLIES (AND (<= i x)"
170            + " (<= x j)) (EXISTS (y) (AND (<= ip y) (<= y jp) (EQ (select (select elems a) x)"
171            + " (select (select elems b) y))))))))"),
172    new Lemma(
173        "definition of && on integers (case when result is 1)",
174        "(FORALL (x y) (IFF (EQ (|java-&&| x y) 1) (AND (NEQ x 0) (NEQ y 0))))"),
175    new Lemma(
176        "definition of && on integers (case when result is 0)",
177        "(FORALL (x y) (IFF (EQ (|java-&&| x y) 0) (NOT (AND (NEQ x 0) (NEQ y 0)))))"),
178    new Lemma(
179        "definition of || on integers (case when result is 1)",
180        "(FORALL (x y) (IFF (EQ (|java-logical-or| x y) 1) (OR (NEQ x 0) (NEQ y 0))))"),
181    new Lemma(
182        "definition of || on integers (case when result is 0)",
183        "(FORALL (x y) (IFF (EQ (|java-logical-or| x y) 0) (NOT (OR (NEQ x 0) (NEQ y 0)))))"),
184    // Some of the following lemmas about MOD (the ones with PATS)
185    // were borrowed from the esc.ax file in the Simplify source
186    new Lemma(
187        "relation between DIV and MOD",
188        "(FORALL (x y) (PATS (DIV x y)) (EQ (+ (MOD x y) (* y (DIV x y))) x))"),
189    new Lemma(
190        "MOD with positive modulus is non-negative",
191        "(FORALL (x y) (PATS (MOD x y)) (IMPLIES (> y 0) (<= 0 (MOD x y))))"),
192    new Lemma(
193        "MOD with positive modulus m is < m",
194        "(FORALL (x y) (PATS (MOD x y)) (IMPLIES (> y 0) (< (MOD x y) y)))"),
195    new Lemma(
196        "MOD with negative modulus m is > m",
197        "(FORALL (x y) (PATS (MOD x y)) (IMPLIES (< y 0) (< y (MOD x y))))"),
198    new Lemma(
199        "MOD with negative modulus is non-positive",
200        "(FORALL (x y) (PATS (MOD x y)) (IMPLIES (< y 0) (<= (MOD x y) 0)))"),
201    new Lemma(
202        "Removing + m inside MOD m (on right)",
203        "(FORALL (x y) (PATS (MOD (+ x y) y)) (EQ (MOD (+ x y) y) (MOD x y)))"),
204    new Lemma(
205        "Removing + m inside MOD m (on left)",
206        "(FORALL (x y) (PATS (MOD (+ y x) y)) (EQ (MOD (+ y x) y) (MOD x y)))"),
207    new Lemma(
208        "Removing - m inside MOD m",
209        "(FORALL (x y) (PATS (MOD (- x y) y)) (EQ (MOD (+ y x) y) (MOD x y)))"),
210    new Lemma(
211        "When MOD by a positive modulus is the identity",
212        "(FORALL (m x) (IMPLIES (AND (> m 0) (>= x 0) (< x m)) (EQ (MOD x m) x)))"),
213    new Lemma(
214        "A sum is even iff the terms have the same parity",
215        "(FORALL (x y) (IFF (EQ (MOD (+ x y) 2) 0) (IFF (EQ (MOD x 2) 0) (EQ (MOD y 2) 0))))"),
216    new Lemma("-1 is odd", "(EQ (MOD -1 2) 1)"),
217    //     new Lemma("x | (x + 1) == x + 1 if x is even",
218    //       "(FORALL (x) (IMPLIES (EQ (MOD x 2) 0) (EQ (+ x 1) (|java-bitwise-or| x (+ x 1)))))"),
219    //     new Lemma("x & (x + 1) == x if x is even",
220    //               "(FORALL (x) (IMPLIES (EQ (MOD x 2) 0) (EQ x (|java-&| x (+ x 1)))))"),
221    // Facts about max and min, also from the Simplify source
222    new Lemma("max(a,b) >= a", "(FORALL (a b) (PATS (max a b)) (>= (max a b) a))"),
223    new Lemma("max(a,b) >= b", "(FORALL (a b) (PATS (max a b)) (>= (max a b) b))"),
224    new Lemma(
225        "max(a,b) is either a or b",
226        "(FORALL (a b) (PATS (max a b)) (OR (EQ (max a b) a) (EQ (max a b) b)))"),
227    new Lemma("min(a,b) <= a", "(FORALL (a b) (PATS (min a b)) (<= (min a b) a))"),
228    new Lemma("min(a,b) <= b", "(FORALL (a b) (PATS (min a b)) (<= (min a b) b))"),
229    new Lemma(
230        "min(a,b) is either a or b",
231        "(FORALL (a b) (PATS (min a b)) (OR (EQ (min a b) a) (EQ (min a b) b)))"),
232    new Lemma(
233        "m > 0 and 0 < x < m => x % m = x",
234        "(FORALL (m x) (IMPLIES (AND (> m 0) (< x m) (>= x (- 1 m))) (EQ (|java-%| x m) x)))"),
235  };
236}