001// ***** This file is automatically generated from SeqIndexComparison.java.jpp 002 003package daikon.inv.unary.sequence; 004 005import daikon.*; 006import daikon.Quantify.QuantFlags; 007import daikon.inv.*; 008import daikon.inv.binary.twoSequence.*; 009import daikon.suppress.*; 010import java.util.Arrays; 011import java.util.Iterator; 012import java.util.logging.Logger; 013import org.checkerframework.checker.interning.qual.Interned; 014import org.checkerframework.checker.lock.qual.GuardSatisfied; 015import org.checkerframework.checker.nullness.qual.NonNull; 016import org.checkerframework.checker.nullness.qual.Nullable; 017import org.checkerframework.dataflow.qual.Pure; 018import org.checkerframework.dataflow.qual.SideEffectFree; 019import org.plumelib.util.Intern; 020import typequals.prototype.qual.NonPrototype; 021import typequals.prototype.qual.Prototype; 022 023/** 024 * Represents an invariant over sequences of long values between the index of an element of the 025 * sequence and the element itself. Prints as {@code x[i] != i}. 026 */ 027public class SeqIndexIntNonEqual extends SingleScalarSequence { 028 // We are Serializable, so we specify a version to allow changes to 029 // method signatures without breaking serialization. If you add or 030 // remove fields, you should change this number to the current date. 031 static final long serialVersionUID = 20040203L; 032 033 /** Debug tracer. */ 034 public static final Logger debug = 035 Logger.getLogger("daikon.inv.unary.sequence.SeqIndexIntNonEqual"); 036 037 // Variables starting with dkconfig_ should only be set via the 038 // daikon.config.Configuration interface. 039 /** Boolean. True iff SeqIndexIntNonEqual invariants should be considered. */ 040 public static boolean dkconfig_enabled = false; 041 042 private @Prototype SeqIndexIntNonEqual() { 043 super(); 044 } 045 046 protected SeqIndexIntNonEqual(PptSlice slice) { 047 super(slice); 048 assert slice != null; 049 assert var().rep_type == ProglangType.INT_ARRAY; 050 } 051 052 private static @Prototype SeqIndexIntNonEqual proto = new @Prototype SeqIndexIntNonEqual(); 053 054 /** Returns the prototype invariant for SeqIndexIntNonEqual */ 055 public static @Prototype SeqIndexIntNonEqual get_proto() { 056 return proto; 057 } 058 059 /** returns whether or not we are enabled */ 060 @Override 061 public boolean enabled() { 062 return dkconfig_enabled && !dkconfig_SeqIndexDisableAll; 063 } 064 065 /** Check that SeqIndex comparisons make sense over these vars. */ 066 @Override 067 public boolean instantiate_ok(VarInfo[] vis) { 068 069 if (!valid_types(vis)) { 070 return false; 071 } 072 073 // Don't compare indices to object addresses. 074 ProglangType elt_type = vis[0].file_rep_type.elementType(); 075 if (!elt_type.baseIsIntegral()) { 076 return false; 077 } 078 079 // Make sure that the indices are comparable to the elements 080 VarInfo seqvar = vis[0]; 081 assert seqvar.comparability != null; 082 VarComparability elt_compar = seqvar.comparability.elementType(); 083 VarComparability index_compar = seqvar.comparability.indexType(0); 084 if (!VarComparability.comparable(elt_compar, index_compar)) { 085 return false; 086 } 087 088 return true; 089 } 090 091 /** Instantiate the invariant on the specified slice. */ 092 @Override 093 public SeqIndexIntNonEqual instantiate_dyn(@Prototype SeqIndexIntNonEqual this, PptSlice slice) { 094 return new SeqIndexIntNonEqual(slice); 095 } 096 097 /** returns the ni-suppressions for SeqIndexIntNonEqual */ 098 @Pure 099 @Override 100 public @Nullable NISuppressionSet get_ni_suppressions() { 101 return null; 102 } 103 104 protected Invariant resurrect_done_swapped() { 105 106 return this; 107 } 108 109 public String getComparator() { 110 return "!="; 111 } 112 113 @SideEffectFree 114 @Override 115 public String format_using(@GuardSatisfied SeqIndexIntNonEqual this, OutputFormat format) { 116 if (format.isJavaFamily()) { 117 return format_java_family(format); 118 } 119 120 // TODO: Eliminate the unnecessary format_xxx() below if the 121 // format_java_family() can handle all the Java family output. 122 123 if (format == OutputFormat.DAIKON) { 124 return format_daikon(); 125 } 126 if (format == OutputFormat.ESCJAVA) { 127 return format_esc(); 128 } 129 if (format == OutputFormat.CSHARPCONTRACT) { 130 return format_csharp_contract(); 131 } 132 if (format == OutputFormat.SIMPLIFY) { 133 return format_simplify(); 134 } 135 136 return format_unimplemented(format); 137 } 138 139 public String format_daikon(@GuardSatisfied SeqIndexIntNonEqual this) { 140 141 // If this is an array/container and not a subsequence 142 if (var().isDerivedSubSequenceOf() == null) { 143 return var().apply_subscript("i") + " != i"; 144 } else { 145 return var().name() + " != (index)"; 146 } 147 } 148 149 // Bad code here: if the first index is changed from i this breaks 150 public String format_esc(@GuardSatisfied SeqIndexIntNonEqual this) { 151 String[] form = VarInfo.esc_quantify(var()); 152 return form[0] + "(" + form[1] + " != i)" + form[2]; 153 } 154 155 public String format_csharp_contract(@GuardSatisfied SeqIndexIntNonEqual this) { 156 String[] split = var().csharp_array_split(); 157 return "Contract.ForAll(0, " + split[0] + ".Count(), i => " + split[0] + "[i]" + split[1] + " != i)"; 158 } 159 160 public String format_java_family(@GuardSatisfied SeqIndexIntNonEqual this, OutputFormat format) { 161 return "daikon.Quant.eltsNotEqualIndex(" 162 + var().name_using(format) + ")"; 163 } 164 165 public String format_simplify(@GuardSatisfied SeqIndexIntNonEqual this) { 166 String[] form = VarInfo.simplify_quantify(QuantFlags.include_index(), 167 var()); 168 return form[0] + "(NEQ " + form[1] + " " + form[2] + ")" 169 + form[3]; 170 } 171 172 @Override 173 public InvariantStatus check_modified(long @Interned [] a, int count) { 174 for (int i = 0; i < a.length; i++) { 175 if (!(a[i] != i)) { 176 return InvariantStatus.FALSIFIED; 177 } 178 } 179 return InvariantStatus.NO_CHANGE; 180 } 181 182 @Override 183 public InvariantStatus add_modified(long @Interned [] a, int count) { 184 185 if (logDetail()) { 186 log("Entered add_modified: ppt.num_values()==%s, sample==%s", 187 ppt.num_values(), Arrays.toString(a)); 188 } 189 InvariantStatus stat = check_modified(a, count); 190 if (logDetail()) { 191 log("Exiting add_modified status = %s", stat); 192 } 193 194 return stat; 195 } 196 197 @Override 198 @SuppressWarnings("UnnecessaryParentheses") // generated code, parentheses are sometimes needed 199 protected double computeConfidence() { 200 201 // Make sure there have been some elements in the sequence 202 ValueSet.ValueSetScalarArray vs = (ValueSet.ValueSetScalarArray) ppt.var_infos[0].get_value_set(); 203 if (vs.elem_cnt() == 0) { 204 return Invariant.CONFIDENCE_UNJUSTIFIED; 205 } 206 207 int num_values = ppt.num_values(); 208 if (num_values == 0) { 209 return Invariant.CONFIDENCE_UNJUSTIFIED; 210 } 211 212 int max_indx = vs.max_length() - 1; 213 if ((vs.min() > max_indx) || (vs.max() < 0)) { 214 return Invariant.CONFIDENCE_UNJUSTIFIED; 215 } else { 216 long overlap = (Math.min(vs.max(), max_indx) - Math.max(vs.min(), 0)); 217 218 if (overlap < 0) { 219 return Invariant.CONFIDENCE_UNJUSTIFIED; 220 } 221 overlap++; 222 double range1 = (double)max_indx + 1; 223 double range2 = (double)(vs.max()) - vs.min() + 1; 224 225 // probability of being equal by chance 226 // = (overlap/range1) * (overlap/range2) * (1/overlap) 227 // = overlap/(range1 * range2) 228 229 double confidence_one_nonequal = ((double)overlap)/(range1 * range2); 230 231 // The factor of 2 is a hack, but this seems too stringent otherwise 232 confidence_one_nonequal = Math.min(1.0, 2.0 * confidence_one_nonequal); 233 234 assert ! Double.isNaN(confidence_one_nonequal) 235 && confidence_one_nonequal >= 0 236 && confidence_one_nonequal <= 1 237 : "overlap=" + overlap 238 + ", range1=" + range1 239 + ", range2=" + range2 240 ; 241 return 1 - Math.pow(1 - confidence_one_nonequal, vs.elem_cnt()); 242 } 243 244 } 245 246 @Pure 247 @Override 248 public boolean isSameFormula(Invariant other) { 249 return true; 250 } 251 252 @Pure 253 @Override 254 public boolean isExclusiveFormula(Invariant other) { 255 return false; 256 } 257 258 // Look up a previously instantiated invariant. 259 public static @Nullable SeqIndexIntNonEqual find(PptSlice ppt) { 260 assert ppt.arity() == 1; 261 for (Invariant inv : ppt.invs) { 262 if (inv instanceof SeqIndexIntNonEqual) { 263 return (SeqIndexIntNonEqual) inv; 264 } 265 } 266 return null; 267 } 268 269 /** 270 * Checks to see if this is obvious over the specified variables Implements the following checks: 271 * 272 * <pre> 273 * (A[] subsequence B[]) ^ (B[i] op i) ⇒ A[i] op i 274 * </pre> 275 * 276 * JHP: Its not obvious (to me) that this is true except when the subsequence starts at index 277 * 0. If B[] = {0, 1, 2, 3, 4} and A[] = {2, 3, 4}, A[] is a subsequence of B[] and B[i] == i, but 278 * A[i] = i is not true. 279 */ 280 @Pure 281 @Override 282 public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) { 283 284 DiscardInfo super_result = super.isObviousDynamically(vis); 285 if (super_result != null) { 286 return super_result; 287 } 288 289 VarInfo seqvar = vis[0]; 290 291 // For each other sequence variable, if it is a supersequence of this 292 // one and it has the same invariant, then this one is obvious. 293 // We have to check for the same equality set here, because 294 // isObviousDynamically is called for each member of the equality set. 295 // We don't want other members of our own equality set to make this obvious 296 PptTopLevel pptt = ppt.parent; 297 for (int i = 0; i < pptt.var_infos.length; i++) { 298 VarInfo vi = pptt.var_infos[i]; 299 if (vi.equalitySet == seqvar.equalitySet) { 300 continue; 301 } 302 if (SubSequence.isObviousSubSequenceDynamically(this, seqvar, vi)) { 303 PptSlice1 other_slice = pptt.findSlice(vi); 304 if (other_slice != null) { 305 SeqIndexIntNonEqual other_sine = SeqIndexIntNonEqual.find(other_slice); 306 if ((other_sine != null) && other_sine.enoughSamples()) { 307 return new DiscardInfo(this, DiscardCode.obvious, 308 "The invariant " + format() + " over var " 309 + seqvar.name() + " also holds over " 310 +" the supersequence " + vi.name()); 311 } 312 } 313 } 314 } 315 316 return null; 317 } 318}