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