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