001// ***** This file is automatically generated from Bound.java.jpp 002 003package daikon.inv.unary.sequence; 004 005import daikon.*; 006import daikon.inv.*; 007 008 import daikon.inv.binary.twoSequence.*; 009 import daikon.inv.unary.scalar.*; 010 011import daikon.derive.unary.*; 012import daikon.inv.unary.*; 013import java.util.*; 014import org.checkerframework.checker.interning.qual.Interned; 015import org.checkerframework.checker.lock.qual.GuardSatisfied; 016import org.checkerframework.checker.nullness.qual.Nullable; 017import org.checkerframework.dataflow.qual.Pure; 018import org.checkerframework.dataflow.qual.SideEffectFree; 019import org.checkerframework.framework.qual.Unused; 020import org.plumelib.util.Intern; 021import typequals.prototype.qual.NonPrototype; 022import typequals.prototype.qual.Prototype; 023 024 /** 025 * Represents the invariant that each element of a sequence of double values is greater than or 026 * equal to a constant. Prints as {@code x[] elements >= c}. 027 */ 028 029// One reason not to combine LowerBound and UpperBound into a single range 030// invariant is that they have separate justifications: one may be 031// justified when the other is not. 032@SuppressWarnings("UnnecessaryParentheses") // code generated by macros 033public class EltLowerBoundFloat extends SingleFloatSequence { 034 // We are Serializable, so we specify a version to allow changes to 035 // method signatures without breaking serialization. If you add or 036 // remove fields, you should change this number to the current date. 037 static final long serialVersionUID = 20030822L; 038 039 // Variables starting with dkconfig_ should only be set via the 040 // daikon.config.Configuration interface. 041 /** Boolean. True iff EltLowerBoundFloat invariants should be considered. */ 042 public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault; 043 /** 044 * Long integer. Together with the corresponding {@code maximal_interesting} parameter, 045 * specifies the range of the computed constant that is ``interesting'' --- the range that should 046 * be reported. For instance, setting {@code minimal_interesting} to -1 and 047 * {@code maximal_interesting} to 2 would only permit output of EltLowerBoundFloat invariants whose 048 * cutoff was one of (-1,0,1,2). 049 */ 050 public static long dkconfig_minimal_interesting = -1; 051 /** 052 * Long integer. Together with the corresponding {@code minimal_interesting} parameter, 053 * specifies the range of the computed constant that is ``interesting'' --- the range that should 054 * be reported. For instance, setting {@code minimal_interesting} to -1 and 055 * {@code maximal_interesting} to 2 would only permit output of EltLowerBoundFloat invariants whose 056 * cutoff was one of (-1,0,1,2). 057 */ 058 public static long dkconfig_maximal_interesting = 2; 059 060 @Unused(when=Prototype.class) 061 private LowerBoundCoreFloat core; 062 063 @SuppressWarnings("nullness") // circular initialization 064 private EltLowerBoundFloat(PptSlice slice) { 065 super(slice); 066 assert slice != null; 067 core = new LowerBoundCoreFloat(this); 068 } 069 070 private @Prototype EltLowerBoundFloat() { 071 super(); 072 // do we need a core? 073 } 074 075 private static @Prototype EltLowerBoundFloat proto = new @Prototype EltLowerBoundFloat(); 076 077 /** Returns the prototype invariant for EltLowerBoundFloat */ 078 public static @Prototype EltLowerBoundFloat get_proto() { 079 return proto; 080 } 081 082 /** returns whether or not this invariant is enabled */ 083 @Override 084 public boolean enabled() { 085 return dkconfig_enabled; 086 } 087 088 /** EltLowerBoundFloat is only valid on integral types. */ 089 @Override 090 public boolean instantiate_ok(VarInfo[] vis) { 091 092 if (!valid_types(vis)) { 093 return false; 094 } 095 096 return vis[0].file_rep_type.baseIsFloat(); 097 } 098 099 /** instantiate an invariant on the specified slice */ 100 @Override 101 public EltLowerBoundFloat instantiate_dyn(@Prototype EltLowerBoundFloat this, PptSlice slice) { 102 return new EltLowerBoundFloat(slice); 103 } 104 105 @SideEffectFree 106 @Override 107 public EltLowerBoundFloat clone(@GuardSatisfied EltLowerBoundFloat this) { 108 EltLowerBoundFloat result = (EltLowerBoundFloat) super.clone(); 109 result.core = core.clone(); 110 result.core.wrapper = result; 111 return result; 112 } 113 114 public double min() { 115 return core.min(); // i.e., core.min1 116 } 117 118 @Override 119 public String repr(@GuardSatisfied EltLowerBoundFloat this) { 120 return "EltLowerBoundFloat" + varNames() + ": " 121 + core.repr(); 122 } 123 124 @SideEffectFree 125 @Override 126 public String format_using(@GuardSatisfied EltLowerBoundFloat this, OutputFormat format) { 127 128 if (format.isJavaFamily()) { 129 return format_java_family(format); 130 } 131 132 if (format == OutputFormat.DAIKON) { 133 return format_daikon(); 134 } else if (format == OutputFormat.SIMPLIFY) { 135 return format_simplify(); 136 } else if (format == OutputFormat.ESCJAVA) { 137 return format_esc(); 138 } else if (format == OutputFormat.CSHARPCONTRACT) { 139 return format_csharp_contract(); 140 } 141 142 return format_unimplemented(format); 143 } 144 // ELTLOWEr || ELTUPPEr 145 public String format_daikon(@GuardSatisfied EltLowerBoundFloat this) { 146 PptTopLevel pptt = ppt.parent; 147 String name = var().name(); 148 149 if (PrintInvariants.dkconfig_static_const_infer) { 150 for (VarInfo vi : pptt.var_infos) { 151 if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) { 152 // If variable is a double, then use fuzzy comparison 153 if (vi.rep_type == ProglangType.DOUBLE) { 154 Double constantVal = (Double)vi.constantValue(); 155 if (Global.fuzzy.eq(constantVal, (core.min1)) || (Double.isNaN(constantVal) && Double.isNaN( core.min1))) { 156 return name + " >= " + vi.name(); 157 } 158 } 159 // Otherwise just use the equals method 160 else { 161 Object constantVal = vi.constantValue(); 162 if (constantVal.equals(core.min1)) { 163 return name + " >= " + vi.name(); 164 } 165 } 166 } 167 } 168 } 169 170 return var().name() + " elements >= " + core.min1; 171 } 172 173 public String format_esc(@GuardSatisfied EltLowerBoundFloat this) { 174 PptTopLevel pptt = ppt.parent; 175 176 if (PrintInvariants.dkconfig_static_const_infer) { 177 for (VarInfo vi : pptt.var_infos) { 178 if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) { 179 // If variable is a double, then use fuzzy comparison 180 if (vi.rep_type == ProglangType.DOUBLE) { 181 Double constantVal = (Double)vi.constantValue(); 182 if (Global.fuzzy.eq(constantVal, (core.min1)) || (Double.isNaN(constantVal) && Double.isNaN( core.min1))) { 183 184 String[] form = VarInfo.esc_quantify(var()); 185 return form[0] + "(" + form[1] + " >= " + vi.name() + ")" + form[2]; 186 } 187 } 188 // Otherwise just use the equals method 189 else { 190 Object constantVal = vi.constantValue(); 191 if (constantVal.equals(core.min1)) { 192 193 String[] form = VarInfo.esc_quantify(var()); 194 return form[0] + "(" + form[1] + " >= " + vi.name() + ")" + form[2]; 195 } 196 } 197 } 198 } 199 } 200 201 String[] form = VarInfo.esc_quantify(var()); 202 return form[0] + "(" + form[1] + " >= " + core.min1 + ")" + form[2]; 203 } 204 205 public String format_csharp_contract(@GuardSatisfied EltLowerBoundFloat this) { 206 PptTopLevel pptt = ppt.parent; 207 208 if (PrintInvariants.dkconfig_static_const_infer) { 209 for (VarInfo vi : pptt.var_infos) { 210 if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) { 211 // If variable is a double, then use fuzzy comparison 212 if (vi.rep_type == ProglangType.DOUBLE) { 213 Double constantVal = (Double)vi.constantValue(); 214 if (Global.fuzzy.eq(constantVal, (core.min1)) || (Double.isNaN(constantVal) && Double.isNaN( core.min1))) { 215 216 String[] split = var().csharp_array_split(); 217 return "Contract.ForAll(" + split[0] + ", x => x" + split[1] + " >= " + vi.name() + ")"; 218 } 219 } 220 // Otherwise just use the equals method 221 else { 222 Object constantVal = vi.constantValue(); 223 if (constantVal.equals(core.min1)) { 224 225 String[] split = var().csharp_array_split(); 226 return "Contract.ForAll(" + split[0] + ", x => x" + split[1] + " >= " + vi.name() + ")"; 227 } 228 } 229 } 230 } 231 } 232 233 String[] split = var().csharp_array_split(); 234 return "Contract.ForAll(" + split[0] + ", x => x" + split[1] + " >= " + core.min1+ ")"; 235 } 236 237 public String format_java_family(@GuardSatisfied EltLowerBoundFloat this, OutputFormat format) { 238 PptTopLevel pptt = ppt.parent; 239 240 if (PrintInvariants.dkconfig_static_const_infer) { 241 for (VarInfo vi : pptt.var_infos) { 242 if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) { 243 // If variable is a double, then use fuzzy comparison 244 if (vi.rep_type == ProglangType.DOUBLE) { 245 Double constantVal = (Double)vi.constantValue(); 246 if (Global.fuzzy.eq(constantVal, (core.min1)) || (Double.isNaN(constantVal) && Double.isNaN( core.min1))) { 247 248 return "daikon.Quant.eltsGTE(" + var().name_using(format) + ", " + vi.name() + ")"; 249 } 250 } 251 // Otherwise just use the equals method 252 else { 253 Object constantVal = vi.constantValue(); 254 if (constantVal.equals(core.min1)) { 255 256 return "daikon.Quant.eltsGTE(" + var().name_using(format) + ", " + vi.name() + ")"; 257 } 258 } 259 } 260 } 261 } 262 263 return 264 "daikon.Quant.eltsGTE(" + var().name_using(format) + ", " + core.min1 + ")"; 265 266 } 267 268 public String format_simplify(@GuardSatisfied EltLowerBoundFloat this) { 269 270 String value = simplify_format_double(core.min1); 271 272 String[] form = VarInfo.simplify_quantify(var()); 273 return form[0] + "(>= " + form[1] + " " + value + ")" 274 + form[2]; 275 276 } 277 278 @Override 279 public InvariantStatus add_modified(double @Interned [] value, int count) { 280 // System.out.println("EltLowerBoundFloat" + varNames() + ": " 281 // + "add(" + value + ", " + modified + ", " + count + ")"); 282 283 boolean changed = false; 284 InvariantStatus status = InvariantStatus.NO_CHANGE; 285 for (int i = 0; i < value.length; i++) { 286 if (!changed && core.wouldChange(value[i])) { 287 changed = true; 288 status = InvariantStatus.WEAKENED; 289 } 290 if (core.add_modified(value[i], count) == 291 InvariantStatus.FALSIFIED) { 292 return InvariantStatus.FALSIFIED; 293 } 294 } 295 return status; 296 } 297 298 @Override 299 public InvariantStatus check_modified(double @Interned [] value, int count) { 300 301 for (int i = 0; i < value.length; i++) { 302 if (core.check(value[i]) == InvariantStatus.WEAKENED) { 303 return InvariantStatus.WEAKENED; 304 } 305 } 306 return InvariantStatus.NO_CHANGE; 307 } 308 309 @Override 310 public boolean enoughSamples(@GuardSatisfied EltLowerBoundFloat this) { 311 return core.enoughSamples(); 312 } 313 314 @Override 315 protected double computeConfidence() { 316 return core.computeConfidence(); 317 } 318 319 @Pure 320 @Override 321 public boolean isExact() { 322 return core.isExact(); 323 } 324 325 @Pure 326 @Override 327 public boolean isSameFormula(Invariant other) { 328 return core.isSameFormula(((EltLowerBoundFloat) other).core); 329 } 330 331 @Override 332 public boolean hasUninterestingConstant() { 333 // If the constant bound is not in some small range of interesting 334 // values (by default {-1, 0, 1, 2}), call it uninteresting. 335 if ((core.min1 < dkconfig_minimal_interesting) 336 || (core.min1 > dkconfig_maximal_interesting)) { 337 return true; 338 } 339 340 else if (core.min1 != (int)core.min1) { 341 // Non-integer bounds are uninteresting even if small. 342 return true; 343 } 344 345 return false; 346 } 347 348 @Pure 349 @Override 350 public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) { 351 VarInfo var = vis[0]; 352 if ((var.derived instanceof SequenceLength) 353 && (((SequenceLength) var.derived).shift != 0)) { 354 return new DiscardInfo(this, DiscardCode.obvious, "Bounds are preferrable over sequence lengths with no shift"); 355 } 356 357 return super.isObviousStatically(vis); 358 } 359 360 @Pure 361 @Override 362 public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) { 363 DiscardInfo super_result = super.isObviousDynamically(vis); 364 if (super_result != null) { 365 return super_result; 366 } 367 368 PptTopLevel pptt = ppt.parent; 369 370 // This check always lets invariants pass through (even if it is not within 371 // the default range of (-1 to 2) if it matches a static constant 372 // As noted below, this check really doesn't belong here, but should be 373 // moved to hasUninterestingConstant() whenever that is implemented 374 if (PrintInvariants.dkconfig_static_const_infer) { 375 if (core.matchConstant()) { 376 return null; 377 } 378 } 379 380 // if the value is not in some range (like -1,0,1,2) then say that it is obvious 381 if ((core.min1 < dkconfig_minimal_interesting) 382 || (core.min1 > dkconfig_maximal_interesting)) { 383 // XXX This check doesn't really belong here. However It 384 // shouldn't get removed until hasUninterestingConstant() is 385 // suitable to be turned on everywhere by default. -SMcC 386 // if the value is not in some range (like -1,0,1,2) then say that 387 // it is obvious 388 String discardString = ""; 389 if (core.min1 < dkconfig_minimal_interesting) { 390 discardString = "MIN1="+core.min1+" is less than dkconfig_minimal_interesting==" 391 + dkconfig_minimal_interesting; 392 } else { 393 discardString = "MIN1="+core.min1+" is greater than dkconfig_maximal_interesting=="+ 394 dkconfig_maximal_interesting; 395 } 396 return new DiscardInfo(this, DiscardCode.obvious, discardString); 397 } 398 EltOneOfFloat oo = EltOneOfFloat.find(ppt); 399 if ((oo != null) && oo.enoughSamples() && oo.num_elts() > 0) { 400 assert oo.var().isCanonical(); 401 // We could also use core.min1 == oo.min_elt(), since the LowerBound 402 // will never have a core.min1 that does not appear in the OneOf. 403 if (core.min1 <= oo.min_elt()) { 404 String varName = vis[0].name(); 405 String discardString = varName + "<=" + core.min1 + " is implied by " + varName + "<=" + oo.min_elt(); 406 log("%s", discardString); 407 return new DiscardInfo(this, DiscardCode.obvious, discardString); 408 } 409 } 410 411 // NOT: "VarInfo v = var();" because we want to operate not on this 412 // object's own variables, but on the variables that were passed in. 413 VarInfo v = vis[0]; 414 415 // Look for the same property over a supersequence of this one. 416 for (Iterator<Invariant> inv_itor = pptt.invariants_iterator(); inv_itor.hasNext(); ) { 417 Invariant inv = inv_itor.next(); 418 if (inv == this) { 419 continue; 420 } 421 if (inv instanceof EltLowerBoundFloat) { 422 EltLowerBoundFloat other = (EltLowerBoundFloat) inv; 423 if (isSameFormula(other) 424 && SubSequenceFloat.isObviousSubSequenceDynamically(this, v, other.var())) { 425 String varName = v.name(); 426 String otherName = other.var().name(); 427 String discardString = varName + " is a subsequence of " + otherName + " for which the invariant holds."; 428 log("%s", discardString); 429 return new DiscardInfo(this, DiscardCode.obvious, discardString); 430 } 431 } 432 } 433 434 // For each sequence variable, if this is an obvious member/subsequence, and 435 // it has the same invariant, then this one is obvious. 436 for (int i = 0; i < pptt.var_infos.length; i++) { 437 VarInfo vi = pptt.var_infos[i]; 438 439 if (SubSequenceFloat.isObviousSubSequenceDynamically(this, v, vi)) 440 { 441 PptSlice1 other_slice = pptt.findSlice(vi); 442 if (other_slice != null) { 443 EltLowerBoundFloat eb = EltLowerBoundFloat.find(other_slice); 444 if ((eb != null) 445 && eb.enoughSamples() 446 && eb.min() == min()) { 447 String otherName = other_slice.var_infos[0].name(); 448 String varName = v.name(); 449 String discardString = varName+" is a subsequence of "+otherName+" for which the invariant holds."; 450 log("%s", discardString); 451 return new DiscardInfo(this, DiscardCode.obvious, discardString); 452 } 453 } 454 } 455 } 456 457 return null; 458 } 459 460 @Pure 461 @Override 462 public boolean isExclusiveFormula(Invariant other) { 463 464 // N.B. "x[] elements >= 200" is not mutually exclusive with "x[] 465 // elements <= 100"; they could both be true if x[] were always empty. 466 467 if (other instanceof OneOfFloat) { 468 return other.isExclusiveFormula(this); 469 } 470 return false; 471 } 472 473 // Look up a previously instantiated invariant. 474 public static @Nullable EltLowerBoundFloat find(PptSlice ppt) { 475 assert ppt.arity() == 1; 476 for (Invariant inv : ppt.invs) { 477 if (inv instanceof EltLowerBoundFloat) { 478 return (EltLowerBoundFloat) inv; 479 } 480 } 481 return null; 482 } 483 484 /** 485 * Bound can merge different formulas from lower points to create a single formula at an upper 486 * point. See merge() below. 487 */ 488 @Override 489 public boolean mergeFormulasOk() { 490 return true; 491 } 492 493 /** 494 * Merge the invariants in invs to form a new invariant. Each must be a EltLowerBoundFloat invariant. This 495 * code finds all of the min/max values in each invariant, applies them to a new parent invariant 496 * and returns the merged invariant (if any). 497 * 498 * @param invs list of invariants to merge. The invariants must all be of the same type and should 499 * come from the children of parent_ppt. They should also all be permuted to match the 500 * variable order in parent_ppt. 501 * @param parent_ppt slice that will contain the new invariant 502 */ 503 @Override 504 public @Nullable Invariant merge(List<Invariant> invs, PptSlice parent_ppt) { 505 506 // Create the initial parent invariant from the first child 507 EltLowerBoundFloat first = (EltLowerBoundFloat) invs.get(0); 508 EltLowerBoundFloat result= first.clone(); 509 result.ppt = parent_ppt; 510 511 // Loop through the rest of the child invariants 512 for (int i = 1; i < invs.size(); i++ ) { 513 EltLowerBoundFloat lb = (EltLowerBoundFloat) invs.get(i); 514 result.core.add(lb.core); 515 } 516 517 result.log("Merged '%s' from %s child invariants", result.format(),invs.size()); 518 return result; 519 } 520}