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}