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 SeqIndexIntEqual extends SingleScalarSequence {
028  static final long serialVersionUID = 20040203L;
029
030  /** Debug tracer. */
031  public static final Logger debug =
032    Logger.getLogger("daikon.inv.unary.sequence.SeqIndexIntEqual");
033
034  // Variables starting with dkconfig_ should only be set via the
035  // daikon.config.Configuration interface.
036  /** Boolean. True iff SeqIndexIntEqual invariants should be considered. */
037  public static boolean dkconfig_enabled = false;
038
039  private @Prototype SeqIndexIntEqual() {
040    super();
041  }
042
043  protected SeqIndexIntEqual(PptSlice slice) {
044    super(slice);
045    assert slice != null;
046    assert var().rep_type == ProglangType.INT_ARRAY;
047  }
048
049  private static @Prototype SeqIndexIntEqual proto = new @Prototype SeqIndexIntEqual();
050
051  /** Returns the prototype invariant for SeqIndexIntEqual */
052  public static @Prototype SeqIndexIntEqual get_proto() {
053    return proto;
054  }
055
056  @Override
057  public boolean enabled() {
058    return dkconfig_enabled && !dkconfig_SeqIndexDisableAll;
059  }
060
061  @Override
062  public boolean instantiate_ok(VarInfo[] vis) {
063
064    if (!valid_types(vis)) {
065      return false;
066    }
067
068    // Don't compare indices to object addresses.
069    ProglangType elt_type = vis[0].file_rep_type.elementType();
070    if (!elt_type.baseIsIntegral()) {
071      return false;
072    }
073
074    // Make sure that the indices are comparable to the elements
075    VarInfo seqvar = vis[0];
076    assert seqvar.comparability != null;
077    VarComparability elt_compar = seqvar.comparability.elementType();
078    VarComparability index_compar = seqvar.comparability.indexType(0);
079    if (!VarComparability.comparable(elt_compar, index_compar)) {
080      return false;
081    }
082
083    return true;
084  }
085
086  @Override
087  public SeqIndexIntEqual instantiate_dyn(@Prototype SeqIndexIntEqual this, PptSlice slice) {
088    return new SeqIndexIntEqual(slice);
089  }
090
091  /** returns the ni-suppressions for SeqIndexIntEqual */
092  @Pure
093  @Override
094  public @Nullable NISuppressionSet get_ni_suppressions() {
095    return null;
096  }
097
098  protected Invariant resurrect_done_swapped() {
099
100      return this;
101  }
102
103  public String getComparator() {
104    return "==";
105  }
106
107  @SideEffectFree
108  @Override
109  public String format_using(@GuardSatisfied SeqIndexIntEqual this, OutputFormat format) {
110    if (format.isJavaFamily()) {
111      return format_java_family(format);
112    }
113
114    // TODO: Eliminate the unnecessary format_xxx() below if the
115    // format_java_family() can handle all the Java family output.
116
117    if (format == OutputFormat.DAIKON) {
118      return format_daikon();
119    }
120    if (format == OutputFormat.ESCJAVA) {
121      return format_esc();
122    }
123    if (format == OutputFormat.CSHARPCONTRACT) {
124      return format_csharp_contract();
125    }
126    if (format == OutputFormat.SIMPLIFY) {
127      return format_simplify();
128    }
129
130    return format_unimplemented(format);
131  }
132
133  public String format_daikon(@GuardSatisfied SeqIndexIntEqual this) {
134
135    // If this is an array/container and not a subsequence
136    if (var().isDerivedSubSequenceOf() == null) {
137      return var().apply_subscript("i") + " == i";
138    } else {
139      return var().name() + " == (index)";
140    }
141  }
142
143  // Bad code here: if the first index is changed from i this breaks
144  public String format_esc(@GuardSatisfied SeqIndexIntEqual this) {
145    String[] form = VarInfo.esc_quantify(var());
146    return form[0] + "(" + form[1] + " == i)" + form[2];
147  }
148
149  public String format_csharp_contract(@GuardSatisfied SeqIndexIntEqual this) {
150    String[] split = var().csharp_array_split();
151    return "Contract.ForAll(0, " + split[0] + ".Count(), i => " + split[0] + "[i]" + split[1] + " == i)";
152  }
153
154  public String format_java_family(@GuardSatisfied SeqIndexIntEqual this, OutputFormat format) {
155    return "daikon.Quant.eltsEqualIndex("
156      + var().name_using(format) + ")";
157  }
158
159  public String format_simplify(@GuardSatisfied SeqIndexIntEqual this) {
160    String[] form = VarInfo.simplify_quantify(QuantFlags.include_index(),
161                                               var());
162    return form[0] + "(EQ " + form[1] + " " + form[2] + ")"
163      + form[3];
164  }
165
166  @Override
167  public InvariantStatus check_modified(long @Interned [] a, int count) {
168    for (int i = 0; i < a.length; i++) {
169      if (!(a[i] == i)) {
170        return InvariantStatus.FALSIFIED;
171      }
172    }
173    return InvariantStatus.NO_CHANGE;
174  }
175
176  @Override
177  public InvariantStatus add_modified(long @Interned [] a, int count) {
178
179    if (logDetail()) {
180      log("Entered add_modified: ppt.num_values()==%s, sample==%s",
181           ppt.num_values(), Arrays.toString(a));
182    }
183    InvariantStatus stat = check_modified(a, count);
184    if (logDetail()) {
185      log("Exiting add_modified status = %s", stat);
186    }
187
188    return stat;
189  }
190
191  @Override
192  @SuppressWarnings("UnnecessaryParentheses")  // generated code, parentheses are sometimes needed
193  protected double computeConfidence() {
194
195    // Make sure there have been some elements in the sequence
196    ValueSet.ValueSetScalarArray vs = (ValueSet.ValueSetScalarArray) ppt.var_infos[0].get_value_set();
197    if (vs.elem_cnt() == 0) {
198      return Invariant.CONFIDENCE_UNJUSTIFIED;
199    }
200
201    int num_values = ppt.num_values();
202    if (num_values == 0) {
203      return Invariant.CONFIDENCE_UNJUSTIFIED;
204    }
205
206      return Invariant.CONFIDENCE_JUSTIFIED;
207
208  }
209
210  @Pure
211  @Override
212  public boolean isSameFormula(Invariant other) {
213    return true;
214  }
215
216  @Pure
217  @Override
218  public boolean isExclusiveFormula(Invariant other) {
219    return false;
220  }
221
222  // Look up a previously instantiated invariant.
223  public static @Nullable SeqIndexIntEqual find(PptSlice ppt) {
224    assert ppt.arity() == 1;
225    for (Invariant inv : ppt.invs) {
226      if (inv instanceof SeqIndexIntEqual) {
227        return (SeqIndexIntEqual) inv;
228      }
229    }
230    return null;
231  }
232
233  /**
234   * Checks to see if this is obvious over the specified variables Implements the following checks:
235   *
236   * <pre>
237   *    (A[] subsequence B[]) ^ (B[i] op i) &rArr; A[i] op i
238   * </pre>
239   *
240   * JHP: Its not obvious (to me) that this is true except when the subsequence starts at index
241   * 0. If B[] = {0, 1, 2, 3, 4} and A[] = {2, 3, 4}, A[] is a subsequence of B[] and B[i] == i, but
242   * A[i] = i is not true.
243   */
244  @Pure
245  @Override
246  public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) {
247
248    DiscardInfo super_result = super.isObviousDynamically(vis);
249    if (super_result != null) {
250      return super_result;
251    }
252
253    VarInfo seqvar = vis[0];
254
255    // For each other sequence variable, if it is a supersequence of this
256    // one and it has the same invariant, then this one is obvious.
257    // We have to check for the same equality set here, because
258    // isObviousDynamically is called for each member of the equality set.
259    // We don't want other members of our own equality set to make this obvious
260    PptTopLevel pptt = ppt.parent;
261    for (int i = 0; i < pptt.var_infos.length; i++) {
262      VarInfo vi = pptt.var_infos[i];
263      if (vi.equalitySet == seqvar.equalitySet) {
264        continue;
265      }
266      if (SubSequence.isObviousSubSequenceDynamically(this, seqvar, vi)) {
267        PptSlice1 other_slice = pptt.findSlice(vi);
268        if (other_slice != null) {
269          SeqIndexIntEqual other_sine = SeqIndexIntEqual.find(other_slice);
270          if ((other_sine != null) && other_sine.enoughSamples()) {
271            return new DiscardInfo(this, DiscardCode.obvious,
272                        "The invariant " + format() + " over var "
273                       + seqvar.name() + " also holds over "
274                       +" the supersequence " + vi.name());
275          }
276        }
277      }
278    }
279
280    return null;
281  }
282}