001// ***** This file is automatically generated from IntComparisons.java.jpp
002
003package daikon.inv.binary.twoScalar;
004
005import daikon.*;
006import daikon.derive.binary.*;
007import daikon.derive.unary.*;
008import daikon.inv.*;
009import daikon.inv.binary.twoScalar.*;
010import daikon.inv.binary.twoSequence.*;
011import daikon.inv.unary.scalar.*;
012import daikon.inv.unary.sequence.*;
013import daikon.inv.unary.string.*;
014import daikon.suppress.*;
015import java.util.*;
016import java.util.logging.Level;
017import java.util.logging.Logger;
018import org.checkerframework.checker.interning.qual.Interned;
019import org.checkerframework.checker.lock.qual.GuardSatisfied;
020import org.checkerframework.checker.nullness.qual.NonNull;
021import org.checkerframework.checker.nullness.qual.Nullable;
022import org.checkerframework.dataflow.qual.Pure;
023import org.checkerframework.dataflow.qual.SideEffectFree;
024import org.plumelib.util.Intern;
025import typequals.prototype.qual.NonPrototype;
026import typequals.prototype.qual.Prototype;
027
028/**
029 * Represents an invariant of &le; between two long scalars. Prints as {@code x <= y}.
030 */
031public final class IntLessEqual extends TwoScalar {
032
033  // We are Serializable, so we specify a version to allow changes to
034  // method signatures without breaking serialization.  If you add or
035  // remove fields, you should change this number to the current date.
036  static final long serialVersionUID = 20030822L;
037
038  // Variables starting with dkconfig_ should only be set via the
039  // daikon.config.Configuration interface.
040  /** Boolean. True iff IntLessEqual invariants should be considered. */
041  public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault;
042
043  public static final Logger debug = Logger.getLogger("daikon.inv.binary.twoScalar.IntLessEqual");
044
045  IntLessEqual(PptSlice ppt) {
046    super(ppt);
047  }
048
049  @Prototype IntLessEqual() {
050    super();
051  }
052
053  private static @Prototype IntLessEqual proto = new @Prototype IntLessEqual();
054
055  /** Returns the prototype invariant for IntLessEqual */
056  public static @Prototype IntLessEqual get_proto() {
057    return proto;
058  }
059
060  /** Returns whether or not this invariant is enabled. */
061  @Override
062  public boolean enabled() {
063    return dkconfig_enabled;
064  }
065
066  /** Returns whether or not the specified var types are valid for IntLessEqual */
067  @Override
068  public boolean instantiate_ok(VarInfo[] vis) {
069
070    if (!valid_types(vis)) {
071      return false;
072    }
073
074        return (vis[0].file_rep_type.isIntegral()
075                && vis[1].file_rep_type.isIntegral());
076
077  }
078
079  /** Instantiate an invariant on the specified slice. */
080  @Override
081  protected IntLessEqual instantiate_dyn(@Prototype IntLessEqual this, PptSlice slice) {
082
083    return new IntLessEqual(slice);
084  }
085
086  @Override
087  protected Invariant resurrect_done_swapped() {
088
089      // we have no non-static member data, so we only need care about our type
090      // As of now, the constructor chain is side-effect free;
091      // let's hope it stays that way.
092      IntGreaterEqual result = new IntGreaterEqual(ppt);
093      return result;
094  }
095
096  /** Returns the class that corresponds to this class with its variable order swapped. */
097  public static Class<? extends Invariant> swap_class() {
098    return IntGreaterEqual.class;
099  }
100
101  // JHP: this should be removed in favor of checks in PptTopLevel
102  // such as is_equal, is_lessequal, etc.
103  // Look up a previously instantiated IntLessEqual relationship.
104  // Should this implementation be made more efficient?
105  public static @Nullable IntLessEqual find(PptSlice ppt) {
106    assert ppt.arity() == 2;
107    for (Invariant inv : ppt.invs) {
108      if (inv instanceof IntLessEqual) {
109        return (IntLessEqual) inv;
110      }
111    }
112
113    // If the invariant is suppressed, create it
114    if ((suppressions != null) && suppressions.suppressed(ppt)) {
115      IntLessEqual inv = proto.instantiate_dyn(ppt);
116      // System.out.printf("%s is suppressed in ppt %s%n", inv.format(), ppt.name());
117      return inv;
118    }
119
120    return null;
121  }
122
123  @Override
124  public String repr(@GuardSatisfied IntLessEqual this) {
125    return "IntLessEqual" + varNames();
126  }
127
128  @SideEffectFree
129  @Override
130  public String format_using(@GuardSatisfied IntLessEqual this, OutputFormat format) {
131
132    String var1name = var1().name_using(format);
133    String var2name = var2().name_using(format);
134
135    if ((format == OutputFormat.DAIKON) || (format == OutputFormat.ESCJAVA)) {
136      String comparator = "<=";
137      return var1name + " " + comparator + " " + var2name;
138    }
139
140    if (format == OutputFormat.CSHARPCONTRACT) {
141
142        String comparator = "<=";
143        return var1name + " " + comparator + " " + var2name;
144    }
145
146    if (format.isJavaFamily()) {
147
148        if ((var1name.indexOf("daikon.Quant.collectObject") != -1)
149
150            || (var2name.indexOf("daikon.Quant.collectObject") != -1)) {
151          return "(warning: it is meaningless to compare hashcodes for values obtained through daikon.Quant.collect... methods:"
152            + var1name + " <= " + var2name + ")";
153        }
154        return var1name + " <= " + var2name;
155    }
156
157    if (format == OutputFormat.SIMPLIFY) {
158
159        String comparator = "<=";
160
161      return "("
162          + comparator
163          + " "
164          + var1().simplifyFixup(var1name)
165          + " "
166          + var2().simplifyFixup(var2name)
167          + ")";
168    }
169
170    return format_unimplemented(format);
171  }
172
173  @Override
174  public InvariantStatus check_modified(long v1, long v2, int count) {
175    if (!(v1 <= v2)) {
176      return InvariantStatus.FALSIFIED;
177    }
178    return InvariantStatus.NO_CHANGE;
179  }
180
181  @Override
182  public InvariantStatus add_modified(long v1, long v2, int count) {
183    if (logDetail() || debug.isLoggable(Level.FINE)) {
184      log(
185          debug,
186          "add_modified (" + v1 + ", " + v2 + ",  ppt.num_values = " + ppt.num_values() + ")");
187    }
188    if ((logOn() || debug.isLoggable(Level.FINE))
189        && check_modified(v1, v2, count) == InvariantStatus.FALSIFIED)
190      log(debug, "destroy in add_modified (" + v1 + ", " + v2 + ",  " + count + ")");
191
192    return check_modified(v1, v2, count);
193  }
194
195  // This is very tricky, because whether two variables are equal should
196  // presumably be transitive, but it's not guaranteed to be so when using
197  // this method and not dropping out all variables whose values are ever
198  // missing.
199  @Override
200  protected double computeConfidence() {
201    // Should perhaps check number of samples and be unjustified if too few
202    // samples.
203
204      // // The reason for this multiplication is that there might be only a
205      // // very few possible values.  Example:  towers of hanoi has only 6
206      // // possible (pegA, pegB) pairs.
207      // return 1 - (Math.pow(.5, ppt.num_values())
208      //             * Math.pow(.99, ppt.num_mod_samples()));
209      return 1 - Math.pow(.5, ppt.num_samples());
210  }
211
212  @Pure
213  @Override
214  public boolean isExact() {
215
216      return false;
217  }
218
219  // // Temporary, for debugging
220  // public void destroy() {
221  //   if (debug.isLoggable(Level.FINE)) {
222  //     System.out.println("IntLessEqual.destroy(" + ppt.name() + ")");
223  //     System.out.println(repr());
224  //     (new Error()).printStackTrace();
225  //   }
226  //   super.destroy();
227  // }
228
229  @Override
230  public InvariantStatus add(
231      @Interned Object v1, @Interned Object v2, int mod_index, int count) {
232    if (debug.isLoggable(Level.FINE)) {
233      debug.fine(
234          "IntLessEqual"
235          + ppt.varNames()
236          + ".add("
237          + v1
238          + ","
239          + v2
240          + ", mod_index="
241          + mod_index
242          + "), count="
243          + count
244          + ")");
245    }
246    return super.add(v1, v2, mod_index, count);
247  }
248
249  @Pure
250  @Override
251  public boolean isSameFormula(Invariant other) {
252    return true;
253  }
254
255  @Pure
256  @Override
257  public boolean isExclusiveFormula(Invariant other) {
258
259    // Also ought to check against LinearBinary, etc.
260
261      if (other instanceof IntGreaterThan) {
262        return true;
263      }
264
265    return false;
266  }
267
268  @Override
269  public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) {
270    final VarInfo var1 = vis[0];
271    final VarInfo var2 = vis[1];
272
273    if (var1.aux.hasValue(VarInfoAux.MAXIMUM_VALUE)
274        && var2.aux.hasValue(VarInfoAux.MINIMUM_VALUE)) {
275      int maxA = var1.aux.getInt(VarInfoAux.MAXIMUM_VALUE),
276          minB = var2.aux.getInt(VarInfoAux.MINIMUM_VALUE);
277
278      if (maxA <= minB) {
279        return new DiscardInfo(
280            this,
281            DiscardCode.obvious,
282            var1.name() + " DISCARD_OP " + var2.name() + " is already known");
283      }
284    }
285
286    return super.isObviousStatically(vis);
287  }
288
289  @Pure
290  @Override
291  public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) {
292
293    // JHP: We might consider adding a check over bounds.   If
294    // x < c and y > c then we know that x < y.  Similarly for
295    // x > c and y < c.  We could also substitute oneof for
296    // one or both of the bound checks.
297
298    DiscardInfo super_result = super.isObviousDynamically(vis);
299    if (super_result != null) {
300      return super_result;
301    }
302
303    VarInfo var1 = vis[0];
304    VarInfo var2 = vis[1];
305
306    @SuppressWarnings("UnusedVariable") // generated code, variable is sometimes used
307    DiscardInfo di;
308
309      // Check for the same invariant over enclosing arrays
310      di = pairwise_implies(vis);
311      if (di != null) {
312        return di;
313      }
314
315    { // Sequence length tests
316      SequenceLength sl1 = null;
317      if (var1.isDerived() && (var1.derived instanceof SequenceLength)) {
318        sl1 = (SequenceLength) var1.derived;
319      }
320      SequenceLength sl2 = null;
321      if (var2.isDerived() && (var2.derived instanceof SequenceLength)) {
322        sl2 = (SequenceLength) var2.derived;
323      }
324
325      // "size(a)-1 cmp size(b)-1" is never even instantiated;
326      // use "size(a) cmp size(b)" instead.
327
328      // This might never get invoked, as equality is printed out specially.
329      VarInfo s1 = (sl1 == null) ? null : sl1.base;
330      VarInfo s2 = (sl2 == null) ? null : sl2.base;
331      if ((s1 != null) && (s2 != null) && (s1.equalitySet == s2.equalitySet)) {
332        // lengths of equal arrays being compared
333        String n1 = var1.name();
334        String n2 = var2.name();
335        return new DiscardInfo(
336            this,
337            DiscardCode.obvious,
338            n1 + " and " + n2 + " are equal arrays, so equal size is implied");
339      }
340
341    }
342
343    return null;
344  } // isObviousDynamically
345
346  /**
347   * If both variables are subscripts and the underlying arrays have the same invariant, then this
348   * invariant is implied:
349   *
350   * <pre>(x[] op y[]) ^ (i == j) &rArr; (x[i] op y[j])</pre>
351   */
352  private @Nullable DiscardInfo pairwise_implies(VarInfo[] vis) {
353
354    VarInfo v1 = vis[0];
355    VarInfo v2 = vis[1];
356
357    // Make sure v1 and v2 are SequenceScalarSubscript with the same shift
358    if (!v1.isDerived() || !(v1.derived instanceof SequenceScalarSubscript)) {
359      return null;
360    }
361    if (!v2.isDerived() || !(v2.derived instanceof SequenceScalarSubscript)) {
362      return null;
363    }
364    @NonNull SequenceScalarSubscript der1 = (SequenceScalarSubscript) v1.derived;
365    @NonNull SequenceScalarSubscript der2 = (SequenceScalarSubscript) v2.derived;
366    if (der1.index_shift != der2.index_shift) {
367      return null;
368    }
369
370    // Make sure that the indices are equal
371    if (!ppt.parent.is_equal(der1.sclvar().canonicalRep(), der2.sclvar().canonicalRep())) {
372      return null;
373    }
374
375    // See if the same relationship holds over the arrays
376    Invariant proto = PairwiseIntLessEqual.get_proto();
377    DiscardInfo di = ppt.parent.check_implied_canonical(this, der1.seqvar(), der2.seqvar(), proto);
378    return di;
379  }
380
381  /** NI suppressions, initialized in get_ni_suppressions() */
382  private static @Nullable NISuppressionSet suppressions = null;
383
384  /** Returns the non-instantiating suppressions for this invariant. */
385  @Pure
386  @Override
387  public NISuppressionSet get_ni_suppressions() {
388    if (suppressions == null) {
389
390        NISuppressee suppressee = new NISuppressee(IntLessEqual.class, 2);
391
392      // suppressor definitions (used in suppressions below)
393
394      NISuppressor v1_eq_v2 = new NISuppressor(0, 1, IntEqual.class);
395
396      NISuppressor v1_lt_v2 = new NISuppressor(0, 1, IntLessThan.class);
397
398      suppressions =
399          new NISuppressionSet(
400              new NISuppression[] {
401
402                  // v1 == v2 => v1 <= v2
403                  new NISuppression(v1_eq_v2, suppressee),
404                  // v1 < v2 => v1 <= v2
405                  new NISuppression(v1_lt_v2, suppressee),
406
407              });
408    }
409    return suppressions;
410  }
411
412}