001// ***** This file is automatically generated from SubSequence.java.jpp 002 003package daikon.inv.binary.twoSequence; 004 005import daikon.*; 006import daikon.derive.*; 007import daikon.derive.binary.*; 008import daikon.derive.ternary.*; 009import daikon.inv.*; 010import daikon.inv.unary.sequence.*; 011import daikon.suppress.*; 012import java.util.*; 013import java.util.logging.Level; 014import java.util.logging.Logger; 015import org.checkerframework.checker.lock.qual.GuardSatisfied; 016import org.checkerframework.checker.nullness.qual.NonNull; 017import org.checkerframework.checker.nullness.qual.Nullable; 018import org.checkerframework.dataflow.qual.Pure; 019import org.checkerframework.dataflow.qual.SideEffectFree; 020import org.plumelib.util.ArraysPlume; 021import org.plumelib.util.IPair; 022import org.plumelib.util.UtilPlume; 023import typequals.prototype.qual.NonPrototype; 024import typequals.prototype.qual.Prototype; 025 026/** 027 * Represents two sequences of long values where one sequence is a subsequence of the 028 * other. Prints as {@code x[] is a subsequence of y[]}. 029 */ 030 031public class SubSequence extends TwoSequence { 032 static final long serialVersionUID = 20031024L; 033 034 private static final Logger debug = 035 Logger.getLogger("daikon.inv.binary.twoSequence.SubSequence"); 036 037 // Variables starting with dkconfig_ should only be set via the 038 // daikon.config.Configuration interface. 039 /** Boolean. True iff SubSequence invariants should be considered. */ 040 public static boolean dkconfig_enabled = false; 041 042 protected SubSequence(PptSlice ppt) { 043 super(ppt); 044 } 045 046 protected @Prototype SubSequence() { 047 super(); 048 } 049 050 private static @Prototype SubSequence proto = new @Prototype SubSequence(); 051 052 /** Returns the prototype invariant for SubSequence */ 053 public static @Prototype SubSequence get_proto() { 054 return proto; 055 } 056 057 @Override 058 public boolean enabled() { 059 return dkconfig_enabled; 060 } 061 062 @Override 063 protected SubSequence instantiate_dyn(@Prototype SubSequence this, PptSlice slice) { 064 return new SubSequence(slice); 065 } 066 067 @Override 068 protected Invariant resurrect_done_swapped() { 069 return new SuperSequence(ppt); 070 } 071 072 @SideEffectFree 073 @Override 074 public String format_using(@GuardSatisfied SubSequence this, OutputFormat format) { 075 if (format == OutputFormat.DAIKON) { 076 return format_daikon(); 077 } 078 if (format == OutputFormat.SIMPLIFY) { 079 return format_simplify(); 080 } 081 if (format == OutputFormat.CSHARPCONTRACT) { 082 return format_csharp_contract(); 083 } 084 if (format.isJavaFamily()) { 085 return format_unimplemented(format); 086 } 087 088 return format_unimplemented(format); 089 } 090 091 public String format_daikon(@GuardSatisfied SubSequence this) { 092 String v1 = var1().name(); 093 String v2 = var2().name(); 094 return v1 + " is a subsequence of " + v2; 095 } 096 097 public String format_csharp_contract(@GuardSatisfied SubSequence this) { 098 String v1 = var1().csharp_collection_string(); 099 String v2 = var2().csharp_collection_string(); 100 return v1 + ".IsSubsequence(" + v2 + ")"; 101 } 102 103 public String format_simplify(@GuardSatisfied SubSequence this) { 104 if (Invariant.dkconfig_simplify_define_predicates) { 105 return format_simplify_defined(); 106 } else { 107 return format_simplify_explicit(); 108 } 109 } 110 111 private String format_simplify_defined(@GuardSatisfied SubSequence this) { 112 String[] sub_name = var1().simplifyNameAndBounds(); 113 String[] super_name = var2().simplifyNameAndBounds(); 114 115 if (sub_name == null || super_name == null) { 116 return String.format("%s.format_simplify_defined(%s): sub_name=%s, super_name=%s, for %s", 117 getClass().getSimpleName(), this, 118 Arrays.toString(sub_name), Arrays.toString(super_name), format()); 119 } 120 121 return "(subsequence " 122 + sub_name[0] + " " + sub_name[1] + " " + sub_name[2] + " " 123 + super_name[0] + " " + super_name[1] + " " + super_name[2] + ")"; 124 } 125 126 // This is apparently broken somehow, though from the logs it's not 127 // clear how. -- smcc 128 private String format_simplify_explicit(@GuardSatisfied SubSequence this) { 129 return "format_simplify disabled"; 130 131 /* Since this doesn't work (since at least april 2003) 132 and it uses quant in complex ways, 133 its just commented out (jhp 8/3/2006) 134 135 // (exists k s.t. (forall i, j; (i bounds & j bounds & (i = j + k)) ==> ...)) 136 137 QuantifyReturn qret = QuantHelper.quantify(new VarInfoName[] 138 { var1().name, var2().name} ); 139 assert qret.bound_vars.size() == 2; 140 assert qret.root_primes.length == 2; 141 142 // These variables are, in order: Example element, free Index 143 // variable, Lower bound, Upper bound, Span 144 String aE, aI, aL, aH, aS; // a = subsequence 145 String bE, bI, bL, bH, bS; // b = supersequence 146 { 147 VarInfoName[] boundv; 148 149 boundv = qret.bound_vars.get(0); 150 aE = qret.root_primes[0].simplify_name(); 151 aI = boundv[0].simplify_name(); 152 aL = boundv[1].simplify_name(); 153 aH = boundv[2].simplify_name(); 154 aS = "(+ (- " + aH + " " + aL + ") 1)"; 155 156 boundv = qret.bound_vars.get(1); 157 bE = qret.root_primes[1].simplify_name(); 158 bI = boundv[0].simplify_name(); 159 bL = boundv[1].simplify_name(); 160 bH = boundv[2].simplify_name(); 161 bS = "(+ (- " + bH + " " + bL + ") 1)"; 162 } 163 164 // This invariant would not have been given data if a value was 165 // missing - for example, if a slice had a negative length. We 166 // must predicate this invariant on the values being sensible. 167 168 String sensible = "(AND (>= " + aS + " 0) (>= " + bS + " 0))"; 169 170 // This invariant would have been falsified if the subsequence A 171 // length was ever zero. Also, this invariant would have been 172 // falsified if the subsequence A was ever longer than the 173 // supersequence B. 174 175 String length_stmt = "(AND (NEQ " + aS + " 0) (>= " + bS + " " + aS + "))"; 176 177 // Subsequence means that there exists an offset in supersequence 178 // B, where (1) the offset is non-negative, (2) the offset doesn't 179 // cause the matching to push past the end of B, and (3) for all 180 // indices less than the span of subsequence A, (4) the elements 181 // starting from A_low and B_low+offset are equal. 182 183 String index = "|__index|"; 184 String shift = "|__shift|"; 185 String subseq_stmt = 186 "(EXISTS (" + shift + ") (AND " 187 + "(<= 0 " + shift + ") " // 1 188 + "(<= (+ " + shift + " " + aS + ") " + bS + ") " // 2 189 + "(FORALL (" + index + ") (IMPLIES (AND (<= 0 " + index + ") (< " + index + " " + aS + ")) " // 3 190 + "(EQ " 191 + aE.replace(aI, "(+ " + aL + " " + index + ")") + " " 192 + bE.replace(bI, "(+ (+ " + bL + " " + index + ") " + shift + ")") + ")))))"; 193 194 // So, when this in sensible, we know that both the length and 195 // subseq statements hold. 196 197 String result = "(IMPLIES " + sensible + " (AND " + length_stmt + " " + subseq_stmt + "))"; 198 return result; 199 */ 200 } 201 202 @Override 203 public InvariantStatus check_modified(long[] a1, long[] a2, 204 int count) { 205 if ((a1 == null) || (a2 == null)) { 206 return InvariantStatus.FALSIFIED; 207 } 208 209 int result = ArraysPlume.indexOf(a2, a1); 210 211 if (result == -1) { 212 return InvariantStatus.FALSIFIED; 213 } else { 214 return InvariantStatus.NO_CHANGE; 215 } 216 } 217 218 @Override 219 public InvariantStatus add_modified(long[] a1, long[] a2, 220 int count) { 221 InvariantStatus is = check_modified(a1, a2, count); 222 if ((is == InvariantStatus.FALSIFIED) && Debug.logOn()) { 223 log("%s destroyed by %s %s", 224 format(), Debug.toString(a1), 225 Debug.toString(a2)); 226 } 227 return is; 228 } 229 230 @Override 231 protected double computeConfidence() { 232 return Invariant.CONFIDENCE_JUSTIFIED; 233 } 234 235 /** Returns a DiscardInfo, or null if the Invariant is not an obvious subsequence. 236@return a DiscardInfo, or null if the Invariant is not an obvious subsequence */ 237 @Pure 238 public static @Nullable DiscardInfo isObviousSubSequence(Invariant inv, VarInfo subvar, VarInfo supervar) { 239 IPair<DiscardCode,String> pcds = isObviousSubSequence(subvar, supervar); 240 if (pcds == null) { 241 return null; 242 } else { 243 return new DiscardInfo(inv, pcds.first, pcds.second); 244 } 245 } 246 247 /** 248 * Returns a IPair of a DiscardCode and a discardReason string, or null if the Invariant is not an 249 * obvious subsequence. 250 * @return a IPair of a DiscardCode and a discardReason string, or null if the Invariant is not an 251 * obvious subsequence 252 */ 253 @Pure 254 public static @Nullable IPair<DiscardCode,String> isObviousSubSequence(VarInfo subvar, VarInfo supervar) { 255 // Must typecheck since this could be called with non-sequence variables in 256 // some methods. 257 ProglangType rep1 = subvar.rep_type; 258 ProglangType rep2 = supervar.rep_type; 259 if (!(((rep1 == ProglangType.INT_ARRAY) 260 && (rep2 == ProglangType.INT_ARRAY)) 261 || ((rep1 == ProglangType.DOUBLE_ARRAY) 262 && (rep2 == ProglangType.DOUBLE_ARRAY)) 263 || ((rep1 == ProglangType.STRING_ARRAY) 264 && (rep2 == ProglangType.STRING_ARRAY)) 265 )) { 266 return null; 267 } 268 269 if (debug.isLoggable(Level.FINE)) { 270 debug.fine("isObviousSubSequence " 271 + subvar.name() + " in " + supervar.name()); 272 } 273 274 // Standard discard reason/string 275 DiscardCode discardCode = DiscardCode.obvious; 276 String discardString = subvar.name()+" obvious subset/subsequence of "+supervar.name(); 277 278 // For unions and intersections, it probably doesn't make sense to 279 // do subsequence or subset detection. This is mainly to prevent 280 // invariants of the form (x subset of union(x, y)) but this means 281 // we also miss those of the form (z subset of union(x,y)) which 282 // might be useful. Subsequence, however, seems totally useless 283 // on unions and intersections. 284 if (supervar.derived instanceof SequenceScalarIntersection 285 || supervar.derived instanceof SequenceScalarUnion 286 || subvar.derived instanceof SequenceScalarIntersection 287 || subvar.derived instanceof SequenceScalarUnion) { 288 discardCode = DiscardCode.obvious; 289 discardString = "Invariants involving subsets/subsequences of unions/intersections are suppressed"; 290 debug.fine(" returning true because of union or intersection"); 291 return IPair.<DiscardCode,String>of(discardCode, discardString); 292 } 293 294 if (subvar.derived instanceof SequencesPredicate) { 295 // It's not useful that predicate(x[], b[]) is a subsequence or subset 296 // of x[] 297 SequencesPredicate derived = (SequencesPredicate) subvar.derived; 298 if (derived.var1().equals(supervar)) { 299 discardCode = DiscardCode.obvious; 300 discardString = subvar.name()+" is derived from "+supervar.name(); 301 debug.fine(" returning true because of predicate slicing"); 302 return IPair.of(discardCode, discardString + " [pred slicing]"); 303 } 304 } 305 306 VarInfo subvar_super = subvar.isDerivedSubSequenceOf(); 307 if (subvar_super == null) { 308 // If it's not a union, intersection or a subsequence, it's not obvious 309 debug.fine(" returning false because subvar_super == null"); 310 return null; 311 } 312 313 if (subvar_super == supervar) { 314 // System.out.println("SubSequence.isObviousDerived(" + subvar.name() + ", " + supervar.name + ") = true"); 315 // System.out.println(" details: subvar_super=" + subvar_super.name + "; supervar_super=" + supervar.isDerivedSubSequenceOf() == null ? "null" : supervar.isDerivedSubSequenceOf().name); 316 discardCode = DiscardCode.obvious; 317 discardString = subvar.name()+"=="+supervar.name(); 318 debug.fine(" returning true because subvar_super == supervar"); 319 return IPair.of(discardCode, 320 discardString + " [subvar_super == supervar]"); 321 } 322 323 // a[i+a..j+b] cmp a[i+c..j+d] 324 VarInfo supervar_super = supervar.isDerivedSubSequenceOf(); 325 // we know subvar_super != null due to check above 326 if (subvar_super == supervar_super) { 327 // both sequences are derived from the same supersequence 328 if ((subvar.derived instanceof SequenceScalarSubsequence 329 || subvar.derived instanceof SequenceScalarArbitrarySubsequence) 330 && (supervar.derived instanceof SequenceScalarSubsequence 331 || supervar.derived instanceof SequenceScalarArbitrarySubsequence)) { 332 // In "A[i..j] subseq B[k..l]": i=sub_left_var, j=sub_right_var, 333 // k=super_left_var, l=super_right_var. 334 VarInfo sub_left_var = null, sub_right_var = null, 335 super_left_var = null, super_right_var = null; 336 // I'm careful not to access foo_shift unless foo_var has been set 337 // to a non-null value, but Java is too stupid to recognize that. 338 int sub_left_shift = 42, sub_right_shift = 69, super_left_shift = 1492, 339 super_right_shift = 1776; 340 if (subvar.derived instanceof SequenceScalarSubsequence) { 341 SequenceScalarSubsequence sub = (SequenceScalarSubsequence)subvar.derived; 342 if (sub.from_start) { 343 sub_right_var = sub.sclvar(); 344 sub_right_shift = sub.index_shift; 345 } else { 346 sub_left_var = sub.sclvar(); 347 sub_left_shift = sub.index_shift; 348 } 349 } else if (subvar.derived instanceof SequenceScalarArbitrarySubsequence) { 350 SequenceScalarArbitrarySubsequence sub = (SequenceScalarArbitrarySubsequence)subvar.derived; 351 sub_left_var = sub.startvar(); 352 sub_left_shift = (sub.left_closed ? 0 : 1); 353 sub_right_var = sub.endvar(); 354 sub_right_shift = (sub.right_closed ? 0 : -1); 355 } else { 356 throw new Error(); 357 } 358 if (supervar.derived instanceof SequenceScalarSubsequence) { 359 SequenceScalarSubsequence super_ = (SequenceScalarSubsequence)supervar.derived; 360 if (super_.from_start) { 361 super_right_var = super_.sclvar(); 362 super_right_shift = super_.index_shift; 363 } else { 364 super_left_var = super_.sclvar(); 365 super_left_shift = super_.index_shift; 366 } 367 } else if (supervar.derived instanceof SequenceScalarArbitrarySubsequence) { 368 SequenceScalarArbitrarySubsequence super_ = (SequenceScalarArbitrarySubsequence)supervar.derived; 369 super_left_var = super_.startvar(); 370 super_left_shift = (super_.left_closed ? 0 : 1); 371 super_right_var = super_.endvar(); 372 super_right_shift = (super_.right_closed ? 0 : -1); 373 } else { 374 throw new Error(); 375 } 376 boolean left_included = false, right_included = false; 377 if (super_left_var == null) { 378 left_included = true; 379 } 380 if (super_left_var == sub_left_var) { 381 if (super_left_shift < sub_left_shift) { 382 left_included = true; 383 } 384 } 385 if (super_right_var == null) { 386 right_included = true; 387 } 388 if (super_right_var == sub_right_var) { 389 if (super_right_shift > sub_right_shift) { 390 right_included = true; 391 } 392 } 393 if (left_included && right_included) { 394 discardCode = DiscardCode.obvious; 395 discardString = subvar.name()+" obvious subset/subsequence of "+supervar.name(); 396 return IPair.of(discardCode, discardString + " [obvious]") 397; 398 } 399 } else if ((subvar.derived instanceof SequenceStringSubsequence) 400 && (supervar.derived instanceof SequenceStringSubsequence)) { 401 // Copied from (an old version) just above 402 // XXX I think this code is dead; why isn't it just produced 403 // from the above by macro expansion? -smcc 404 SequenceStringSubsequence sss1 = (SequenceStringSubsequence) subvar.derived; 405 SequenceStringSubsequence sss2 = (SequenceStringSubsequence) supervar.derived; 406 VarInfo index1 = sss1.sclvar(); 407 int shift1 = sss1.index_shift; 408 boolean start1 = sss1.from_start; 409 VarInfo index2 = sss2.sclvar(); 410 int shift2 = sss2.index_shift; 411 boolean start2 = sss2.from_start; 412 if (index1 == index2) { 413 if (start1 == true && start2 == true) { 414 if (shift1 <= shift2) { 415 return IPair.of(discardCode, discardString + " [shift1]"); 416 } 417 } else if (start1 == false && start2 == false) { 418 if (shift1 >= shift2) { 419 return IPair.of(discardCode, discardString + " [shift2]"); 420 } 421 } 422 } 423 } else { 424 throw new Error("how can this happen? " + subvar.name() 425 + " " + (subvar.derived == null 426 ? "(not derived)" 427 : subvar.derived.getClass()) 428 + " " + supervar.name() 429 + " " + (supervar.derived == null 430 ? "(not derived)" 431 : supervar.derived.getClass())); 432 } 433 } 434 435 return null; 436 } 437 438 // Look up a previously instantiated SubSequence relationship. 439 public static @Nullable SubSequence find(PptSlice ppt) { 440 assert ppt.arity() == 2; 441 for (Invariant inv : ppt.invs) { 442 if (inv instanceof SubSequence) { 443 return (SubSequence) inv; 444 } 445 } 446 return null; 447 } 448 449 @Pure 450 @Override 451 public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) { 452 453 VarInfo subvar = var1(vis); 454 VarInfo supervar = var2(vis); 455 456 // check for x[i..j] subsequence of x[] 457 VarInfo subvar_super = subvar.isDerivedSubSequenceOf(); 458 if (subvar_super == supervar) { 459 debug.fine(" returning true because subvar_super == supervar"); 460 return new DiscardInfo(this, DiscardCode.obvious, 461 "x[i..j] subsequence of x[] is obvious"); 462 } 463 464 DiscardInfo di = SubSequence.isObviousSubSequence(this, subvar, supervar); 465 if (di != null) { 466 return di; 467 } 468 469 // JHP: This is not a valid obvious check, since it doesn't imply that 470 // the invariant is true. 471 if (!subvar.aux.hasOrder() 472 || !supervar.aux.hasOrder()) { 473 // Doesn't make sense to consider subsequence if order doens't matter 474 return new DiscardInfo(this, DiscardCode.obvious, 475 "Order doesn't matter, so subsequence is meaningless"); 476 } 477 478 return super.isObviousStatically(vis); 479 } 480 481 // Two ways to go about this: 482 // * look at all subseq relationships, see if one is over a variable of 483 // interest 484 // * look at all variables derived from the 485 486 // (Seems overkill to check for other transitive relationships. 487 // Eventually that is probably the right thing, however.) 488 @Pure 489 @Override 490 public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) { 491 492 // System.out.println("checking isObviousImplied for: " + format()); 493 if (debug.isLoggable(Level.FINE)) { 494 debug.fine("isObviousDynamically: checking " + vis[0].name() + " in " + vis[1].name()); 495 } 496 497 DiscardInfo super_result = super.isObviousDynamically(vis); 498 if (super_result != null) { 499 return super_result; 500 } 501 502 VarInfo subvar = var1(vis); 503 VarInfo supervar = var2(vis); 504 505 // JHP: The next check is an un-interesting check, not 506 // an obvious check. We need to figure out how to resolve this. 507 508 // Uninteresting if this is of the form x[0..i] subsequence 509 // x[0..j]. Not necessarily obvious. 510 VarInfo subvar_super = subvar.isDerivedSubSequenceOf(); 511 VarInfo supervar_super = supervar.isDerivedSubSequenceOf(); 512 if (subvar_super != null && subvar_super == supervar_super) { 513 debug.fine(" returning true because subvar_super == supervar_super"); 514 return new DiscardInfo(this, DiscardCode.obvious, 515 "x[0..i] subsequence of x[0..j] is uninteresting"); 516 } 517 518 if (isObviousSubSequenceDynamically(this, subvar, supervar)) { 519 return new DiscardInfo(this, DiscardCode.obvious, subvar.name() 520 + " is an obvious subsequence of " 521 + supervar.name()); 522 } 523 return null; 524 } 525 526 /** 527 * Returns true if the two original variables are related in a way that makes subsequence or 528 * subset detection not informative. 529 */ 530 public static boolean isObviousSubSequenceDynamically(Invariant inv, 531 VarInfo subvar, VarInfo supervar) { 532 533 VarInfo [] vis = {subvar, supervar}; 534 535 ProglangType rep1 = subvar.rep_type; 536 ProglangType rep2 = supervar.rep_type; 537 if (!(((rep1 == ProglangType.INT_ARRAY) 538 && (rep2 == ProglangType.INT_ARRAY)) 539 || ((rep1 == ProglangType.DOUBLE_ARRAY) 540 && (rep2 == ProglangType.DOUBLE_ARRAY)) 541 || ((rep1 == ProglangType.STRING_ARRAY) 542 && (rep2 == ProglangType.STRING_ARRAY)) 543 )) { 544 return false; 545 } 546 547 if (debug.isLoggable(Level.FINE)) { 548 debug.fine("Checking isObviousSubSequenceDynamically " 549 + subvar.name() + " in " + supervar.name()); 550 } 551 552 DiscardInfo di = isObviousSubSequence(inv, subvar, supervar); 553 if (di != null) { 554 inv.log("ObvSubSeq- true from isObviousSubSequence: %s", di.discardString()); 555 return true; 556 } 557 debug.fine(" not isObviousSubSequence(statically)"); 558 559 PptTopLevel ppt_parent = subvar.ppt; 560 561 // If the elements of supervar are always the same (EltOneOf), 562 // we aren't going to learn anything new from this invariant, 563 // since each sequence should have an EltOneOf over it. 564 if (false) { 565 PptSlice1 slice = ppt_parent.findSlice(supervar); 566 if (slice == null) { 567 System.out.println("No slice: parent =" + ppt_parent); 568 } else { 569 System.out.println("Slice var =" + slice.var_infos[0]); 570 for (Invariant superinv : slice.invs) { 571 System.out.println("Inv = " + superinv); 572 if (superinv instanceof EltOneOf) { 573 EltOneOf eltinv = (EltOneOf) superinv; 574 if (eltinv.num_elts() > 0) { 575 inv.log(" obvious because of %s", eltinv.format()); 576 return true; 577 } 578 } 579 } 580 } 581 } 582 583 // Obvious if subvar is always just [] 584 if (true) { 585 PptSlice1 slice = ppt_parent.findSlice(subvar); 586 if (slice != null) { 587 for (Invariant subinv : slice.invs) { 588 if (subinv instanceof OneOfSequence) { 589 OneOfSequence seqinv = (OneOfSequence) subinv; 590 if (seqinv.num_elts() == 1) { 591 Object elt = seqinv.elt(); 592 if (elt instanceof long[] && ((long[]) elt).length == 0) { 593 Debug.log(debug, inv.getClass(), inv.ppt, vis, 594 "ObvSubSeq- True from subvar being []"); 595 return true; 596 } 597 if (elt instanceof double[] && ((double[]) elt).length == 0) { 598 inv.log("ObvSubSeq- True from subvar being []"); 599 return true; 600 } 601 } 602 } 603 } 604 } 605 } 606 607 // Check for a[0..i] subseq a[0..j] but i < j. 608 VarInfo subvar_super = subvar.isDerivedSubSequenceOf(); 609 VarInfo supervar_super = supervar.isDerivedSubSequenceOf(); 610 611 if (subvar_super != null && subvar_super == supervar_super) { 612 // both sequences are derived from the same supersequence 613 if ((subvar.derived instanceof SequenceScalarSubsequence 614 || subvar.derived instanceof SequenceScalarArbitrarySubsequence) 615 && (supervar.derived instanceof SequenceScalarSubsequence 616 || supervar.derived instanceof SequenceScalarArbitrarySubsequence)) { 617 VarInfo sub_left_var = null, sub_right_var = null, 618 super_left_var = null, super_right_var = null; 619 // I'm careful not to access foo_shift unless foo_var has been set 620 // to a non-null value, but Java is too stupid to recognize that. 621 int sub_left_shift = 42, sub_right_shift = 69, super_left_shift = 1492, 622 super_right_shift = 1776; 623 if (subvar.derived instanceof SequenceScalarSubsequence) { 624 SequenceScalarSubsequence sub = (SequenceScalarSubsequence)subvar.derived; 625 if (sub.from_start) { 626 sub_right_var = sub.sclvar(); 627 sub_right_shift = sub.index_shift; 628 } else { 629 sub_left_var = sub.sclvar(); 630 sub_left_shift = sub.index_shift; 631 } 632 } else if (subvar.derived instanceof SequenceScalarArbitrarySubsequence) { 633 SequenceScalarArbitrarySubsequence sub = (SequenceScalarArbitrarySubsequence)subvar.derived; 634 sub_left_var = sub.startvar(); 635 sub_left_shift = (sub.left_closed ? 0 : 1); 636 sub_right_var = sub.endvar(); 637 sub_right_shift = (sub.right_closed ? 0 : -1); 638 } else { 639 throw new Error(); 640 } 641 if (supervar.derived instanceof SequenceScalarSubsequence) { 642 SequenceScalarSubsequence super_ = (SequenceScalarSubsequence)supervar.derived; 643 if (super_.from_start) { 644 super_right_var = super_.sclvar(); 645 super_right_shift = super_.index_shift; 646 } else { 647 super_left_var = super_.sclvar(); 648 super_left_shift = super_.index_shift; 649 } 650 } else if (supervar.derived instanceof SequenceScalarArbitrarySubsequence) { 651 SequenceScalarArbitrarySubsequence super_ = (SequenceScalarArbitrarySubsequence)supervar.derived; 652 super_left_var = super_.startvar(); 653 super_left_shift = (super_.left_closed ? 0 : 1); 654 super_right_var = super_.endvar(); 655 super_right_shift = (super_.right_closed ? 0 : -1); 656 } else { 657 throw new Error(); 658 } 659 boolean left_included, right_included; 660 if (super_left_var == null) { 661 left_included = true; 662 } else if (sub_left_var == null) // we know super_left_var != null here 663 left_included = false; 664 else { 665 left_included = 666 VarInfo.compare_vars(super_left_var, super_left_shift, 667 sub_left_var, sub_left_shift, 668 true /* <= */); 669 } 670 if (super_right_var == null) { 671 right_included = true; 672 } else if (sub_right_var == null) // we know super_right_var != null here 673 right_included = false; 674 else { 675 right_included = 676 VarInfo.compare_vars(super_right_var, super_right_shift, 677 sub_right_var, sub_right_shift, 678 false /* >= */); 679 } 680// System.out.println("Is " + subvar.name() + " contained in " 681// + supervar.name() 682// + "? left: " + left_included + ", right: " 683// + right_included); 684 if (left_included && right_included) { 685 inv.log("ObvSubSeq- True a[0..i] subseq a[0..j] and i < j"); 686 return true; 687 } 688 } else if ((subvar.derived instanceof SequenceStringSubsequence) 689 && (supervar.derived instanceof SequenceStringSubsequence)) { 690 // Copied from just above 691 SequenceStringSubsequence sss1 = (SequenceStringSubsequence) subvar.derived; 692 SequenceStringSubsequence sss2 = (SequenceStringSubsequence) supervar.derived; 693 VarInfo index1 = sss1.sclvar(); 694 int shift1 = sss1.index_shift; 695 boolean start1 = sss1.from_start; 696 VarInfo index2 = sss2.sclvar(); 697 int shift2 = sss2.index_shift; 698 boolean start2 = sss2.from_start; 699 if (start1 == start2) { 700 if (VarInfo.compare_vars(index1, shift1, index2, shift2, start1)) { 701 inv.log("True from comparing indices"); 702 return true; 703 } 704 } 705 } else { 706 throw new Error("how can this happen? " + subvar.name() 707 + " " + (subvar.derived == null 708 ? "(not derived)" 709 : subvar.derived.getClass()) 710 + " " + supervar.name() 711 + " " + (supervar.derived == null 712 ? "(not derived)" 713 : supervar.derived.getClass())); 714 } 715 716 } 717 718 // Also need to check A[0..i] subseq A[0..j] via compare_vars. 719 720 // A subseq B[0..n] => A subseq B 721 722 List<Derivation> derivees = supervar.derivees(); 723 // For each variable derived from supervar ("B") 724 for (Derivation der : derivees) { 725 // System.out.println(" ... der = " + der.getVarInfo().name() + " " + der); 726 if (der instanceof SequenceScalarSubsequence) { 727 // If that variable is "B[0..n]" 728 VarInfo supervar_part = der.getVarInfo(); 729 // Get the canonical version; being equal to it is good enough. 730 if (supervar_part.get_equalitySet_leader() == subvar) { 731 Debug.log(debug, inv.getClass(), inv.ppt, vis, 732 "ObvSubSeq- True from canonical leader"); 733 return true; 734 } 735 736 if (supervar_part.isCanonical()) { 737 if (subvar == supervar_part) { 738 System.err.println("Error: variables " 739 + subvar.name() 740 + " and " 741 + supervar_part.name() 742 + " are identical. Canonical"); 743 System.err.println(subvar.isCanonical()); 744 System.err.println(supervar_part.isCanonical()); 745 throw new Error(); 746 } 747 748 // Check to see if there is a subsequence over the supervar 749 if (ppt_parent.is_subsequence(subvar, supervar_part)) { 750 if (Debug.logOn()) { 751 inv.log("ObvSubSeq- true from A subseq B[0..n] %s/%s", 752 subvar.name(), supervar_part.name()); 753 } 754 return true; 755 } 756 } 757 } 758 } 759 return false; 760 } 761 762 @Pure 763 @Override 764 public boolean isSameFormula(Invariant inv) { 765 assert inv instanceof SubSequence; 766 return true; 767 } 768 769 /** returns the ni-suppressions for SubSequence */ 770 @Pure 771 @Override 772 public NISuppressionSet get_ni_suppressions() { 773 return suppressions; 774 } 775 776 /** definition of this invariant (the suppressee) */ 777 private static NISuppressee suppressee = new NISuppressee(SubSequence.class, 2); 778 779 // suppressor definitions (used in suppressions below) 780 private static NISuppressor v1_eq_v2 = new NISuppressor(0, 1, SeqSeqIntEqual.class); 781 private static NISuppressor v1_pw_eq_v2 = new NISuppressor(0, 1, PairwiseIntEqual.class); 782 783 // sub/super sequence suppressions. We have both SeqSeq and Pairwise 784 // as suppressions because each can be enabled separately. 785 private static NISuppressionSet suppressions = 786 new NISuppressionSet( 787 new NISuppression[] { 788 // a[] == b[] ==> a[] sub/superset b[] 789 new NISuppression(v1_eq_v2, suppressee), 790 // a[] == b[] ==> a[] sub/superset b[] 791 new NISuppression(v1_pw_eq_v2, suppressee), 792 }); 793 794}