001// ***** This file is automatically generated from OneOf.java.jpp 002 003package daikon.inv.unary.sequence; 004 005import daikon.*; 006import daikon.inv.*; 007import daikon.inv.unary.OneOf; 008 009 import daikon.inv.binary.twoSequence.SubSequence; 010 import daikon.inv.unary.scalar.*; 011 012import java.io.*; 013import java.util.logging.Logger; 014import java.util.logging.Level; 015import java.util.*; 016 017import org.checkerframework.checker.initialization.qual.Initialized; 018import org.checkerframework.checker.interning.qual.Interned; 019import org.checkerframework.checker.lock.qual.GuardSatisfied; 020import org.checkerframework.checker.nullness.qual.NonNull; 021import org.checkerframework.checker.nullness.qual.Nullable; 022import org.checkerframework.dataflow.qual.Pure; 023import org.checkerframework.dataflow.qual.SideEffectFree; 024import org.checkerframework.framework.qual.Unused; 025import daikon.SignaturesUtil; 026import org.plumelib.reflection.Signatures; 027import org.plumelib.util.ArraysPlume; 028import org.plumelib.util.Intern; 029import org.plumelib.util.StringsPlume; 030import org.plumelib.util.UtilPlume; 031import typequals.prototype.qual.NonPrototype; 032import typequals.prototype.qual.Prototype; 033 034// This subsumes an "exact" invariant that says the value is always exactly 035// a specific value. Do I want to make that a separate invariant 036// nonetheless? Probably not, as this will simplify implication and such. 037 038 /** 039 * Represents sequences of double values where the elements of the sequence take on only a 040 * few distinct values. Prints as either {@code x[] elements == c} (when there is only one value), 041 * or as {@code x[] elements one of {c1, c2, c3}} (when there are multiple values). 042 043 */ 044 045@SuppressWarnings("UnnecessaryParentheses") // generated code, parentheses are sometimes needed 046public final class EltOneOfFloat extends SingleFloatSequence implements OneOf { 047 static final long serialVersionUID = 20030822L; 048 049 /** Debugging logger. */ 050 public static final Logger debug = 051 Logger.getLogger(EltOneOfFloat.class.getName()); 052 053 // Variables starting with dkconfig_ should only be set via the 054 // daikon.config.Configuration interface. 055 /** Boolean. True iff OneOf invariants should be considered. */ 056 public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault; 057 058 /** 059 * Positive integer. Specifies the maximum set size for this type of invariant (x is one of 060 * {@code size} items). 061 */ 062 063 public static int dkconfig_size = 3; 064 065 // Probably needs to keep its own list of the values, and number of each seen. 066 // (That depends on the slice; maybe not until the slice is cleared out. 067 // But so few values is cheap, so this is quite fine for now and long-term.) 068 069 @Unused(when=Prototype.class) 070 private double[] elts; 071 @Unused(when=Prototype.class) 072 private int num_elts; 073 074 @Prototype EltOneOfFloat() { 075 super(); 076 } 077 078 EltOneOfFloat(PptSlice slice) { 079 super(slice); 080 081 elts = new double[dkconfig_size]; 082 083 num_elts = 0; 084 085 // var() is initialized by the super constructor 086 assert var().is_array() : 087 String.format("In %s constructor, var %s (type=%s, rep_type=%s) should be an array", 088 "EltOneOfFloat", var().name(), var().type, var().rep_type); 089 090 } 091 092 private static @Prototype EltOneOfFloat proto = new @Prototype EltOneOfFloat(); 093 094 /** Returns the prototype invariant for EltOneOfFloat */ 095 public static @Prototype EltOneOfFloat get_proto() { 096 return proto; 097 } 098 099 @Override 100 public boolean enabled() { 101 return dkconfig_enabled; 102 } 103 104 @Override 105 public EltOneOfFloat instantiate_dyn(@Prototype EltOneOfFloat this, PptSlice slice) { 106 return new EltOneOfFloat(slice); 107 } 108 109 @Pure 110 public boolean is_boolean(@GuardSatisfied EltOneOfFloat this) { 111 return var().file_rep_type.elementType() == ProglangType.BOOLEAN; 112 } 113 @Pure 114 public boolean is_hashcode(@GuardSatisfied EltOneOfFloat this) { 115 return var().file_rep_type.elementType() == ProglangType.HASHCODE; 116 } 117 118 @SideEffectFree 119 @Override 120 public EltOneOfFloat clone(@GuardSatisfied EltOneOfFloat this) { 121 EltOneOfFloat result = (EltOneOfFloat) super.clone(); 122 result.elts = elts.clone(); 123 124 result.num_elts = this.num_elts; 125 return result; 126 } 127 128 @Override 129 public int num_elts() { 130 return num_elts; 131 } 132 133 @Override 134 public Object elt() { 135 return elt(0); 136 } 137 138 public Object elt(int index) { 139 if (num_elts <= index) { 140 throw new Error("Represents " + num_elts + " elements, index " + index + " not valid"); 141 } 142 143 return Intern.internedDouble(elts[index]); 144 } 145 146 private void sort_rep(@GuardSatisfied EltOneOfFloat this) { 147 Arrays.sort(elts, 0, num_elts ); 148 } 149 150 public double min_elt() { 151 if (num_elts == 0) { 152 throw new Error("Represents no elements"); 153 } 154 sort_rep(); 155 return elts[0]; 156 } 157 158 public double max_elt() { 159 if (num_elts == 0) { 160 throw new Error("Represents no elements"); 161 } 162 sort_rep(); 163 return elts[num_elts - 1]; 164 } 165 166 // Assumes the other array is already sorted 167 public boolean compare_rep(int num_other_elts, double[] other_elts) { 168 if (num_elts != num_other_elts) { 169 return false; 170 } 171 sort_rep(); 172 for (int i = 0; i < num_elts; i++) { 173 if (!(Global.fuzzy.eq(elts[i], other_elts[i]) || (Double.isNaN(elts[i]) && Double.isNaN(other_elts[i])))) { // elements are interned 174 return false; 175 } 176 } 177 return true; 178 } 179 180 private String subarray_rep(@GuardSatisfied EltOneOfFloat this) { 181 // Not so efficient an implementation, but simple; 182 // and how often will we need to print this anyway? 183 sort_rep(); 184 StringJoiner sj = new StringJoiner(", ", "{ ", " }"); 185 for (int i = 0; i < num_elts; i++) { 186 187 if (PrintInvariants.dkconfig_static_const_infer) { 188 boolean curVarMatch = false; 189 PptTopLevel pptt = ppt.parent; 190 for (VarInfo vi : pptt.var_infos) { 191 if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) { 192 // If variable is a double, then use fuzzy comparison 193 if (vi.rep_type == ProglangType.DOUBLE) { 194 Double constantVal = (Double)vi.constantValue(); 195 if (Global.fuzzy.eq(constantVal, elts[i]) || (Double.isNaN(constantVal) && Double.isNaN(elts[i]))) { 196 sj.add(vi.name()); 197 curVarMatch = true; 198 } 199 } 200 // Otherwise just use the equals method 201 else { 202 Object constantVal = vi.constantValue(); 203 if (constantVal.equals(elts[i])) { 204 sj.add(vi.name()); 205 curVarMatch = true; 206 } 207 } 208 } 209 } 210 211 if (curVarMatch == false) { 212 sj.add((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i]))); 213 } 214 } else { 215 sj.add((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i]))); 216 } 217 218 } 219 return sj.toString(); 220 } 221 222 @Override 223 public String repr(@GuardSatisfied EltOneOfFloat this) { 224 return "EltOneOfFloat" + varNames() + ": falsified=" + falsified 225 + ", num_elts=" + num_elts 226 + ", elts=" + subarray_rep(); 227 } 228 229 @SideEffectFree 230 @Override 231 public String format_using(@GuardSatisfied EltOneOfFloat this, OutputFormat format) { 232 sort_rep(); 233 234 if (format.isJavaFamily()) { 235 return format_java_family(format); 236 } 237 238 if (format == OutputFormat.DAIKON) { 239 return format_daikon(); 240 } else if (format == OutputFormat.SIMPLIFY) { 241 return format_simplify(); 242 } else if (format == OutputFormat.ESCJAVA) { 243 String result = format_esc(); 244 return result; 245 } else if (format == OutputFormat.CSHARPCONTRACT) { 246 return format_csharp_contract(); 247 } else { 248 return format_unimplemented(format); 249 } 250 } 251 252 public String format_daikon(@GuardSatisfied EltOneOfFloat this) { 253 String varname = var().name() + " elements"; 254 if (num_elts == 1) { 255 256 if (PrintInvariants.dkconfig_static_const_infer) { 257 PptTopLevel pptt = ppt.parent; 258 for (VarInfo vi : pptt.var_infos) { 259 if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) { 260 if (vi.rep_type == ProglangType.DOUBLE) { 261 Double constantVal = (Double)vi.constantValue(); 262 if (Global.fuzzy.eq(constantVal, elts[0]) || (Double.isNaN(constantVal) && Double.isNaN(elts[0]))) { 263 return varname + " == " + vi.name(); 264 } 265 } else { 266 Object constantVal = vi.constantValue(); 267 if (constantVal.equals(elts[0])) { 268 return varname + " == " + vi.name(); 269 } 270 } 271 } 272 } 273 } 274 return varname + " == " + (Double.isNaN(elts[0]) ? "Double.NaN" : String.valueOf(elts[0])); 275 } else { 276 return varname + " one of " + subarray_rep(); 277 } 278 } 279 280 public String format_esc(@GuardSatisfied EltOneOfFloat this) { 281 sort_rep(); 282 283 String[] form = VarInfo.esc_quantify(var()); 284 String varname = form[1]; 285 286 String result; 287 288 { 289 result = ""; 290 for (int i = 0; i < num_elts; i++) { 291 if (i != 0) { result += " || "; } 292 result += varname + " == " + (Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])); 293 } 294 } 295 296 result = form[0] + "(" + result + ")" + form[2]; 297 298 return result; 299 } 300 301public String format_csharp_contract(@GuardSatisfied EltOneOfFloat this) { 302 303 @NonNull @Initialized String result; 304 305 String equalsString = " == "; 306 String endString = ""; 307 308 String[] split = var().csharp_array_split(); 309 List<String> args_list = new ArrayList<>(); 310 // Construct the array that unary value will be compared against. 311 for (int i = 0; i < num_elts; i++) { 312 313 args_list.add((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i]))); 314 315 } 316 String args = String.join(", ", args_list); 317 318 if (num_elts == 0) { // If there are no elements, length must be 0. 319 String varname = var().csharp_name(); 320 return varname + ".Count() == 0"; 321 } else if (num_elts == 1) { 322 323 { 324 result = "Contract.ForAll(" + split[0] + ", x => x" + split[1] + equalsString + args + endString + ")"; 325 } 326 } else { 327 assert num_elts > 1; 328 result = "Contract.ForAll(" + split[0] + ", x => x" + split[1] + ".OneOf(" + args + "))"; 329 } 330 331 return result; 332 } 333 334 public String format_java_family(@GuardSatisfied EltOneOfFloat this, OutputFormat format) { 335 336 String result; 337 338 // Setting up the name of the unary variable 339 String varname = var().name_using(format); 340 341 // Constructing the array that unary val will be compared against 342 343 String oneOfArray = "new double[] { "; 344 345 for (int i = 0 ; i < num_elts ; i++) { 346 if (i != 0) { 347 oneOfArray += ", "; 348 } 349 oneOfArray = oneOfArray + (Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])); 350 } 351 oneOfArray += " }"; 352 353 // Calling quantification method 354 if (num_elts == 1) { 355 356 { 357 result = "daikon.Quant.eltsEqual(" + varname + ", " 358 + (Double.isNaN(elts[0]) ? "Double.NaN" : String.valueOf(elts[0])) + ")"; 359 } 360 } else { 361 assert num_elts > 1; 362 // eltsOneOf == subsetOf 363 result = "daikon.Quant.subsetOf(" + varname + ", " + oneOfArray + ")"; 364 } 365 366 return result; 367 } 368 369 public String format_simplify(@GuardSatisfied EltOneOfFloat this) { 370 371 sort_rep(); 372 373 String[] form = VarInfo.simplify_quantify(var()); 374 String varname = form[1]; 375 376 String result; 377 378 { 379 result = ""; 380 for (int i = 0; i < num_elts; i++) { 381 result += " (EQ " + varname + " " + simplify_format_double(elts[i]) + ")"; 382 } 383 if (num_elts > 1) { 384 result = "(OR" + result + ")"; 385 } else if (num_elts == 1) { 386 // chop leading space 387 result = result.substring(1); 388 } else { 389 // Haven't actually seen any data, so we're vacuously true 390 return format_too_few_samples(OutputFormat.SIMPLIFY, null); 391 } 392 } 393 394 result = form[0] + result + form[2]; 395 396 if (result.indexOf("format_simplify") == -1) { 397 daikon.simplify.SimpUtil.assert_well_formed(result); 398 } 399 return result; 400 } 401 402 @Override 403 public InvariantStatus add_modified(double[] a, int count) { 404 return runValue(a, count, true); 405 } 406 407 @Override 408 public InvariantStatus check_modified(double[] a, int count) { 409 return runValue(a, count, false); 410 } 411 412 private InvariantStatus runValue(double[] a, int count, boolean mutate) { 413 InvariantStatus finalStatus = InvariantStatus.NO_CHANGE; 414 for (int ai = 0; ai <a.length; ai++) { 415 InvariantStatus status; 416 if (mutate) { 417 status = add_mod_elem(a[ai], count); 418 } else { 419 status = check_mod_elem(a[ai], count); 420 } 421 if (status == InvariantStatus.FALSIFIED) { 422 return InvariantStatus.FALSIFIED; 423 } else if (status == InvariantStatus.WEAKENED) { 424 finalStatus = InvariantStatus.WEAKENED; 425 } 426 } 427 return finalStatus; 428 } 429 430 /** 431 * Adds a single sample to the invariant. Returns 432 * the appropriate InvariantStatus from the result 433 * of adding the sample to this. 434 */ 435 public InvariantStatus add_mod_elem(double v, int count) { 436 InvariantStatus status = check_mod_elem(v, count); 437 if (status == InvariantStatus.WEAKENED) { 438 elts[num_elts] = v; 439 num_elts++; 440 } 441 return status; 442 } 443 444 /** 445 * Checks a single sample to the invariant. Returns 446 * the appropriate InvariantStatus from the result 447 * of adding the sample to this. 448 */ 449 public InvariantStatus check_mod_elem(double v, int count) { 450 451 // Look for v in our list of previously seen values. If it's 452 // found, we're all set. 453 for (int i = 0; i < num_elts; i++) { 454 // if (logDetail()) 455 // log ("add_modified (" + v + ")"); 456 if ((Global.fuzzy.eq(elts[i], v) || (Double.isNaN(elts[i]) && Double.isNaN( v)))) { 457 return InvariantStatus.NO_CHANGE; 458 } 459 } 460 461 if (num_elts == dkconfig_size) { 462 return InvariantStatus.FALSIFIED; 463 } 464 465 return InvariantStatus.WEAKENED; 466 } 467 468 // It is possible to have seen many (array) samples, but no (double) 469 // array element values. 470 @Override 471 public boolean enoughSamples(@GuardSatisfied EltOneOfFloat this) { 472 return num_elts > 0; 473 } 474 475 @Override 476 protected double computeConfidence() { 477 // This is not ideal. 478 if (num_elts == 0) { 479 return Invariant.CONFIDENCE_UNJUSTIFIED; 480 } else { 481 return Invariant.CONFIDENCE_JUSTIFIED; 482 } 483 } 484 485 @Pure 486 @Override 487 public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) { 488 // Static constants are necessarily OneOf precisely one value. 489 // This removes static constants from the output, which might not be 490 // desirable if the user doesn't know their actual value. 491 if (vis[0].isStaticConstant()) { 492 assert num_elts <= 1; 493 return new DiscardInfo(this, DiscardCode.obvious, vis[0].name() + " is a static constant."); 494 } 495 return super.isObviousStatically(vis); 496 } 497 498 @Pure 499 @Override 500 public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) { 501 DiscardInfo super_result = super.isObviousDynamically(vis); 502 if (super_result != null) { 503 return super_result; 504 } 505 506 VarInfo v = vis[0]; 507 508 // We can check if all values in the list match with the ones we know about 509 // (useful for booleans and numeric enumerations). 510 if (v.aux.hasValue(VarInfoAux.VALID_VALUES)) { 511 String[] vsValidValues = v.aux.getList(VarInfoAux.VALID_VALUES); 512 Set<Double> setValidValues = new TreeSet<>(); 513 for (String s : vsValidValues) { 514 setValidValues.add(Double.valueOf(s)); 515 } 516 Set<Double> setValuesInvariant = new TreeSet<>(); 517 for (double e : elts) { 518 setValuesInvariant.add(e); 519 } 520 if (setValidValues.equals(setValuesInvariant)) { 521 return new DiscardInfo(this, DiscardCode.obvious, 522 "The value list matches the allowed value list"); 523 } 524 } 525 526 // Look for the same property over a supersequence of this one. 527 PptTopLevel pptt = ppt.parent; 528 for (Iterator<Invariant> inv_itor = pptt.invariants_iterator(); inv_itor.hasNext(); ) { 529 Invariant inv = inv_itor.next(); 530 if (inv == this) { 531 continue; 532 } 533 if (inv instanceof EltOneOfFloat) { 534 EltOneOfFloat other = (EltOneOfFloat) inv; 535 if (isSameFormula(other) 536 && SubSequence.isObviousSubSequenceDynamically(this, v, other.var())) { 537 debug.fine("isObviousDyn: Returning true because isObviousSubSequenceDynamically"); 538 return new DiscardInfo(this, DiscardCode.obvious, "The same property holds over a supersequence " + other.var().name()); 539 } 540 } 541 } 542 543 return null; 544 } 545 546 /** 547 * Oneof can merge different formulas from lower points to create a single formula at an upper 548 * point. 549 */ 550 @Override 551 public boolean mergeFormulasOk() { 552 return true; 553 } 554 555 @Pure 556 @Override 557 public boolean isSameFormula(Invariant o) { 558 EltOneOfFloat other = (EltOneOfFloat) o; 559 if (num_elts != other.num_elts) { 560 return false; 561 } 562 if (num_elts == 0 && other.num_elts == 0) { 563 return true; 564 } 565 566 sort_rep(); 567 other.sort_rep(); 568 569 for (int i = 0; i < num_elts; i++) { 570 if (!(Global.fuzzy.eq(elts[i], other.elts[i]) || (Double.isNaN(elts[i]) && Double.isNaN(other.elts[i])))) { 571 return false; 572 } 573 } 574 575 return true; 576 } 577 578 @Pure 579 @Override 580 public boolean isExclusiveFormula(Invariant o) { 581 if (o instanceof EltOneOfFloat) { 582 EltOneOfFloat other = (EltOneOfFloat) o; 583 584 if (num_elts == 0 || other.num_elts == 0) { 585 return false; 586 } 587 for (int i = 0; i < num_elts; i++) { 588 for (int j = 0; j < other.num_elts; j++) { 589 if ((Global.fuzzy.eq(elts[i], other.elts[j]) || (Double.isNaN(elts[i]) && Double.isNaN(other.elts[j])))) // elements are interned 590 return false; 591 } 592 } 593 594 return true; 595 } 596 597 // Many more checks can be added here: against nonzero, modulus, etc. 598 if ((o instanceof EltNonZeroFloat) && (num_elts == 1) && (elts[0] == 0)) { 599 return true; 600 } 601 double elts_min = Double.MAX_VALUE; 602 double elts_max = Double.MIN_VALUE; 603 for (int i = 0; i < num_elts; i++) { 604 elts_min = Math.min(elts_min, elts[i]); 605 elts_max = Math.max(elts_max, elts[i]); 606 } 607 if ((o instanceof LowerBoundFloat) && (elts_max < ((LowerBoundFloat)o).min())) { 608 return true; 609 } 610 if ((o instanceof UpperBoundFloat) && (elts_min > ((UpperBoundFloat)o).max())) { 611 return true; 612 } 613 614 return false; 615 } 616 617 @Override 618 public boolean hasUninterestingConstant() { 619 620 for (int i = 0; i < num_elts; i++) { 621 if (elts[i] < -1.0 || elts[i] > 2.0 || elts[i] != (long)elts[i]) { 622 return true; 623 } 624 } 625 626 return false; 627 } 628 629 @Pure 630 @Override 631 public boolean isExact() { 632 return num_elts == 1; 633 } 634 635 // Look up a previously instantiated invariant. 636 public static @Nullable EltOneOfFloat find(PptSlice ppt) { 637 assert ppt.arity() == 1; 638 for (Invariant inv : ppt.invs) { 639 if (inv instanceof EltOneOfFloat) { 640 return (EltOneOfFloat) inv; 641 } 642 } 643 return null; 644 } 645 646 // Interning is lost when an object is serialized and deserialized. 647 // Manually re-intern any interned fields upon deserialization. 648 private void readObject(ObjectInputStream in) throws IOException, 649 ClassNotFoundException { 650 in.defaultReadObject(); 651 652 for (int i = 0; i < num_elts; i++) { 653 elts[i] = Intern.intern(elts[i]); 654 } 655 } 656 657 /** 658 * Merge the invariants in invs to form a new invariant. Each must be a EltOneOfFloat invariant. 659 * This code finds all of the oneof values from each of the invariants and returns the merged 660 * invariant (if any). 661 * 662 * @param invs list of invariants to merge. The invariants must all be of the same type and should 663 * come from the children of parent_ppt. They should also all be permuted to match the 664 * variable order in parent_ppt. 665 * @param parent_ppt slice that will contain the new invariant 666 */ 667 @Override 668 public @Nullable EltOneOfFloat merge(List<Invariant> invs, PptSlice parent_ppt) { 669 670 // Create the initial parent invariant from the first child 671 EltOneOfFloat first = (EltOneOfFloat) invs.get(0); 672 EltOneOfFloat result = first.clone(); 673 result.ppt = parent_ppt; 674 675 // Loop through the rest of the child invariants 676 for (int i = 1; i < invs.size(); i++ ) { 677 678 // Get this invariant 679 EltOneOfFloat inv = (EltOneOfFloat) invs.get(i); 680 681 // Loop through each distinct value found in this child and add 682 // it to the parent. If the invariant is falsified, there is no parent 683 // invariant 684 for (int j = 0; j < inv.num_elts; j++) { 685 double val = inv.elts[j]; 686 687 InvariantStatus status = result.add_mod_elem(val, 1); 688 if (status == InvariantStatus.FALSIFIED) { 689 690 result.log("%s", "child value '" + val + "' destroyed oneof"); 691 692 return null; 693 } 694 } 695 } 696 697 result.log("Merged '%s' from %s child invariants", result.format(), invs.size()); 698 return result; 699 } 700 701 /** 702 * Setup the invariant with the specified elements. Normally used when searching for a specified 703 * OneOf. The elements of vals are not necessarily interned; this method interns each element. 704 */ 705 public void set_one_of_val(double[] vals) { 706 707 num_elts = vals.length; 708 for (int i = 0; i < num_elts; i++) { 709 elts[i] = Intern.intern(vals[i]); 710 } 711 } 712 713 /** 714 * Returns true if every element in this invariant is contained in the specified state. For 715 * example if x = 1 and the state contains 1 and 2, true will be returned. 716 */ 717 @Override 718 public boolean state_match(Object state) { 719 720 if (num_elts == 0) { 721 return false; 722 } 723 724 if (!(state instanceof double[])) { 725 // Daikon is about to crash. Produce some debugging output. 726 System.out.printf("state = %s [%s]%n", state, state.getClass()); 727 System.out.printf("problem with %s%n", this); 728 } 729 double[] e = (double[]) state; 730 for (int i = 0; i < num_elts; i++) { 731 boolean match = false; 732 for (int j = 0; j < e.length; j++) { 733 if (elts[i] == e[j]) { 734 match = true; 735 break; 736 } 737 } 738 if (!match) { 739 return false; 740 } 741 } 742 return true; 743 } 744 745}