001package daikon.inv;
002
003import static daikon.tools.nullness.NullnessUtil.castNonNullDeep;
004
005import daikon.Daikon;
006import daikon.Debug;
007import daikon.FileIO;
008import daikon.PptSlice;
009import daikon.PptSlice1;
010import daikon.PptSlice2;
011import daikon.PrintInvariants;
012import daikon.ValueTuple;
013import daikon.VarComparability;
014import daikon.VarComparabilityImplicit;
015import daikon.VarInfo;
016import daikon.inv.binary.BinaryInvariant;
017import daikon.inv.filter.InvariantFilters;
018import daikon.inv.ternary.TernaryInvariant;
019import daikon.inv.unary.OneOf;
020import daikon.inv.unary.UnaryInvariant;
021import daikon.simplify.LemmaStack;
022import daikon.simplify.SimpUtil;
023import daikon.suppress.NISuppressionSet;
024import java.io.Serializable;
025import java.lang.reflect.Field;
026import java.lang.reflect.Method;
027import java.lang.reflect.Modifier;
028import java.util.ArrayList;
029import java.util.Arrays;
030import java.util.Comparator;
031import java.util.IdentityHashMap;
032import java.util.List;
033import java.util.StringJoiner;
034import java.util.logging.Level;
035import java.util.logging.Logger;
036import java.util.regex.Pattern;
037import org.checkerframework.checker.formatter.qual.FormatMethod;
038import org.checkerframework.checker.initialization.qual.UnderInitialization;
039import org.checkerframework.checker.initialization.qual.UnknownInitialization;
040import org.checkerframework.checker.interning.qual.UsesObjectEquals;
041import org.checkerframework.checker.lock.qual.GuardSatisfied;
042import org.checkerframework.checker.nullness.qual.EnsuresNonNullIf;
043import org.checkerframework.checker.nullness.qual.Nullable;
044import org.checkerframework.dataflow.qual.Pure;
045import org.checkerframework.dataflow.qual.SideEffectFree;
046import org.checkerframework.framework.qual.Unused;
047import org.plumelib.util.ArraysPlume;
048import org.plumelib.util.CollectionsPlume;
049import org.plumelib.util.MathPlume;
050import typequals.prototype.qual.NonPrototype;
051import typequals.prototype.qual.Prototype;
052
053/**
054 * Base implementation for Invariant objects. Intended to be subclassed but not to be directly
055 * instantiated. Rules/assumptions for invariants:
056 *
057 * <p>For each program point's set of VarInfos, there exists no more than one invariant of its type.
058 * For example, between variables a and b at PptTopLevel T, there will not be two instances of
059 * invariant I(a, b).
060 */
061@UsesObjectEquals
062@Prototype
063public abstract class Invariant implements Serializable, Cloneable // but don't YOU clone it
064{
065  static final long serialVersionUID = 20040921L;
066
067  /** General debug tracer. */
068  public static final Logger debug = Logger.getLogger("daikon.inv.Invariant");
069
070  /** Debug tracer for printing invariants. */
071  public static final Logger debugPrint = Logger.getLogger("daikon.print");
072
073  /** Debug tracer for invariant flow. */
074  public static final Logger debugFlow = Logger.getLogger("daikon.flow.flow");
075
076  /** Debug tracer for printing equality invariants. */
077  public static final Logger debugPrintEquality = Logger.getLogger("daikon.print.equality");
078
079  /** Debug tracer for isWorthPrinting() checks. */
080  public static final Logger debugIsWorthPrinting =
081      Logger.getLogger("daikon.print.isWorthPrinting");
082
083  /** Debug tracer for guarding. */
084  public static final Logger debugGuarding = Logger.getLogger("daikon.guard");
085
086  /** Debug tracer for isObvious checks. */
087  public static final Logger debugIsObvious = Logger.getLogger("daikon.inv.Invariant.isObvious");
088
089  /**
090   * Floating-point number between 0 and 1. Invariants are displayed only if the confidence that the
091   * invariant did not occur by chance is greater than this. (May also be set via the {@code
092   * --conf_limit} command-line option to Daikon; refer to manual.)
093   */
094  public static double dkconfig_confidence_limit = .99;
095
096  /**
097   * A boolean value. If true, Daikon's Simplify output (printed when the {@code --format simplify}
098   * flag is enabled, and used internally by {@code --suppress_redundant}) will include new
099   * predicates representing some complex relationships in invariants, such as lexical ordering
100   * among sequences. If false, some complex relationships will appear in the output as complex
101   * quantified formulas, while others will not appear at all. When enabled, Simplify may be able to
102   * make more inferences, allowing {@code --suppress_redundant} to suppress more redundant
103   * invariants, but Simplify may also run more slowly.
104   */
105  public static boolean dkconfig_simplify_define_predicates = false;
106
107  /**
108   * Floating-point number between 0 and 0.1, representing the maximum relative difference between
109   * two floats for fuzzy comparisons. Larger values will result in floats that are relatively
110   * farther apart being treated as equal. A value of 0 essentially disables fuzzy comparisons.
111   * Specifically, if {@code abs(1 - f1/f2)} is less than or equal to this value, then the two
112   * doubles ({@code f1} and {@code f2}) will be treated as equal by Daikon.
113   */
114  public static double dkconfig_fuzzy_ratio = 0.0001;
115
116  /** The default for dkconfig_enabled in each subclass of Invariant. */
117  public static boolean invariantEnabledDefault = true;
118
119  /**
120   * The program point for this invariant; includes values, number of samples, VarInfos, etc. Can be
121   * null for a "prototype" invariant.
122   */
123  @Unused(when = Prototype.class)
124  public PptSlice ppt;
125
126  // Has to be public so wrappers can read it.
127  /**
128   * True exactly if the invariant has been falsified: it is guaranteed never to hold (and should be
129   * either in the process of being destroyed or about to be destroyed). This should never be set
130   * directly; instead, call destroy().
131   */
132  protected boolean falsified = false;
133
134  // Whether an invariant is a guarding predicate, that is, creately solely
135  // for the purpose of ensuring invariants with variables that can be
136  // missing do not cause exceptions when tested.  If this is true, then
137  // the invariant itself does not hold over the observed data.
138  public boolean isGuardingPredicate = false;
139
140  /**
141   * The probability that this could have happened by chance alone. <br>
142   * 1 = could never have happened by chance; that is, we are fully confident that this invariant is
143   * a real invariant
144   */
145  public static final double CONFIDENCE_JUSTIFIED = 1;
146
147  /**
148   * (0..1) = greater to lesser likelihood of coincidence <br>
149   * 0 = must have happened by chance
150   */
151  public static final double CONFIDENCE_UNJUSTIFIED = 0;
152
153  /** -1 = delete this invariant; we know it's not true */
154  public static final double CONFIDENCE_NEVER = -1;
155
156  /**
157   * The probability that this could have happened by chance alone. <br>
158   * 0 = could never have happened by chance; that is, we are fully confident that this invariant is
159   * a real invariant
160   */
161  public static final double PROBABILITY_JUSTIFIED = 0;
162
163  /**
164   * (0..1) = lesser to greater likelihood of coincidence <br>
165   * 1 = must have happened by chance
166   */
167  public static final double PROBABILITY_UNJUSTIFIED = 1;
168
169  /** 3 = delete this invariant; we know it's not true */
170  public static final double PROBABILITY_NEVER = 3;
171
172  /**
173   * Return Invariant.CONFIDENCE_JUSTIFIED if x&ge;goal. Return Invariant.CONFIDENCE_UNJUSTIFIED if
174   * x&le;1. For intermediate inputs, the result gives confidence that grades between the two
175   * extremes. See the discussion of gradual vs. sudden confidence transitions.
176   *
177   * @param x the greater value
178   * @param goal the lesser value
179   * @return CONFIDENCE_JUSTIFIED if x&ge;goal, Invariant.CONFIDENCE_UNJUSTIFIED if x&le;1, other
180   *     values otherwise
181   */
182  public static final double conf_is_ge(double x, double goal) {
183    if (x >= goal) {
184      return 1;
185    }
186    if (x <= 1) {
187      return 0;
188    }
189    double result = 1 - (goal - x) / (goal - 1);
190    assert 0 <= result && result <= 1
191        : "conf_is_ge: bad result = " + result + " for (x=" + x + ", goal=" + goal + ")";
192    return result;
193  }
194
195  /**
196   * Return Invariant.PROBABILITY_JUSTIFIED if x&ge;goal. Return Invariant.PROBABILITY_UNJUSTIFIED
197   * if x&le;1. For intermediate inputs, the result gives probability that grades between the two
198   * extremes. See the discussion of gradual vs. sudden probability transitions.
199   *
200   * @param x the greater value
201   * @param goal the lesser value
202   * @return if x&ge;goal: invariant.PROBABILITY_JUSTIFIED; if x&le;1:
203   *     Invariant.PROBABILITY_UNJUSTIFIED; otherwise: other values
204   */
205  public static final double prob_is_ge(double x, double goal) {
206    if (x >= goal) {
207      return 0;
208    }
209    if (x <= 1) {
210      return 1;
211    }
212    double result = (goal - x) / (goal - 1);
213    assert 0 <= result && result <= 1
214        : "prob_is_ge: bad result = " + result + " for (x=" + x + ", goal=" + goal + ")";
215    return result;
216  }
217
218  /**
219   * Return the "and" of the given confidences. This is the confidence that multiple conditions
220   * (whose confidences are given) are all satisfied.
221   *
222   * @param c1 the confidence of the first condition
223   * @param c2 the confidence of the second condition
224   * @return the "and" of the two condidences
225   */
226  public static final double confidence_and(double c1, double c2) {
227    assert 0 <= c1 && c1 <= 1 : "confidence_and: bad c1 = " + c1;
228    assert 0 <= c2 && c2 <= 1 : "confidence_and: bad c2 = " + c2;
229
230    double result = c1 * c2;
231
232    assert 0 <= result && result <= 1 : "confidence_and: bad result = " + result;
233    return result;
234  }
235
236  /**
237   * Return the "and" of the given confidences. This is the confidence that multiple conditions
238   * (whose confidences are given) are all satisfied.
239   *
240   * @param c1 the confidence of the first condition
241   * @param c2 the confidence of the second condition
242   * @param c3 the confidence of the third condition
243   * @return the "and" of the two condidences
244   */
245  public static final double confidence_and(double c1, double c2, double c3) {
246    assert 0 <= c1 && c1 <= 1 : "confidence_and: bad c1 = " + c1;
247    assert 0 <= c2 && c2 <= 1 : "confidence_and: bad c2 = " + c1;
248    assert 0 <= c3 && c3 <= 1 : "confidence_and: bad c3 = " + c1;
249
250    double result = c1 * c2 * c3;
251
252    assert 0 <= result && result <= 1 : "confidence_and: bad result = " + result;
253    return result;
254  }
255
256  /**
257   * Return the "or" of the given confidences. This is the confidence that at least one of multiple
258   * conditions (whose confidences are given) is satisfied.
259   *
260   * @param c1 the confidence of the first condition
261   * @param c2 the confidence of the second condition
262   * @return the "or" of the two condidences
263   */
264  public static final double confidence_or(double c1, double c2) {
265    // Not "1-(1-c1)*(1-c2)" because that can produce a value too large; we
266    // don't want the result to be larger than the larger argument.
267    return Math.max(c1, c2);
268  }
269
270  /**
271   * Return the "and" of the given probabilities. This is the probability that multiple conditions
272   * (whose probabilities are given) are all satisfied.
273   *
274   * @param p1 the probability of the first condition
275   * @param p2 the probability of the second condition
276   * @return the "and" of the two condidences
277   */
278  public static final double prob_and(double p1, double p2) {
279    assert 0 <= p1 && p1 <= 1 : "prob_and: bad p1 = " + p1;
280    assert 0 <= p2 && p2 <= 1 : "prob_and: bad p2 = " + p2;
281
282    // 1 - (1-p1)*(1-p2)
283    double result = p1 + p2 - p1 * p2;
284
285    assert 0 <= result && result <= 1 : "prob_and: bad result = " + result;
286    return result;
287  }
288
289  /**
290   * Return the "and" of the given probabilities. This is the probability that multiple conditions
291   * (whose probabilities are given) are all satisfied.
292   *
293   * @param p1 the probability of the first condition
294   * @param p2 the probability of the second condition
295   * @param p3 the probability of the third condition
296   * @return the "and" of the two condidences
297   */
298  public static final double prob_and(double p1, double p2, double p3) {
299    assert 0 <= p1 && p1 <= 1 : "prob_and: bad p1 = " + p1;
300    assert 0 <= p2 && p2 <= 1 : "prob_and: bad p2 = " + p1;
301    assert 0 <= p3 && p3 <= 1 : "prob_and: bad p3 = " + p1;
302
303    double result = 1 - (1 - p1) * (1 - p2) * (1 - p3);
304
305    assert 0 <= result && result <= 1 : "prob_and: bad result = " + result;
306    return result;
307  }
308
309  /**
310   * Return the "or" of the given probabilities. This is the probability that at least one of
311   * multiple conditions (whose probabilities are given) is satisfied.
312   *
313   * @param p1 the probability of the first condition
314   * @param p2 the probability of the second condition
315   * @return the "or" of the two condidences
316   */
317  public static final double prob_or(double p1, double p2) {
318    // Not "p1*p2" because that can produce a value too small; we don't
319    // want the result to be smaller than the smaller argument.
320    return Math.min(p1, p2);
321  }
322
323  // Subclasses should set these; Invariant never does.
324
325  /**
326   * At least this many samples are required, or else we don't report any invariant at all. (Except
327   * that OneOf invariants are treated differently.)
328   */
329  public static final int min_mod_non_missing_samples = 5;
330
331  /**
332   * Returns true if the invariant has enough samples to have its computed constants well-formed. Is
333   * overridden in classes like LinearBinary/Ternary and Upper/LowerBound.
334   *
335   * @return true if the invariant has enough samples to have its computed constants well-formed
336   */
337  public boolean enoughSamples(@GuardSatisfied @NonPrototype Invariant this) {
338    return true;
339  }
340
341  // The confidence routines (getConfidence and internal helper
342  // computeConfidence) use ModBitTracker information to compute
343  // justification.
344
345  // There are three confidence routines:
346  //  justified() is what most clients should call
347  //  getConfidence() gives the actual confidence.  It used to cache
348  //    results, but it does not do so any longer.
349  //  computeConfidence() is an internal helper method that does the
350  //    actual work, but it should not be called externally, only by
351  //    getConfidence.  It ignores whether the invariant is falsified.
352
353  // There are two general approaches to computing confidence
354  // when there is a threshold (such as needing to see 10 samples):
355  //  * Make the confidence typically either 0 or 1, transitioning
356  //    suddenly between the two as soon as the 10th sample is observed.
357  //  * Make the confidence transition more gradually; for instance, each
358  //    sample changes the confidence by 10%.
359  // The gradual approach has advantages and disadvantages:
360  //  + Users can set the confidence limit to see invariants earlier; this
361  //    is simpler than figuring out all the thresholds to set.
362  //  + Tools such as the operational difference for test suite generation
363  //    are assisted by knowing whether they are getting closer to
364  //    justification.
365  //  - The code is a bit more complicated.
366
367  /**
368   * A wrapper around getConfidence() or getConfidence().
369   *
370   * @return true if this invariant's confidence is greater than the global confidence limit
371   */
372  public final boolean justified(@NonPrototype Invariant this) {
373    boolean just = (!falsified && (getConfidence() >= dkconfig_confidence_limit));
374    if (logOn()) {
375      log(
376          "justified = %s, confidence = %s, samples = %s",
377          just, getConfidence(), ppt.num_samples());
378    }
379    return just;
380  }
381
382  // If confidence == CONFIDENCE_NEVER, then this invariant can be eliminated.
383  /**
384   * Given that this invariant has been true for all values seen so far, this method returns the
385   * confidence that that situation has occurred by chance alone.
386   *
387   * <p>Returns the probability that the observed data did not happen by chance alone. The result is
388   * a value between 0 and 1 inclusive. 0 means that this invariant could never have occurred by
389   * chance alone; we are fully confident that its truth is no coincidence. 1 means that the
390   * invariant is certainly a happenstance, so the truth of the invariant is not relevant and it
391   * should not be reported. Values between 0 and 1 give differing confidences in the invariant. The
392   * method may also return {@link #CONFIDENCE_NEVER}, meaning the invariant has been falsified.
393   *
394   * <p>An invariant is printed only if its probability of not occurring by chance alone is large
395   * enough (by default, greater than .99; see Daikon's --conf_limit command-line option.
396   *
397   * <p>As an example, consider the invariant "x!=0". If only one value, 22, has been seen for x,
398   * then the conclusion "x!=0" is not justified. But if there have been 1,000,000 values, and none
399   * of them were 0, then we may be confident that the property "x!=0" is not a coincidence.
400   *
401   * <p>This method is a wrapper around {@link #computeConfidence()}, which does the actual work.
402   *
403   * <p>Consider the invariant is 'x is even', which has a 50% chance of being true by chance for
404   * each sample. Then a reasonable body for {@link #computeConfidence} would be
405   *
406   * <pre>return 1 - Math.pow(.5, ppt.num_samples());</pre>
407   *
408   * If 5 values had been seen, then this implementation would return 31/32, which is the likelihood
409   * that all 5 values seen so far were even not purely by chance.
410   *
411   * @return confidence of this invariant
412   * @see #computeConfidence()
413   */
414  public final double getConfidence(@NonPrototype Invariant this) {
415    assert !falsified;
416    // if (falsified)
417    //   return CONFIDENCE_NEVER;
418    double result = computeConfidence();
419    // System.out.println("getConfidence: " + getClass().getName() + " " + ppt.varNames());
420    if (!((result == CONFIDENCE_JUSTIFIED)
421        || (result == CONFIDENCE_UNJUSTIFIED)
422        || (result == CONFIDENCE_NEVER)
423        || ((0 <= result) && (result <= 1)))) {
424      // Can't print this.repr_prob(), as it may compute the confidence!
425      System.out.println(
426          "getConfidence: " + getClass().getName() + " " + ppt.varNames() + " => " + result);
427      System.out.println("  " + this.format() + "; " + repr());
428    }
429    assert ((0 <= result) && (result <= 1))
430            || (result == CONFIDENCE_JUSTIFIED)
431            || (result == CONFIDENCE_UNJUSTIFIED)
432            || (result == CONFIDENCE_NEVER)
433        : "unexpected conf value: " + getClass().getName() + ": " + repr() + ", result=" + result;
434    return result;
435  }
436
437  /**
438   * This method computes the confidence that this invariant occurred by chance. Clients should call
439   * {@link #getConfidence()} instead.
440   *
441   * <p>This method need not check the value of field "falsified", as the caller does that.
442   *
443   * @return confidence of this invariant
444   * @see #getConfidence()
445   */
446  protected abstract double computeConfidence(@NonPrototype Invariant this);
447
448  /**
449   * Subclasses should override. An exact invariant indicates that given all but one variable value,
450   * the last one can be computed. (I think that's correct, anyway.) Examples are IntComparison
451   * (when only equality is possible), LinearBinary, FunctionUnary. OneOf is treated differently, as
452   * an interface. The result of this method does not depend on whether the invariant is justified,
453   * destroyed, etc.
454   *
455   * @return true if any variable value can be computed from all the others
456   */
457  @Pure
458  public boolean isExact(@Prototype Invariant this) {
459    return false;
460  }
461
462  // Implementations of this need to examine all the data values already
463  // in the ppt.  Or, don't put too much work in the constructor and instead
464  // have the caller do that.
465  // The "ppt" argument can be null if this is a prototype invariant.
466  protected Invariant(PptSlice ppt) {
467    this.ppt = ppt;
468    checkMergeOverridden();
469  }
470
471  @SuppressWarnings("nullness") // weakness in @Unused checking
472  protected @Prototype Invariant() {
473    this.ppt = null;
474    checkMergeOverridden();
475  }
476
477  @SuppressWarnings("unused")
478  @Pure
479  private boolean isPrototype() {
480    return this.ppt == null;
481  }
482
483  /**
484   * Marks the invariant as falsified. Should always be called rather than just setting the flag so
485   * that we can track when this happens.
486   */
487  public void falsify(@NonPrototype Invariant this) {
488    falsified = true;
489    if (logOn()) {
490      log("Destroyed %s", format());
491    }
492  }
493
494  /** Clear the falsified flag. */
495  public void clear_falsified(@NonPrototype Invariant this) {
496    falsified = false;
497  }
498
499  /**
500   * Returns whether or not this invariant has been falsified.
501   *
502   * @return true if this invariant has been falsified
503   */
504  @Pure
505  public boolean is_false(@NonPrototype Invariant this) {
506    return falsified;
507  }
508
509  /** Do nothing special, Overridden to remove exception from declaration. */
510  @SideEffectFree
511  @Override
512  public Invariant clone(@GuardSatisfied @NonPrototype Invariant this) {
513    try {
514      Invariant result = (Invariant) super.clone();
515      return result;
516    } catch (CloneNotSupportedException e) {
517      throw new Error(); // can never happen
518    }
519  }
520
521  /**
522   * Make a copy of this invariant and transfer it into a new PptSlice.
523   *
524   * @param new_ppt must have the same arity and types
525   * @param permutation gives the varinfo array index mapping in the new ppt
526   * @return a copy of the invariant, on a different slice
527   */
528  public Invariant transfer(@NonPrototype Invariant this, PptSlice new_ppt, int[] permutation) {
529    // Check some sanity conditions
530    assert new_ppt.arity() == ppt.arity();
531    assert permutation.length == ppt.arity();
532    for (int i = 0; i < ppt.arity(); i++) {
533      VarInfo oldvi = ppt.var_infos[i];
534      VarInfo newvi = new_ppt.var_infos[permutation[i]];
535      // We used to check that all 3 types were equal, but we can't do
536      // that anymore, because with equality, invariants may get
537      // transferred between old and new VarInfos of different types.
538      // They are, however, comparable
539      assert oldvi.comparableNWay(newvi);
540    }
541
542    Invariant result;
543    // Clone it
544    result = this.clone();
545
546    // Fix up the fields
547    result.ppt = new_ppt;
548    // Let subclasses fix what they need to
549    result = result.resurrect_done(permutation);
550
551    if (logOn()) {
552      result.log(
553          "Created %s:%s via transfer from %s:%s using permutation %s old_ppt = %s new_ppt = %s",
554          result.getClass().getName(),
555          result.format(),
556          getClass().getName(),
557          format(),
558          Arrays.toString(permutation),
559          ppt,
560          new_ppt);
561      // result.log (UtilPlume.backTrace());
562    }
563    // if (debug.isLoggable(Level.FINE))
564    //    debug.fine ("Invariant.transfer to " + new_ppt.name() + " "
565    //                 + result.repr());
566
567    return result;
568  }
569
570  /**
571   * Clones the invariant and then permutes it as specified. Normally used to make child invariant
572   * match the variable order of the parent when merging invariants bottom up.
573   */
574  public Invariant clone_and_permute(@NonPrototype Invariant this, int[] permutation) {
575
576    Invariant result = this.clone();
577    result = result.resurrect_done(permutation);
578
579    if (logOn()) {
580      result.log(
581          "Created %s via clone_and_permute from %s using permutation %s old_ppt = %s",
582          result.format(), format(), Arrays.toString(permutation), Arrays.toString(ppt.var_infos)
583          // + " new_ppt = " + Arrays.toString (new_ppt.var_infos)
584          );
585    }
586
587    return result;
588  }
589
590  /**
591   * Take a falsified invariant and resurrect it in a new PptSlice.
592   *
593   * @param new_ppt must have the same arity and types
594   * @param permutation gives the varinfo array index mapping
595   * @return the resurrected invariant, in a new PptSlice
596   */
597  public Invariant resurrect(@NonPrototype Invariant this, PptSlice new_ppt, int[] permutation) {
598    // Check some sanity conditions
599    assert falsified;
600    assert new_ppt.arity() == ppt.arity();
601    assert permutation.length == ppt.arity();
602    for (int i = 0; i < ppt.arity(); i++) {
603      VarInfo oldvi = ppt.var_infos[i];
604      VarInfo newvi = new_ppt.var_infos[permutation[i]];
605      // We used to check that all 3 types were equal, but we can't do
606      // that anymore, because with equality, invariants may get
607      // resurrected between old and new VarInfos of different types.
608      // They are, however, comparable
609      assert oldvi.comparableNWay(newvi);
610    }
611
612    Invariant result;
613    // Clone it
614    result = this.clone();
615
616    // Fix up the fields
617    result.falsified = false;
618    result.ppt = new_ppt;
619    // Let subclasses fix what they need to
620    result = result.resurrect_done(permutation);
621
622    if (logOn()) {
623      result.log(
624          "Created %s via resurrect from %s using permutation %s old_ppt = %s new_ppt = %s",
625          result.format(),
626          format(),
627          Arrays.toString(permutation),
628          Arrays.toString(ppt.var_infos),
629          Arrays.toString(new_ppt.var_infos));
630    }
631
632    return result;
633  }
634
635  /**
636   * Returns a single VarComparability that describes the set of variables used by this invariant.
637   * Since all of the variables in an invariant must be comparable, this can usually be the
638   * comparability information for any variable. The exception is when one or more variables is
639   * always comparable (comparable to everything else). An always comparable VarComparability is
640   * returned only if all of the variables involved are always comparable. Otherwise the
641   * comparability information from one of the non always-comparable variables is returned.
642   *
643   * @return a VarComparability that describes any (and all) of this invariant's variables
644   */
645  public VarComparability get_comparability(@NonPrototype Invariant this) {
646
647    // assert ppt != null : "class " + getClass();
648
649    // Return the first variable that is not always-comparable
650    for (int i = 0; i < ppt.var_infos.length; i++) {
651      VarComparability vc = ppt.var_infos[i].comparability;
652      if (!vc.alwaysComparable()) {
653        return vc;
654      }
655    }
656
657    // All the variables are always-comparable, just return the first one
658    // return ppt.var_infos[0].comparability;
659    return VarComparabilityImplicit.unknown;
660  }
661
662  /**
663   * Merge the invariants in invs to form a new invariant. This implementation merely returns a
664   * clone of the first invariant in the list. This is correct for simple invariants whose equation
665   * or statistics don't depend on the actual samples seen. It should be overriden for more complex
666   * invariants (eg, bound, oneof, linearbinary, etc).
667   *
668   * @param invs list of invariants to merge. The invariants must all be of the same type and should
669   *     come from the children of parent_ppt. They should also all be permuted to match the
670   *     variable order in parent_ppt.
671   * @param parent_ppt slice that will contain the new invariant
672   * @return the merged invariant or null if the invariants didn't represent the same invariant
673   */
674  public @Nullable @NonPrototype Invariant merge(
675      @Prototype Invariant this, List<@NonPrototype Invariant> invs, PptSlice parent_ppt) {
676
677    Invariant first = invs.get(0);
678    Invariant result = first.clone();
679    result.ppt = parent_ppt;
680    result.log(
681        "Merged '%s' from %s child invariants",
682        result.format(), invs.size() /*, first.ppt.name() */);
683
684    // Make sure that each invariant was really of the same type
685    boolean assert_enabled = false;
686    assert (assert_enabled = true);
687    // Now, assert_enabled is true if the JVM was started with the "-ea" command-line argument.
688    if (assert_enabled) {
689      Match m = new Match(result);
690      for (int i = 1; i < invs.size(); i++) {
691        assert m.equals(new Match(invs.get(i)));
692      }
693    }
694
695    return result;
696  }
697
698  /**
699   * Permutes the invariant as specified. Often creates a new invariant (with a different class).
700   *
701   * @param permutation the permutation
702   * @return the permuted invariant
703   */
704  public @NonPrototype Invariant permute(@NonPrototype Invariant this, int[] permutation) {
705    return resurrect_done(permutation);
706  }
707
708  /**
709   * Called on the new invariant just before resurrect() returns it to allow subclasses to fix any
710   * information they might have cached from the old Ppt and VarInfos.
711   *
712   * @param permutation the permutation
713   * @return the permuted invariant
714   */
715  protected abstract Invariant resurrect_done(@NonPrototype Invariant this, int[] permutation);
716
717  // Regrettably, I can't declare a static abstract method.
718  // // The return value is probably ignored.  The new Invariant installs
719  // // itself on the PptSlice, and that's what really matters (right?).
720  // public static abstract Invariant instantiate(PptSlice ppt);
721
722  /** Return true if this invariant uses the given variable. */
723  public boolean usesVar(@NonPrototype Invariant this, VarInfo vi) {
724    return ppt.usesVar(vi);
725  }
726
727  /** Return true if this invariant uses the given variable. */
728  public boolean usesVar(@NonPrototype Invariant this, String name) {
729    return ppt.usesVar(name);
730  }
731
732  /** Return true if this invariant uses the given variable or any variable derived from it. */
733  public boolean usesVarDerived(@NonPrototype Invariant this, String name) {
734    return ppt.usesVarDerived(name);
735  }
736
737  // Not used as of 1/31/2000
738  // // For use by subclasses.
739  // /** Put a string representation of the variable names in the StringBuilder. */
740  // public void varNames(StringBuilder sb) {
741  //   // sb.append(this.getClass().getName());
742  //   ppt.varNames(sb);
743  // }
744
745  /**
746   * Return a string representation of the variable names.
747   *
748   * @return a string representation of the variable names
749   */
750  public final String varNames(@GuardSatisfied @NonPrototype Invariant this) {
751    return ppt.varNames();
752  }
753
754  // repr()'s output should not include result of getConfidence, because
755  // repr() may be called from computeConfidence or elsewhere for
756  // debugging purposes.
757  /**
758   * For printing invariants, there are two interfaces: repr gives a low-level representation
759   * ({@link #repr_prob} also prints the confidence), and {@link #format} gives a high-level
760   * representation for user output.
761   *
762   * @return a string representation of this
763   */
764  public String repr(@GuardSatisfied @NonPrototype Invariant this) {
765    // A better default would be to use reflection and print out all
766    // the variable names.
767    return getClass() + varNames() + ": " + format();
768  }
769
770  /**
771   * For printing invariants, there are two interfaces: {@link #repr} gives a low-level
772   * representation (repr_prob also prints the confidence), and {@link #format} gives a high-level
773   * representation for user output.
774   *
775   * @return {@link #repr()}, but with the confidence as well
776   */
777  public String repr_prob(@NonPrototype Invariant this) {
778    return repr() + "; confidence = " + getConfidence();
779  }
780
781  /**
782   * Returns a high-level printed representation of the invariant, for user output. {@code format}
783   * produces normal output, while the {@link #repr} formatting routine produces low-level, detailed
784   * output for debugging, and {@link #repr_prob} also prints the confidence.
785   *
786   * @return a string representation of this
787   */
788  // Does not respect PrintInvariants.dkconfig_print_inv_class; PrintInvariants does so.
789  // Receiver must be fully-initialized because subclasses read their fields.
790  @SideEffectFree
791  public String format(@GuardSatisfied @NonPrototype Invariant this) {
792    return format_using(OutputFormat.DAIKON);
793  }
794
795  /**
796   * Returns the class name of the invariant, for use in debugging output. Returns "" if {@link
797   * PrintInvariants#dkconfig_print_inv_class} is false.
798   *
799   * @return a string representation of the class name of the invariant, or ""
800   */
801  public String format_classname() {
802    if (!PrintInvariants.dkconfig_print_inv_class) {
803      return "";
804    }
805    String classname = getClass().getName();
806    int index = classname.lastIndexOf('.');
807    classname = classname.substring(index + 1);
808    return " [" + classname + "]";
809  }
810
811  /** Return a printed representation of this invariant, in the given format. */
812  @SideEffectFree
813  public abstract String format_using(
814      @GuardSatisfied @NonPrototype Invariant this, OutputFormat format);
815
816  /**
817   * Returns a conjuction of mapping the same function of our expresssions's VarInfos, in general.
818   * Subclasses may override if they are able to handle generally-inexpressible properties in
819   * special-case ways.
820   *
821   * @return conjuction of mapping the same function of our expresssions's VarInfos
822   * @see VarInfo#isValidEscExpression
823   */
824  @Pure
825  public boolean isValidEscExpression(@NonPrototype Invariant this) {
826    for (int i = 0; i < ppt.var_infos.length; i++) {
827      if (!ppt.var_infos[i].isValidEscExpression()) {
828        return false;
829      }
830    }
831    return true;
832  }
833
834  /** A "\type(...)" construct where the "..." contains a "$". */
835  private static Pattern anontype_pat = Pattern.compile("\\\\type\\([^\\)]*\\$");
836
837  /**
838   * Returns true if this Invariant can be properly formatted for the given output format.
839   *
840   * @param format the expected output format
841   * @return true if this Invariant can be properly formatted for the given output format
842   */
843  @Pure
844  public boolean isValidExpression(@NonPrototype Invariant this, OutputFormat format) {
845    if ((format == OutputFormat.ESCJAVA) && !isValidEscExpression()) {
846      return false;
847    }
848
849    String s = format_using(format);
850
851    if ((format == OutputFormat.ESCJAVA) || format.isJavaFamily()) {
852      // This list should get shorter as we improve the formatting.
853      if ((s.indexOf(" needs to be implemented: ") != -1)
854          || (s.indexOf("<<") != -1)
855          || (s.indexOf(">>") != -1)
856          || (s.indexOf("warning: ") != -1)
857          || (s.indexOf('~') != -1)
858          || (s.indexOf("\\new") != -1)
859          || (s.indexOf(".toString ") != -1)
860          || s.endsWith(".toString")
861          || (s.indexOf(".typeArray") != -1)
862          || (s.indexOf("warning: method") != -1)
863          || (s.indexOf("inexpressible") != -1)
864          || (s.indexOf("unimplemented") != -1)
865          || (s.indexOf("Infinity") != -1)
866          || anontype_pat.matcher(s).find()) {
867        return false;
868      }
869    }
870    return true;
871  }
872
873  /**
874   * Returns standard "format needs to be implemented" for the given requested format. Made public
875   * so cores can call it.
876   *
877   * @param format the requested output format
878   * @return standard "format needs to be implemented" for the given requested format
879   */
880  public String format_unimplemented(
881      @GuardSatisfied @NonPrototype Invariant this, OutputFormat format) {
882    String classname = this.getClass().getName();
883    return "warning: method "
884        + classname
885        + ".format("
886        + format
887        + ")"
888        + " needs to be implemented: "
889        + format();
890  }
891
892  /**
893   * Returns standard "too few samples for to have interesting invariant" for the requested format.
894   * For machine-readable formats, this is just "true". An optional string argument, if supplied, is
895   * a human-readable description of the invariant in its uninformative state, which will be added
896   * to the message.
897   *
898   * @param format the requested output format
899   * @return standard "too few samples for to have interesting invariant" for the requested format
900   */
901  public String format_too_few_samples(
902      @GuardSatisfied @NonPrototype Invariant this, OutputFormat format, @Nullable String attempt) {
903    if (format == OutputFormat.SIMPLIFY) {
904      return "(AND)";
905    } else if (format == OutputFormat.JAVA
906        || format == OutputFormat.ESCJAVA
907        || format == OutputFormat.JML
908        || format == OutputFormat.DBCJAVA) {
909      return "true";
910    }
911    String classname = this.getClass().getName();
912    if (attempt == null) {
913      attempt = varNames();
914    }
915    return "warning: too few samples for " + classname + " invariant: " + attempt;
916  }
917
918  /**
919   * Convert a floating point value into the weird Modula-3-like floating point format that the
920   * Simplify tool requires.
921   *
922   * @param d the number to print
923   * @return a printed representation of the number, for Simplify
924   */
925  public static String simplify_format_double(double d) {
926    String s = d + "";
927    if (s.indexOf('E') != -1) {
928      // 1E6 -> 1d6
929      // 1.43E6 -> 1.43d6
930      s = s.replace('E', 'd');
931    } else if (s.indexOf('.') != -1) {
932      // 3.14 -> 3.14d0
933      s = s + "d0";
934    } else if (s.equals("-Infinity")) {
935      // -Infinity -> NegativeInfinity
936      s = "NegativeInfinity";
937    }
938    // 5 -> 5
939    // NaN -> NaN
940    // Infinity -> Infinity
941    return s;
942  }
943
944  /**
945   * Conver a long integer value into a format that Simplify can use. If the value is too big, we
946   * have to print it in a weird way, then tell Simplify about its properties specially.
947   *
948   * @param l the number to print
949   * @return a printed representation of the number, for Simplify
950   */
951  public static String simplify_format_long(long l) {
952    LemmaStack.noticeInt(l);
953    if (l > -LemmaStack.SMALL_INTEGER && l < LemmaStack.SMALL_INTEGER) {
954      // Simplify's internal numeric representation is based on
955      // (ratios of) signed 32-bit integers, so it can't be both sound
956      // and precise with respect to integer overflow. In its default
957      // configuration it crashes with an internal error when any
958      // internal computation overflows. To work around this, we print
959      // large integers in an abstract format, and then explicitly
960      // give the ordering among those values. This loses other
961      // arithmetic facts, but is good enough for the way we use it.
962      // Examples of inputs containing large integers that crash:
963      // > (BG_PUSH (< 2147483647 n))
964      // (assertion in negative argument to GCD)
965      // > (BG_PUSH (>= x -1073741825))
966      // > (BG_PUSH (<= x 1073741825))
967      // > (OR)
968      // (assertion: unexpected negative value in the Simplex engine)
969      // > (BG_PUSH (EQ x 56312))
970      // > (BG_PUSH (EQ y (* y x)))
971      // (assertion: negative denomniator in rational normalize)
972      // The value 32000 for SMALL_INTEGER is semi-empirically derived
973      // as "2**15 - some slop" in hopes of working around as many
974      // potential overflows in Simplify as possible, while still
975      // letting it do concrete arithmetic on small integers. It may
976      // be that there's no bound that would work with arbitrary
977      // formulas, but this one seems to work OK for formulas
978      // generated by Daikon.
979      return "" + l;
980    } else {
981      return SimpUtil.formatInteger(l);
982    }
983  }
984
985  /**
986   * Convert a string value into the weird |-quoted format that the Simplify tool requires. (Note
987   * that Simplify doesn't distinguish between variables, symbolic constants, and strings, so we
988   * prepend "_string_" to avoid collisions with variables and other symbols).
989   *
990   * @param s the number to print
991   * @return a printed representation of the string, for Simplify
992   */
993  public static String simplify_format_string(String s) {
994    if (s == null) {
995      return "null";
996    }
997    StringBuilder buf = new StringBuilder("|_string_");
998    if (s.length() > 150) {
999      // Simplify can't handle long strings (its input routines have a
1000      // 4000-character limit for |...| identifiers, but it gets an
1001      // internal array overflow for ones more than about 195
1002      // characters), so replace all but the beginning and end of a
1003      // long string with a hashed summary.
1004      int summ_length = s.length() - 100;
1005      int p1 = 50 + summ_length / 4;
1006      int p2 = 50 + summ_length / 2;
1007      int p3 = 50 + 3 * summ_length / 4;
1008      int p4 = 50 + summ_length;
1009      StringBuilder summ_buf = new StringBuilder(s.substring(0, 50));
1010      summ_buf.append("...");
1011      summ_buf.append(Integer.toHexString(s.substring(50, p1).hashCode()));
1012      summ_buf.append(Integer.toHexString(s.substring(p1, p2).hashCode()));
1013      summ_buf.append(Integer.toHexString(s.substring(p2, p3).hashCode()));
1014      summ_buf.append(Integer.toHexString(s.substring(p3, p4).hashCode()));
1015      summ_buf.append("...");
1016      summ_buf.append(s.substring(p4));
1017      s = summ_buf.toString();
1018    }
1019    for (int i = 0; i < s.length(); i++) {
1020      char c = s.charAt(i);
1021      // The following line uses '\n' rather than linesep.
1022      if (c == '\n') buf.append("\\n");
1023      else if (c == '\r') buf.append("\\r");
1024      else if (c == '\t') buf.append("\\t");
1025      else if (c == '\f') buf.append("\\f");
1026      else if (c == '\\') buf.append("\\\\");
1027      else if (c == '|') buf.append("\\|");
1028      else if (c >= ' ' && c <= '~') buf.append(c);
1029      else {
1030        buf.append("\\");
1031        // AFAIK, Simplify doesn't glork Unicode, so lop off all but
1032        // the low 8 bits
1033        String octal = Integer.toOctalString(c & 0xff);
1034        // Also, Simplify only accepts octal escapes with exactly 3 digits
1035        while (octal.length() < 3) octal = "0" + octal;
1036        buf.append(octal);
1037      }
1038    }
1039    buf.append("|");
1040    return buf.toString();
1041  }
1042
1043  // This should perhaps be merged with some kind of PptSlice comparator.
1044  /** Compare based on arity, then printed representation. */
1045  public static final class InvariantComparatorForPrinting implements Comparator<Invariant> {
1046    @Pure
1047    @Override
1048    public int compare(@NonPrototype Invariant inv1, @NonPrototype Invariant inv2) {
1049      if (inv1 == inv2) {
1050        return 0;
1051      }
1052
1053      // Guarding implications should compare as if they were without the
1054      // guarding predicate
1055
1056      if (inv1 instanceof GuardingImplication) {
1057        inv1 = ((GuardingImplication) inv1).right;
1058      }
1059      if (inv2 instanceof GuardingImplication) {
1060        inv2 = ((GuardingImplication) inv2).right;
1061      }
1062
1063      // Put equality invariants first
1064      if ((inv1 instanceof EqualityComparison) && !(inv2 instanceof EqualityComparison)) {
1065        return -1;
1066      }
1067      if (!(inv1 instanceof EqualityComparison) && (inv2 instanceof EqualityComparison)) {
1068        return 1;
1069      }
1070
1071      // assert inv1.ppt.parent == inv2.ppt.parent;
1072      VarInfo[] vis1 = inv1.ppt.var_infos;
1073      VarInfo[] vis2 = inv2.ppt.var_infos;
1074      int arity_cmp = vis1.length - vis2.length;
1075      if (arity_cmp != 0) {
1076        return arity_cmp;
1077      }
1078      // Comparing on variable index is wrong in general:  variables of the
1079      // same name may have different indices at different program points.
1080      // However, it's safe if the invariants are from the same program
1081      // point.  Also, it is nice to avoid changing the order of variables
1082      // from that of the data trace file.
1083
1084      if (inv1.ppt.parent == inv2.ppt.parent) {
1085        for (int i = 0; i < vis1.length; i++) {
1086          int tmp = vis1[i].varinfo_index - vis2[i].varinfo_index;
1087          if (tmp != 0) {
1088            return tmp;
1089          }
1090        }
1091      } else {
1092        // // Debugging
1093        // System.out.println("ICFP: different parents for " + inv1.format() + ", " +
1094        // inv2.format());
1095
1096        for (int i = 0; i < vis1.length; i++) {
1097          String name1 = vis1[i].name();
1098          String name2 = vis2[i].name();
1099          if (name1.equals(name2)) {
1100            continue;
1101          }
1102          int name1in2 = inv2.ppt.parent.indexOf(name1);
1103          int name2in1 = inv1.ppt.parent.indexOf(name2);
1104          int cmp1 = (name1in2 == -1) ? 0 : vis1[i].varinfo_index - name1in2;
1105          int cmp2 = (name2in1 == -1) ? 0 : vis2[i].varinfo_index - name2in1;
1106          int cmp = MathPlume.sign(cmp1) + MathPlume.sign(cmp2);
1107          if (cmp != 0) {
1108            return cmp;
1109          }
1110        }
1111      }
1112
1113      // Sort OneOf invariants earlier than others
1114      if ((inv1 instanceof OneOf) && !(inv2 instanceof OneOf)) {
1115        return -1;
1116      }
1117      if (!(inv1 instanceof OneOf) && (inv2 instanceof OneOf)) {
1118        return 1;
1119      }
1120
1121      // System.out.println("ICFP: default rule yields "
1122      //                    + inv1.format().compareTo(inv2.format())
1123      //                    + " for " + inv1.format() + ", " + inv2.format());
1124      // (Actually, FileIO.new_decl_format should always be non-null here.)
1125      if (PrintInvariants.dkconfig_old_array_names
1126          && FileIO.new_decl_format != null
1127          && FileIO.new_decl_format) {
1128        return inv1.format().replace("[..]", "[]").compareTo(inv2.format().replace("[..]", "[]"));
1129      } else {
1130        return inv1.format().compareTo(inv2.format());
1131      }
1132    }
1133  }
1134
1135  /**
1136   * Returns true iff the two invariants represent the same mathematical formula. Does not consider
1137   * the context such as variable names, confidences, sample counts, value counts, or related
1138   * quantities. As a rule of thumb, if two invariants format the same, this method returns true.
1139   * Furthermore, in many cases, if an invariant does not involve computed constants (as "x&gt;c"
1140   * and "y=ax+b" do for constants a, b, and c), then this method vacuously returns true.
1141   *
1142   * @param other the invariant to compare to this one
1143   * @return true iff the two invariants represent the same mathematical formula. Does not consider
1144   * @exception RuntimeException if other.getClass() != this.getClass()
1145   */
1146  public abstract boolean isSameFormula(@Prototype Invariant this, Invariant other);
1147
1148  /**
1149   * Returns whether or not it is possible to merge invariants of the same class but with different
1150   * formulas when combining invariants from lower ppts to build invariants at upper program points.
1151   * Invariants that have this characteristic (eg, bound, oneof) should override this function. Note
1152   * that invariants that can do this, normally need special merge code as well (to merge the
1153   * different formulas into a single formula at the upper point.
1154   *
1155   * @return true if invariants with different formulas can be merged
1156   */
1157  public boolean mergeFormulasOk(@Prototype Invariant this) {
1158    return false;
1159  }
1160
1161  /**
1162   * Returns true iff the argument is the "same" invariant as this. Same, in this case, means a
1163   * matching type, formula, and variable names.
1164   *
1165   * @param inv2 the other invariant to compare to this one
1166   * @return true iff the argument is the "same" invariant as this
1167   */
1168  @Pure
1169  public boolean isSameInvariant(@NonPrototype Invariant this, Invariant inv2) {
1170    // return isSameInvariant(inv2, defaultIsSameInvariantNameExtractor);
1171
1172    Invariant inv1 = this;
1173
1174    // Can't be the same if they aren't the same type
1175    if (!inv1.getClass().equals(inv2.getClass())) {
1176      return false;
1177    }
1178
1179    // Can't be the same if they aren't the same formula
1180    if (!inv1.isSameFormula(inv2)) {
1181      return false;
1182    }
1183
1184    // The variable names much match up, in order
1185    VarInfo[] vars1 = inv1.ppt.var_infos;
1186    VarInfo[] vars2 = inv2.ppt.var_infos;
1187
1188    // due to inv type match already
1189    assert vars1.length == vars2.length;
1190
1191    for (int i = 0; i < vars1.length; i++) {
1192      VarInfo var1 = vars1[i];
1193      VarInfo var2 = vars2[i];
1194      if (!var1.name().equals(var2.name())) {
1195        return false;
1196      }
1197    }
1198
1199    return true;
1200  }
1201
1202  /**
1203   * Returns true iff the two invariants represent mutually exclusive mathematical formulas -- that
1204   * is, if one of them is true, then the other must be false. This method does not consider the
1205   * context such as variable names, confidences, sample counts, value counts, or related
1206   * quantities.
1207   *
1208   * @param other the other invariant to compare to this one
1209   * @return true iff the two invariants represent mutually exclusive mathematical formulas
1210   */
1211  @Pure
1212  public boolean isExclusiveFormula(@NonPrototype Invariant this, Invariant other) {
1213    return false;
1214  }
1215
1216  /**
1217   * Look up a previously instantiated Invariant.
1218   *
1219   * @param invclass the class of the invariant to search for
1220   * @param ppt the program point in which to look for the invariant
1221   * @return the invariant of class invclass, or null if none was found
1222   */
1223  // This implementation should be made more efficient, because it's used in
1224  // suppression.  We should somehow index invariants by their type.
1225  public static @Nullable Invariant find(Class<? extends Invariant> invclass, PptSlice ppt) {
1226    for (Invariant inv : ppt.invs) {
1227      if (inv.getClass() == invclass) {
1228        return inv;
1229      }
1230    }
1231    return null;
1232  }
1233
1234  /**
1235   * Returns the set of non-instantiating suppressions for this invariant. May return null instead
1236   * of an empty set. Should be overridden by subclasses with non-instantiating suppressions.
1237   *
1238   * @return the set of non-instantiating suppressions for this invariant
1239   */
1240  @Pure
1241  public @Nullable NISuppressionSet get_ni_suppressions(@Prototype Invariant this) {
1242    return null;
1243  }
1244
1245  /**
1246   * Returns whether or not this invariant is ni-suppressed.
1247   *
1248   * @return true if this invariant is ni-suppressed
1249   */
1250  @SuppressWarnings(
1251      "nullness") // tricky control flow, need to mark get_ni_suppressions as @Pure if that's true
1252  @EnsuresNonNullIf(result = true, expression = "get_ni_suppressions()")
1253  @Pure
1254  public boolean is_ni_suppressed() {
1255
1256    NISuppressionSet ss = get_ni_suppressions();
1257    if (ss == null) {
1258      return false;
1259    }
1260    boolean suppressed = ss.suppressed(ppt);
1261    if (suppressed && Debug.logOn() && (Daikon.current_inv != null)) {
1262      Daikon.current_inv.log("inv %s suppressed: %s", format(), ss);
1263    }
1264    if (Debug.logDetail()) {
1265      log("suppressed = %s suppression set = %s", suppressed, ss);
1266    }
1267
1268    return suppressed;
1269  }
1270
1271  // ///////////////////////////////////////////////////////////////////////////
1272  // Tests about the invariant (for printing)
1273  //
1274
1275  // DO NOT OVERRIDE.  Should be declared "final", but the "final" is
1276  // omitted to allow for easier testing.
1277  @Pure
1278  public boolean isWorthPrinting(@NonPrototype Invariant this) {
1279    return InvariantFilters.defaultFilters().shouldKeep(this) == null;
1280  }
1281
1282  // ////////////////////////////////////////////////////////////////////////////
1283  // Static and dynamic checks for obviousness
1284
1285  /**
1286   * Return true if this invariant is necessarily true from a fact that can be determined statically
1287   * from the decls files. (An example is being from a certain derivation.) Intended to be
1288   * overridden by subclasses.
1289   *
1290   * <p>This method is final because children of Invariant should be extending
1291   * isObviousStatically(VarInfo[]) because it is more general.
1292   */
1293  @Pure
1294  public final @Nullable DiscardInfo isObviousStatically(@NonPrototype Invariant this) {
1295    return isObviousStatically(this.ppt.var_infos);
1296  }
1297
1298  /**
1299   * Return true if this invariant is necessarily true from a fact that can be determined statically
1300   * -- for the given varInfos rather than the varInfos of this. Conceptually, this means "is this
1301   * invariant statically obvious if its VarInfos were switched with vis?" Intended to be overridden
1302   * by subclasses. Should only do static checking.
1303   *
1304   * <p>Precondition: vis.length == this.ppt.var_infos.length
1305   *
1306   * @param vis the VarInfos this invariant is obvious over. The position and data type of the
1307   *     variables is the *same* as that of this.ppt.var_infos.
1308   */
1309  @Pure
1310  public @Nullable DiscardInfo isObviousStatically(@Prototype Invariant this, VarInfo[] vis) {
1311    return null;
1312  }
1313
1314  /**
1315   * Return true if this invariant and all equality combinations of its member variables are
1316   * necessarily true from a fact that can be determined statically (i.e., the decls files). For
1317   * example, a == b, and f(a) is obvious, but f(b) is not. In that case, this method on f(a) would
1318   * return false. If f(b) is also obvious, then this method would return true.
1319   */
1320  // This is used because we cannot decide to non-instantiate some
1321  // invariants just because isObviousStatically is true, since some
1322  // of the member variables may be equal to non-obvious varInfos.  If
1323  // we were to non-instantiate, we could not copy an invariant to the
1324  // non-obvious VarInfos should they split off from the obvious one.
1325  // Of course, it's expensive to examine every possible permutation
1326  // of VarInfos and their equality set, so a possible conservative
1327  // approximation is to simply return false.
1328  @Pure
1329  public boolean isObviousStatically_AllInEquality(@NonPrototype Invariant this) {
1330    // If the leaders aren't statically obvious, then clearly not all
1331    // combinations are.
1332    if (isObviousStatically() == null) {
1333      return false;
1334    }
1335
1336    for (int i = 0; i < ppt.var_infos.length; i++) {
1337      if (ppt.var_infos[i].equalitySet.getVars().size() > 1) {
1338        return false;
1339      }
1340    }
1341    return true;
1342  }
1343
1344  /**
1345   * Return true if this invariant and some equality combinations of its member variables are
1346   * statically obvious. For example, if a == b, and f(a) is obvious, then so is f(b). We use the
1347   * someInEquality (or least interesting) method during printing so we only print an invariant if
1348   * all its variables are interesting, since a single, static, non interesting occurance means all
1349   * the equality combinations aren't interesting.
1350   *
1351   * @return the VarInfo array that contains the VarInfos that showed this invariant to be obvious.
1352   *     The contains variables that are elementwise in the same equality set as this.ppt.var_infos.
1353   *     Can be null if no such assignment exists.
1354   */
1355  @Pure
1356  public @Nullable DiscardInfo isObviousStatically_SomeInEquality(@NonPrototype Invariant this) {
1357    DiscardInfo result = isObviousStatically();
1358    if (result != null) {
1359      return result;
1360    }
1361    return isObviousStatically_SomeInEqualityHelper(
1362        this.ppt.var_infos, new /*NNC:@MonotonicNonNull*/ VarInfo[this.ppt.var_infos.length], 0);
1363  }
1364
1365  // TODO: finish this comment.
1366  /** Recurse through vis and generate the cartesian product of ... */
1367  @Pure
1368  protected @Nullable DiscardInfo isObviousStatically_SomeInEqualityHelper(
1369      @NonPrototype Invariant this,
1370      VarInfo[] vis,
1371      /*NNC:@MonotonicNonNull*/ VarInfo[] assigned,
1372      int position) {
1373    if (position == vis.length) {
1374      if (debugIsObvious.isLoggable(Level.FINE)) {
1375        StringBuilder sb = new StringBuilder();
1376        sb.append("  isObviousStatically_SomeInEquality: ");
1377        for (int i = 0; i < vis.length; i++) {
1378          sb.append(assigned[i].name() + " ");
1379        }
1380        debugIsObvious.fine(sb.toString());
1381      }
1382
1383      assigned = castNonNullDeep(assigned); // https://tinyurl.com/cfissue/986
1384      return isObviousStatically(assigned);
1385    } else {
1386      for (VarInfo vi : vis[position].get_equalitySet_vars()) {
1387        assigned[position] = vi;
1388        DiscardInfo temp = isObviousStatically_SomeInEqualityHelper(vis, assigned, position + 1);
1389        if (temp != null) {
1390          return temp;
1391        }
1392      }
1393      return null;
1394    }
1395  }
1396
1397  /**
1398   * Return true if this invariant is necessarily true from a fact that can be determined statically
1399   * (i.e., the decls files) or dynamically (after checking data). Intended not to be overriden,
1400   * because sub-classes should override isObviousStatically or isObviousDynamically. Wherever
1401   * possible, suppression, rather than this, should do the dynamic checking.
1402   */
1403  @Pure
1404  public final @Nullable DiscardInfo isObvious(@NonPrototype Invariant this) {
1405    // Actually actually, we'll eliminate invariants as they become obvious
1406    // rather than on output; the point of this is to speed up computation.
1407    // // Actually, we do need to check isObviousDerived after all because we
1408    // // add invariants that might be obvious, but might also turn out to be
1409    // // even stronger (and so not obvious).  We don't know how the invariant
1410    // // turns out until after testing it.
1411    // // // We don't need to check isObviousDerived because we won't add
1412    // // // obvious-derived invariants to lists in the first place.
1413    DiscardInfo staticResult = isObviousStatically_SomeInEquality();
1414    if (staticResult != null) {
1415      if (debugPrint.isLoggable(Level.FINE)) {
1416        debugPrint.fine("  [obvious:  " + repr_prob() + " ]");
1417      }
1418      return staticResult;
1419    } else {
1420      DiscardInfo dynamicResult = isObviousDynamically_SomeInEquality();
1421      if (dynamicResult != null) {
1422        if (debugPrint.isLoggable(Level.FINE)) {
1423          debugPrint.fine("  [obvious:  " + repr_prob() + " ]");
1424        }
1425        return dynamicResult;
1426      } else {
1427        return null;
1428      }
1429    }
1430  }
1431
1432  /**
1433   * Return non-null if this invariant is necessarily true from a fact that can be determined
1434   * dynamically (after checking data) -- for the given varInfos rather than the varInfos of this.
1435   * Conceptually, this means, "Is this invariant dynamically obvious if its VarInfos were switched
1436   * with vis?" Intended to be overriden by subclasses so they can filter invariants after checking;
1437   * the overriding method should first call "super.isObviousDynamically(vis)". Since this method is
1438   * dynamic, it should only be called after all processing.
1439   */
1440  public @Nullable DiscardInfo isObviousDynamically(@NonPrototype Invariant this, VarInfo[] vis) {
1441    assert !Daikon.isInferencing;
1442    assert vis.length <= 3 : "Unexpected more-than-ternary invariant";
1443    if (!ArraysPlume.hasNoDuplicates(vis)) {
1444      log("Two or more variables are equal %s", format());
1445      return new DiscardInfo(this, DiscardCode.obvious, "Two or more variables are equal");
1446    }
1447    // System.out.println("Passed Invariant.isObviousDynamically(): " + format());
1448    return null;
1449  }
1450
1451  /**
1452   * Return true if more than one of the variables in the invariant are the same variable. We create
1453   * such invariants for the purpose of equality set processing, but they aren't intended for
1454   * printing; there should be invariants with the same meaning but lower arity instead. For
1455   * instance, we don't need "x = x + x" because we have "x = 0" instead.
1456   *
1457   * <p>Actually, this isn't strictly true: we don't have an invariant "a[] is a palindrome"
1458   * corresponding to "a[] is the reverse of a[]", for instance.
1459   *
1460   * @return true if more than one of the variables in the invariant are the same variable
1461   */
1462  @Pure
1463  public boolean isReflexive(@NonPrototype Invariant this) {
1464    return !ArraysPlume.hasNoDuplicates(ppt.var_infos);
1465  }
1466
1467  /**
1468   * Return true if this invariant is necessarily true from a fact that can be determined
1469   * dynamically (after checking data, based on other invariants that were inferred). Since this
1470   * method is dynamic, it should only be called after all processing.
1471   *
1472   * <p>If a test does not look up other inferred invariants (that is, it relies only on information
1473   * in the decls file), then it should be written as an isObviousStatically test, not an
1474   * isObviousDynamically test.
1475   *
1476   * <p>This method is final because subclasses should extend isObviousDynamically(VarInfo[]) since
1477   * that method is more general.
1478   */
1479  public final @Nullable DiscardInfo isObviousDynamically(@NonPrototype Invariant this) {
1480    assert !Daikon.isInferencing;
1481    return isObviousDynamically(ppt.var_infos);
1482  }
1483
1484  /**
1485   * Return true if this invariant and some equality combinations of its member variables are
1486   * dynamically obvious. For example, a == b, and f(a) is obvious, so is f(b). We use the
1487   * someInEquality (or least interesting) method during printing so we only print an invariant if
1488   * all its variables are interesting, since a single, dynamic, non interesting occurance means all
1489   * the equality combinations aren't interesting.
1490   *
1491   * @return the VarInfo array that contains the VarInfos that showed this invariant to be obvious.
1492   *     The contains variables that are elementwise in the same equality set as this.ppt.var_infos.
1493   *     Can be null if no such assignment exists.
1494   */
1495  @Pure
1496  public @Nullable DiscardInfo isObviousDynamically_SomeInEquality(@NonPrototype Invariant this) {
1497    DiscardInfo result = isObviousDynamically();
1498    if (result != null) {
1499      return result;
1500    }
1501    return isObviousDynamically_SomeInEqualityHelper(
1502        this.ppt.var_infos, new /*NNC:@MonotonicNonNull*/ VarInfo[this.ppt.var_infos.length], 0);
1503  }
1504
1505  /**
1506   * Recurse through vis (an array of leaders) and generate the cartesian product of their equality
1507   * sets; in other words, every combination of one element from each equality set. For each such
1508   * combination, test isObviousDynamically; if any test is true, then return that combination. The
1509   * combinations are generated via recursive calls to this routine.
1510   */
1511  protected @Nullable DiscardInfo isObviousDynamically_SomeInEqualityHelper(
1512      @NonPrototype Invariant this, VarInfo[] vis, VarInfo[] assigned, int position) {
1513    if (position == vis.length) {
1514      // base case
1515      if (debugIsObvious.isLoggable(Level.FINE)) {
1516        StringBuilder sb = new StringBuilder();
1517        sb.append("  isObviousDynamically_SomeInEquality: ");
1518        for (int i = 0; i < vis.length; i++) {
1519          sb.append(assigned[i].name() + " ");
1520        }
1521        debugIsObvious.fine(sb.toString());
1522      }
1523      return isObviousDynamically(assigned);
1524    } else {
1525      // recursive case
1526      for (VarInfo vi : vis[position].get_equalitySet_vars()) {
1527        assigned[position] = vi;
1528        DiscardInfo temp = isObviousDynamically_SomeInEqualityHelper(vis, assigned, position + 1);
1529        if (temp != null) {
1530          return temp;
1531        }
1532      }
1533      return null;
1534    }
1535  }
1536
1537  /**
1538   * Returns true if this invariant is only over prestate variables.
1539   *
1540   * @return true if this invariant is only over prestate variables
1541   */
1542  @Pure
1543  public boolean isAllPrestate(@NonPrototype Invariant this) {
1544    return ppt.allPrestate();
1545  }
1546
1547  /**
1548   * An invariant that includes an uninteresting constant (say, "size(x[]) &lt; 237") is likely to
1549   * be an artifact of the way the program was tested, rather than a statement that would in fact
1550   * hold over all possible executions.
1551   */
1552  public boolean hasUninterestingConstant(@NonPrototype Invariant this) {
1553    return false;
1554  }
1555
1556  // Orders invariants by class, then by variable names.  If the
1557  // invariants are both of class Implication, they are ordered by
1558  // comparing the predicate, then the consequent.
1559  public static final class ClassVarnameComparator implements Comparator<Invariant> {
1560    @Pure
1561    @Override
1562    public int compare(Invariant inv1, Invariant inv2) {
1563
1564      if (inv1 instanceof Implication && inv2 instanceof Implication) {
1565        return compareImplications((Implication) inv1, (Implication) inv2);
1566      }
1567
1568      int compareClass = compareClass(inv1, inv2);
1569      if (compareClass != 0) {
1570        return compareClass;
1571      }
1572
1573      return compareVariables(inv1, inv2);
1574    }
1575
1576    // Returns 0 if the invariants are of the same class.  Else,
1577    // returns the comparison of the class names.
1578    private int compareClass(Invariant inv1, Invariant inv2) {
1579      if (inv1.getClass().equals(inv2.getClass())) {
1580        if (inv1 instanceof DummyInvariant) {
1581          // This special case is needed because the other code
1582          // assumes that all invariants of a given class have the
1583          // same arity.
1584          String df1 = inv1.format();
1585          String df2 = inv2.format();
1586          int cmp = df1.compareTo(df2);
1587          if (cmp != 0) {
1588            return cmp;
1589          }
1590          return inv1.ppt.var_infos.length - inv2.ppt.var_infos.length;
1591        }
1592        return 0;
1593      } else {
1594        String classname1 = inv1.getClass().getName();
1595        String classname2 = inv2.getClass().getName();
1596        return classname1.compareTo(classname2);
1597      }
1598    }
1599
1600    // Returns 0 if the invariants have the same variable names.
1601    // Else, returns the comparison of the first variable names that
1602    // differ.  Requires that the invariants be of the same class.
1603    private int compareVariables(Invariant inv1, Invariant inv2) {
1604      VarInfo[] vars1 = inv1.ppt.var_infos;
1605      VarInfo[] vars2 = inv2.ppt.var_infos;
1606
1607      // due to inv type match already
1608      assert vars1.length == vars2.length
1609          : "Bad type match: " + inv1.format() + " vs. " + inv2.format();
1610
1611      for (int i = 0; i < vars1.length; i++) {
1612        VarInfo var1 = vars1[i];
1613        VarInfo var2 = vars2[i];
1614        int compare = var1.name().compareTo(var2.name());
1615        if (compare != 0) {
1616          return compare;
1617        }
1618      }
1619
1620      // All the variable names matched
1621      return 0;
1622    }
1623
1624    private int compareImplications(Implication inv1, Implication inv2) {
1625      int comparePredicate = compare(inv1.predicate(), inv2.predicate());
1626      if (comparePredicate != 0) {
1627        return comparePredicate;
1628      }
1629
1630      return compare(inv1.consequent(), inv2.consequent());
1631    }
1632  }
1633
1634  /**
1635   * Orders invariants by class, then variable names, then formula. If the formulas are the same,
1636   * compares the printed representation obtained from the format() method.
1637   */
1638  public static final class ClassVarnameFormulaComparator implements Comparator<Invariant> {
1639
1640    Comparator<Invariant> classVarnameComparator = new ClassVarnameComparator();
1641
1642    @Pure
1643    @Override
1644    public int compare(@NonPrototype Invariant inv1, @NonPrototype Invariant inv2) {
1645      int compareClassVarname = classVarnameComparator.compare(inv1, inv2);
1646
1647      if (compareClassVarname != 0) {
1648        return compareClassVarname;
1649      }
1650
1651      if (inv1.isSameInvariant(inv2)) {
1652        return 0;
1653      }
1654
1655      int result = inv1.format().compareTo(inv2.format());
1656
1657      // The purpose of the assertion below would seem to be to insist that
1658      // anything that doesn't return true to isSameInvariant() will not
1659      // produce the same written formula.  This can happen, however, if the
1660      // variables have a different order (as in function binary), but the
1661      // swapped variables are actually the same (since we create invariants
1662      // of the form f(a, a, a) because of equality sets.
1663      // assert result != 0
1664      //                   : "isSameInvariant() returned false "
1665      //                   + "(isSameFormula returned " + inv1.isSameFormula(inv2) + ")," + lineSep
1666      //                   + "but format().compareTo() returned 0:" + lineSep
1667      //                   + "  " + inv1.format() + lineSep + "      "  + inv1.repr() + lineSep
1668      //                   + "    " + inv1.ppt.parent.name + lineSep
1669      //                   + "  " + inv2.format() + lineSep + "      "  + inv2.repr() + lineSep
1670      //                   + "    " + inv1.ppt.parent.name + lineSep
1671      //                  ;
1672
1673      return result;
1674    }
1675  }
1676
1677  /**
1678   * Class used as a key to store invariants in a MAP where their equality depends on the invariant
1679   * representing the same invariant (i.e., their class is the same) and the same internal state
1680   * (when multiple invariants with the same class are possible).
1681   *
1682   * <p>Note that this is based on the Invariant type (i.e., class) and the internal state and not
1683   * on what ppt the invariant is in or what variables it is over. Thus, invariants from different
1684   * ppts are the same if they represent the same type of invariant.
1685   */
1686  public static class Match {
1687
1688    public Invariant inv;
1689
1690    public Match(Invariant inv) {
1691      this.inv = inv;
1692    }
1693
1694    @EnsuresNonNullIf(result = true, expression = "#1")
1695    @Pure
1696    @Override
1697    public boolean equals(@GuardSatisfied Match this, @GuardSatisfied @Nullable Object obj) {
1698      if (!(obj instanceof Match)) {
1699        return false;
1700      }
1701
1702      Match ic = (Match) obj;
1703      return ic.inv.match(inv);
1704    }
1705
1706    @Pure
1707    @Override
1708    public int hashCode(@GuardSatisfied Match this) {
1709      return inv.getClass().hashCode();
1710    }
1711  }
1712
1713  /**
1714   * Returns whether or not two invariants are of the same type. To be of the same type, invariants
1715   * must be of the same class. Some invariant classes represent multiple invariants (such as
1716   * FunctionBinary). They must also be the same formula. Note that invariants with different
1717   * formulas based on their samples (LinearBinary, Bounds, etc) will still match as long as the
1718   * mergeFormulaOk() method returns true.
1719   */
1720  public boolean match(@Prototype Invariant inv) {
1721
1722    if (inv.getClass() == getClass()) {
1723      return inv.mergeFormulasOk() || isSameFormula(inv);
1724    } else {
1725      return false;
1726    }
1727  }
1728
1729  /**
1730   * Returns whether or not the invariant matches the specified state. Must be overriden by
1731   * subclasses that support this. Otherwise, it returns true only if the state is null.
1732   */
1733  public boolean state_match(@NonPrototype Invariant this, Object state) {
1734    return (state == null);
1735  }
1736
1737  /** Create a guarding predicate for a given invariant. Returns null if no guarding is needed. */
1738  public @Nullable @NonPrototype Invariant createGuardingPredicate(boolean install) {
1739    if (debugGuarding.isLoggable(Level.FINE)) {
1740      debugGuarding.fine("Guarding predicate being created for: ");
1741      debugGuarding.fine("  " + this.format());
1742    }
1743
1744    // Find which VarInfos must be guarded
1745    List<VarInfo> mustBeGuarded = getGuardingList();
1746
1747    if (mustBeGuarded.isEmpty()) {
1748      if (debugGuarding.isLoggable(Level.FINE)) {
1749        debugGuarding.fine("No guarding is needed, returning");
1750      }
1751      return null;
1752    }
1753
1754    // This conjunction would look better if it was built up right-to-left.
1755    Invariant guardingPredicate = null;
1756    for (VarInfo vi : mustBeGuarded) {
1757      Invariant currentGuard = vi.createGuardingPredicate(install);
1758      if (currentGuard == null) {
1759        continue;
1760      }
1761      debugGuarding.fine(String.format("VarInfo %s guard is %s", vi, currentGuard));
1762      if (guardingPredicate == null) {
1763        guardingPredicate = currentGuard;
1764      } else {
1765        guardingPredicate = new AndJoiner(ppt.parent, guardingPredicate, currentGuard);
1766      }
1767      debugGuarding.fine(String.format("  predicate so far: %s", guardingPredicate));
1768    }
1769
1770    // If the guarding predicate has been previously constructed, return it.
1771    // Otherwise, we will return the newly constructed one.
1772    // This algorithm is inefficient.
1773    if (guardingPredicate != null) { // equivalently: mustBeGuarded.size() > 1
1774      List<Invariant> joinerViewInvs = ppt.parent.joiner_view.invs;
1775      for (Invariant currentInv : joinerViewInvs) {
1776        if (currentInv.isSameInvariant(guardingPredicate)) {
1777          return currentInv;
1778        }
1779      }
1780    }
1781    return guardingPredicate;
1782  }
1783
1784  /**
1785   * Return a list of all the variables that must be non-null in order for this invariant to be
1786   * evaluated. For instance, it this invariant is "a.b.c &gt; d.e" (where c and e are of integer
1787   * type), then it doesn't make sense to evaluate the invariant unless "a" is non-null, "a.b" is
1788   * non-null, and "d" is non-null. So, another way to write the invariant (in "guarded" form) would
1789   * be "a != null &amp;&amp; a.b != null &amp;&amp; d != null &amp;&amp; a.b.c &gt; d.e".
1790   */
1791  public List<VarInfo> getGuardingList(@NonPrototype Invariant this) {
1792    return getGuardingList(ppt.var_infos);
1793  }
1794
1795  /**
1796   * Returns the union of calling VarInfo.getGuardingList on each element of the argument.
1797   *
1798   * @param varInfos an array of VarInfo
1799   * @return the union of calling VarInfo.getGuardingList on each element of the argument
1800   */
1801  public static List<VarInfo> getGuardingList(VarInfo[] varInfos) {
1802    List<VarInfo> guardingList = new ArrayList<>();
1803
1804    for (int i = 0; i < varInfos.length; i++) {
1805      // debugGuarding.fine (varInfos[i]);
1806      guardingList.addAll(varInfos[i].getGuardingList());
1807      // debugGuarding.fine (guardingSet.toString());
1808    }
1809
1810    return CollectionsPlume.withoutDuplicates(guardingList);
1811  }
1812
1813  // This is called only from finally_print_the_invariants().
1814  // Nothing is ever done with the result except print it and discard it.
1815  /**
1816   * This procedure guards one invariant and returns the resulting guarded invariant (implication),
1817   * without placing it in any slice and without modifying the original invariant. Returns null if
1818   * the invariant does not need to be guarded.
1819   */
1820  public @Nullable @NonPrototype Invariant createGuardedInvariant(boolean install) {
1821    if (Daikon.dkconfig_guardNulls == "never") { // interned
1822      return null;
1823    }
1824
1825    if (debugGuarding.isLoggable(Level.FINE)) {
1826      debugGuarding.fine("  Trying to add guard for: " + this + "; repr = " + repr());
1827    }
1828    if (isGuardingPredicate) {
1829      debugGuarding.fine("  Do not guard: this is a guarding predicate");
1830      return null;
1831    }
1832    Invariant guardingPredicate = createGuardingPredicate(install);
1833    if (debugGuarding.isLoggable(Level.FINE)) {
1834      if (guardingPredicate != null) {
1835        debugGuarding.fine("  Predicate: " + guardingPredicate.format());
1836        debugGuarding.fine("  Consequent: " + format());
1837      } else {
1838        debugGuarding.fine("  No implication needed");
1839      }
1840    }
1841
1842    if (guardingPredicate == null) {
1843      return null;
1844    }
1845
1846    Implication guardingImplication =
1847        GuardingImplication.makeGuardingImplication(ppt.parent, guardingPredicate, this, false);
1848
1849    if (install) {
1850      if (!ppt.parent.joiner_view.hasImplication(guardingImplication)) {
1851        ppt.parent.joiner_view.addInvariant(guardingImplication);
1852      }
1853    }
1854    return guardingImplication;
1855  }
1856
1857  /**
1858   * Instantiates (creates) an invariant of the same class on the specified slice. Must be
1859   * overridden in each class. Must be used rather than {@link #clone} so that checks in {@link
1860   * #instantiate} for reasonable invariants are done.
1861   *
1862   * <p>The implementation of this method is almost always {@code return new
1863   * <em>InvName</em>(slice);}
1864   *
1865   * @return the new invariant
1866   */
1867  protected abstract @NonPrototype Invariant instantiate_dyn(
1868      @Prototype Invariant this, PptSlice slice);
1869
1870  /**
1871   * Returns whether or not this class of invariants is currently enabled.
1872   *
1873   * <p>Its implementation is almost always {@code return dkconfig_enabled;}.
1874   */
1875  public abstract boolean enabled(@Prototype Invariant this);
1876
1877  /**
1878   * Returns whether or not the invariant is valid over the basic types in vis. This only checks
1879   * basic types (scalar, string, array, etc) and should match the basic superclasses of invariant
1880   * (SingleFloat, SingleScalarSequence, ThreeScalar, etc). More complex checks that depend on
1881   * variable details can be implemented in instantiate_ok().
1882   *
1883   * @see #instantiate_ok(VarInfo[])
1884   */
1885  public abstract boolean valid_types(@Prototype Invariant this, VarInfo[] vis);
1886
1887  /**
1888   * Returns true if it makes sense to instantiate this invariant over the specified variables.
1889   * Checks details beyond what is provided by {@link #valid_types}. This should never be called
1890   * without calling valid_types() first (implementations should be able to presume that
1891   * valid_types() returns true).
1892   *
1893   * <p>This method does not have to be overridden; the default implementation in Invariant returns
1894   * true.
1895   *
1896   * @see #valid_types(VarInfo[])
1897   */
1898  public boolean instantiate_ok(@Prototype Invariant this, VarInfo[] vis) {
1899    return true;
1900  }
1901
1902  // Every Invariant is either a regular Invariant, or a "prototype"
1903  // Invariant.  A prototype invariant is really a factory.  The
1904  // "instantiate" method should only be called on a prototype invariant,
1905  // and many methods should only be called on non-prototype methods.
1906  // Another (arguably better, though less convenient in certain ways)
1907  // design would not represent the factory as an Invariant object.  An
1908  // object never transitions at run time between being a factory/prototype
1909  // and being a normal invariant.
1910  //
1911  // Could we just use the class, such as Positive.class, as (a proxy for)
1912  // the factory?
1913  //  * That would require use of reflection to call the constructor, which
1914  //    is ugly.
1915  //  * The factory needs at least some state is needed, for example to
1916  //    distinguish between creating a division operator "a/b" vs. "b/a".
1917  //
1918  // Could the factories be represented by a separate class, unrelated in
1919  // the type hierarchy to Invariant?
1920  //  * That would probably be a better design.
1921  //  * instantiate_dyn would have to have more than just the single line that
1922  //    it is right now; longer code is more error-prone.
1923  //  * Not all the code for an invariant would be in a single class any
1924  //    more; but it could still all be in the same file, for example.
1925  //  * There are probably other difficulties that escape me at the moment.
1926
1927  /**
1928   * Instantiates this invariant over the specified slice. The slice must not be null and its
1929   * variables must be valid for this type of invariant. Returns null if the invariant is not
1930   * enabled or if the invariant is not reasonable over the specified variables. Otherwise returns
1931   * the new invariant.
1932   */
1933  public @Nullable Invariant instantiate(@Prototype Invariant this, PptSlice slice) {
1934
1935    assert isPrototype(); // receiver should be a "prototype" invariant
1936    assert slice != null;
1937    if (!valid_types(slice.var_infos)) {
1938      System.out.printf("this.getClass(): %s%n", this.getClass());
1939      System.out.printf("slice: %s%n", slice);
1940      System.out.printf(
1941          "slice.var_infos (length %d): %s%n", slice.var_infos.length, (Object) slice.var_infos);
1942      for (VarInfo vi : slice.var_infos) {
1943        System.out.printf("  var_info: %s %s%n", vi, vi.type);
1944      }
1945    }
1946    assert valid_types(slice.var_infos)
1947        : String.format("valid_types(%s) = false for %s", Arrays.toString(slice.var_infos), this);
1948    if (!enabled() || !instantiate_ok(slice.var_infos)) {
1949      return null;
1950    }
1951    Invariant inv = instantiate_dyn(slice);
1952    assert inv != null;
1953    if (inv.ppt == null) {
1954      // Avoid creating the message if the check succeeds
1955      assert inv.ppt != null : "invariant class " + inv.getClass();
1956    }
1957    return inv;
1958  }
1959
1960  /**
1961   * Adds the specified sample to the invariant and returns the result.
1962   *
1963   * @param vt the sample to add to this invariant
1964   * @param count the number of occurrences of the sample to add to this invariant
1965   * @return the result of adding the samples to this invariant
1966   */
1967  public InvariantStatus add_sample(@NonPrototype Invariant this, ValueTuple vt, int count) {
1968
1969    if (ppt instanceof PptSlice1) {
1970
1971      VarInfo v = ppt.var_infos[0];
1972      UnaryInvariant unary_inv = (UnaryInvariant) this;
1973      return unary_inv.add(vt.getValue(v), vt.getModified(v), count);
1974
1975    } else if (ppt instanceof PptSlice2) {
1976
1977      VarInfo v1 = ppt.var_infos[0];
1978      VarInfo v2 = ppt.var_infos[1];
1979      BinaryInvariant bin_inv = (BinaryInvariant) this;
1980      return bin_inv.add_unordered(vt.getValue(v1), vt.getValue(v2), vt.getModified(v1), count);
1981
1982    } else /* must be ternary */ {
1983
1984      VarInfo v1 = ppt.var_infos[0];
1985      VarInfo v2 = ppt.var_infos[1];
1986      VarInfo v3 = ppt.var_infos[2];
1987      assert (this instanceof TernaryInvariant)
1988          : "invariant '" + format() + "' in slice " + ppt.name() + " is not ternary";
1989      TernaryInvariant ternary_inv = (TernaryInvariant) this;
1990      return ternary_inv.add(
1991          vt.getValue(v1), vt.getValue(v2), vt.getValue(v3), vt.getModified(v1), count);
1992    }
1993  }
1994
1995  /** Check the rep invariants of this. */
1996  public void repCheck(@Prototype Invariant this) {}
1997
1998  /**
1999   * Returns whether or not the invariant is currently active. This is used to identify those
2000   * invariants that require a certain number of points before they actually do computation (eg,
2001   * LinearBinary)
2002   *
2003   * <p>This is used during suppresion. Any invariant that is not active cannot suppress another
2004   * invariant.
2005   *
2006   * @return true if this invariant is currently active
2007   */
2008  @Pure
2009  public boolean isActive(@NonPrototype Invariant this) {
2010    return true;
2011  }
2012
2013  // TODO: The logDetail and (especially) logOn methods are misleading,
2014  // because they are static but are very often called with an instance as
2015  // the receiver, suggesting that they have something to do with the
2016  // receiver.  This should be corrected.  -MDE
2017
2018  /**
2019   * Returns true if detailed logging is on. Note that this check is not performed inside the
2020   * logging calls themselves, it must be performed by the caller.
2021   *
2022   * @return true if detailed logging is on
2023   * @see daikon.Debug#logDetail()
2024   * @see daikon.Debug#logOn()
2025   * @see daikon.Debug#log(Logger, Class, Ppt, String)
2026   */
2027  public static boolean logDetail() {
2028    return Debug.logDetail();
2029  }
2030
2031  /**
2032   * Returns whether or not logging is on.
2033   *
2034   * @see daikon.Debug#logOn()
2035   */
2036  public static boolean logOn() {
2037    return Debug.logOn();
2038  }
2039
2040  // Using `@link` leads to javadoc -Xdoclint:all crashing with:
2041  // "com.sun.tools.javac.code.Type$AnnotatedType cannot be cast to
2042  // com.sun.tools.javac.code.Type$ClassType"
2043  /**
2044   * Logs a description of the invariant and the specified msg via the logger as described in {@code
2045   * daikon.Debug#log(Logger, Class, Ppt, VarInfo[], String)}.
2046   *
2047   * @param log where to log the message
2048   * @param msg the message to log
2049   */
2050  // receiver needs to be initialized because subclass implementations will read their own fields
2051  public void log(@NonPrototype Invariant this, Logger log, String msg) {
2052
2053    if (Debug.logOn()) {
2054      Debug.log(log, getClass(), ppt, msg);
2055    }
2056  }
2057
2058  // Using `@link` leads to javadoc -Xdoclint:all crashing with:
2059  // "com.sun.tools.javac.code.Type$AnnotatedType cannot be cast to
2060  // com.sun.tools.javac.code.Type$ClassType"
2061  /**
2062   * Logs a description of the invariant and the specified msg via the logger as described in {@code
2063   * daikon.Debug#log(Logger, Class, Ppt, VarInfo[], String)}.
2064   *
2065   * @param format a format string
2066   * @param args the argumnts to the format string
2067   * @return whether or not it logged anything
2068   */
2069  @FormatMethod
2070  public boolean log(
2071      @UnknownInitialization(Invariant.class) @NonPrototype Invariant this,
2072      String format,
2073      @Nullable Object... args) {
2074    if (ppt != null) {
2075      String msg = format;
2076      if (args.length > 0) {
2077        msg = String.format(format, args);
2078      }
2079      return Debug.log(getClass(), ppt, msg);
2080    } else {
2081      return false;
2082    }
2083  }
2084
2085  // Receiver must be fully initialized
2086  @SideEffectFree
2087  @Override
2088  public String toString(@GuardSatisfied Invariant this) {
2089    return format();
2090  }
2091
2092  /**
2093   * Return a string representation of the given invariants.
2094   *
2095   * @param invs the invariants to get a string representation of
2096   * @return a string representation of the given invariants
2097   */
2098  public static String toString(@NonPrototype Invariant[] invs) {
2099
2100    ArrayList<String> strings = new ArrayList<>(invs.length);
2101    for (int i = 0; i < invs.length; i++) {
2102      if (invs[i] == null) {
2103        strings.add("null");
2104      } else {
2105        strings.add(invs[i].format());
2106      }
2107    }
2108    return String.join(", ", strings);
2109  }
2110
2111  /**
2112   * Used throughout Java family formatting of invariants.
2113   *
2114   * <p>Returns
2115   *
2116   * <p>"plume.FuzzyFloat.method(v1_name, v2_name)"
2117   *
2118   * <p>Where v1_name and v2_name are the properly formatted varinfos v1 and v2, under the given
2119   * format.
2120   */
2121  // [[ This method doesn't belong here. But where? ]]
2122  public static String formatFuzzy(String method, VarInfo v1, VarInfo v2, OutputFormat format) {
2123
2124    StringBuilder results = new StringBuilder();
2125    return results
2126        .append("daikon.Quant.fuzzy.")
2127        .append(method)
2128        .append("(")
2129        .append(v1.name_using(format))
2130        .append(", ")
2131        .append(v2.name_using(format))
2132        .append(")")
2133        .toString();
2134  }
2135
2136  @SuppressWarnings("unchecked") // casting method
2137  public static Class<? extends Invariant> asInvClass(Object x) {
2138    return (Class<? extends Invariant>) x;
2139  }
2140
2141  /**
2142   * Returns true if this is an equality comparison. That is, returns true if this Invariant
2143   * satisfies the following conditions:
2144   *
2145   * <ul>
2146   *   <li>the Invariant is an EqualityComparison (its relationship is =, not &lt;, &le;, &gt;, or
2147   *       &ge;).
2148   *   <li>the invariant is statistically satisfied (its confidence is above the limit)
2149   * </ul>
2150   *
2151   * This does not consider PairwiseIntComparison to be an equality invariant.
2152   */
2153  public boolean isEqualityComparison() {
2154    if (!(this instanceof EqualityComparison)) {
2155      return false;
2156    }
2157    double chance_conf = ((EqualityComparison) this).eq_confidence();
2158    return chance_conf > Invariant.dkconfig_confidence_limit;
2159  }
2160
2161  /**
2162   * Throws an exception if this object is invalid.
2163   *
2164   * @exception RuntimeException if representation invariant on this is broken
2165   */
2166  public void checkRep() {
2167    // very partial initial implementation
2168    for (VarInfo vi : ppt.var_infos) {
2169      vi.checkRep();
2170    }
2171  }
2172
2173  /** Classes for which {@link #checkMergeOverridden} has been called. */
2174  public static IdentityHashMap<Class<?>, Boolean> checkedMergeOverridden = new IdentityHashMap<>();
2175
2176  /**
2177   * Throws an exception if the class directly defines fields but does not override {@link #merge}.
2178   */
2179  private void checkMergeOverridden(
2180      @UnderInitialization(daikon.inv.Invariant.class) Invariant this) {
2181    Class<?> thisClass = getClass();
2182    if (!checkedMergeOverridden.containsKey(thisClass)) {
2183      checkedMergeOverridden.put(thisClass, true);
2184
2185      // TODO: Could look at all fields and compare them to the fields of Invariant.class.
2186      Field[] declaredFields = thisClass.getDeclaredFields();
2187      List<Field> statefulFields = new ArrayList<>(4);
2188      for (Field declaredField : declaredFields) {
2189        if (Modifier.isStatic(declaredField.getModifiers())) {
2190          continue;
2191        }
2192
2193        String fieldName = declaredField.getName();
2194        if (fieldName.equals("serialVersionUID")) {
2195          continue;
2196        }
2197        if (fieldName.startsWith("$")) {
2198          continue;
2199        }
2200        if (fieldName.startsWith("dkconfig_")) {
2201          continue;
2202        }
2203        if (fieldName.startsWith("debug")) {
2204          continue;
2205        }
2206        if (fieldName.endsWith("Cache")) {
2207          continue;
2208        }
2209
2210        statefulFields.add(declaredField);
2211      }
2212
2213      if (statefulFields.isEmpty()) {
2214        return;
2215      }
2216
2217      try {
2218        @SuppressWarnings(
2219            "UnusedVariable" // Method is called for side effect, ignore return value, but give the
2220        // unused variable a name for documentation purposes.
2221        )
2222        Method mergeMethod = thisClass.getDeclaredMethod("merge", List.class, PptSlice.class);
2223        // `mergeMethod` is non-null, or else `NoSuchMethodException` was thrown.
2224      } catch (NoSuchMethodException e) {
2225        StringJoiner fields = new StringJoiner(", ");
2226        for (Field f : statefulFields) {
2227          fields.add(f.getName());
2228        }
2229        throw new Error(
2230            thisClass.getSimpleName()
2231                + " does not override `merge(List, PptTopLevel)`,"
2232                + " but these fields might store state: "
2233                + fields);
2234      }
2235    }
2236  }
2237}