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