001// ***** This file is automatically generated from Numeric.java.jpp
002
003package daikon.inv.binary.twoScalar;
004
005import org.checkerframework.checker.lock.qual.GuardSatisfied;
006import org.checkerframework.checker.nullness.qual.NonNull;
007import org.checkerframework.checker.nullness.qual.Nullable;
008import org.checkerframework.checker.signature.qual.ClassGetName;
009import org.checkerframework.dataflow.qual.Pure;
010import org.checkerframework.dataflow.qual.SideEffectFree;
011import static daikon.inv.Invariant.asInvClass;
012
013import daikon.*;
014import daikon.Quantify.QuantFlags;
015import daikon.derive.binary.*;
016import daikon.inv.*;
017import daikon.inv.binary.twoScalar.*;
018import daikon.inv.binary.twoString.*;
019import daikon.inv.unary.scalar.*;
020import daikon.inv.unary.sequence.*;
021import daikon.suppress.*;
022import java.util.*;
023import org.plumelib.util.UtilPlume;
024import typequals.prototype.qual.NonPrototype;
025import typequals.prototype.qual.Prototype;
026
027/**
028 * Baseclass for binary numeric invariants.
029 *
030 * Each specific invariant is implemented in a subclass (typically, in this file). The subclass must
031 * provide the methods instantiate(), check(), and format(). Symmetric functions should define
032 * is_symmetric() to return true.
033 */
034public abstract class NumericFloat extends TwoFloat {
035
036  static final long serialVersionUID = 20060609L;
037
038  protected NumericFloat(PptSlice ppt, boolean swap) {
039    super(ppt);
040    this.swap = swap;
041  }
042
043  protected NumericFloat(boolean swap) {
044    super();
045    this.swap = swap;
046  }
047
048  @Override
049  public boolean instantiate_ok(VarInfo[] vis) {
050
051    ProglangType type1 = vis[0].file_rep_type;
052    ProglangType type2 = vis[1].file_rep_type;
053    if (!type1.isFloat() || !type2.isFloat()) {
054      return false;
055    }
056
057    return true;
058  }
059
060  @Pure
061  @Override
062  public boolean isExact() {
063    return true;
064  }
065
066  @Override
067  public String repr(@GuardSatisfied NumericFloat this) {
068    return getClass().getSimpleName() + ": " + format()
069      + (swap ? " [swapped]" : " [unswapped]");
070  }
071
072  /**
073   * Returns a string in the specified format that describes the invariant.
074   *
075   * The generic format string is obtained from the subclass specific get_format_str(). Instances of
076   * %varN% are replaced by the variable name in the specified format.
077   */
078  @SideEffectFree
079  @Override
080  public String format_using(@GuardSatisfied NumericFloat this, OutputFormat format) {
081
082    if (ppt == null) {
083      return String.format("proto ppt [class %s] format %s", getClass(),
084                           get_format_str(format));
085    }
086    String fmt_str = get_format_str(format);
087
088    String v1 = var1().name_using(format);
089    String v2 = var2().name_using(format);
090
091    // Note that we do not use String.replaceAll here, because that's
092    // inseparable from the regex library, and we don't want to have to
093    // escape v1 with something like
094    // v1.replaceAll("([\\$\\\\])", "\\\\$1")
095    fmt_str = fmt_str.replace("%var1%", v1);
096    fmt_str = fmt_str.replace("%var2%", v2);
097
098    // if (false && (format == OutputFormat.DAIKON)) {
099    //   fmt_str = "[" + getClass() + "]" + fmt_str + " ("
100    //          + var1().get_value_info() + ", " + var2().get_value_info() +  ")";
101    // }
102    return fmt_str;
103  }
104
105  /** Calls the function specific equal check and returns the correct status. */
106
107  @Override
108  public InvariantStatus check_modified(double x, double y, int count) {
109
110    try {
111      if (eq_check(x, y)) {
112        return InvariantStatus.NO_CHANGE;
113      } else {
114        return InvariantStatus.FALSIFIED;
115      }
116    } catch (Exception e) {
117      return InvariantStatus.FALSIFIED;
118    }
119  }
120
121  /**
122   * Checks to see if 'x[a] op y[b]' where 'x[] op y[]' and 'a == b'. Doesn't catch the case where
123   * a = b+1.
124   */
125  public @Nullable DiscardInfo is_subscript(VarInfo[] vis) {
126
127    VarInfo v1 = var1(vis);
128    VarInfo v2 = var2(vis);
129
130    // Make sure each var is a sequence subscript
131    if (!v1.isDerived() || !(v1.derived instanceof SequenceFloatSubscript)) {
132      return null;
133    }
134    if (!v2.isDerived() || !(v2.derived instanceof SequenceFloatSubscript)) {
135      return null;
136    }
137
138    @NonNull SequenceFloatSubscript der1 = (SequenceFloatSubscript) v1.derived;
139    @NonNull SequenceFloatSubscript der2 = (SequenceFloatSubscript) v2.derived;
140
141    // Make sure the shifts match
142    if (der1.index_shift != der2.index_shift) {
143      return null;
144    }
145
146    // Look for this invariant over a sequence
147    String cstr = getClass().getName();
148    cstr = cstr.replaceFirst("Numeric", "PairwiseNumeric");
149    cstr = cstr.replaceFirst("twoScalar", "twoSequence");
150    cstr = cstr.replaceFirst("twoFloat", "twoSequence");
151    Class<? extends Invariant> pairwise_class;
152    try {
153      @SuppressWarnings("signature") // string manipulation; application invariants
154      @ClassGetName String cstr_cgn = cstr;
155      pairwise_class = asInvClass(Class.forName(cstr_cgn));
156    } catch (Exception e) {
157      throw new Error("can't create class for " + cstr, e);
158    }
159    Invariant inv = find(pairwise_class, der1.seqvar(), der2.seqvar());
160    if (inv == null) {
161      return null;
162    }
163
164    // Look to see if the subscripts are equal
165    Invariant subinv = find(FloatEqual.class, der1.sclvar(), der2.sclvar());
166    if (subinv == null) {
167      return null;
168    }
169
170    return new DiscardInfo(this, DiscardCode.obvious, "Implied by "
171                           + inv.format() + " and " + subinv.format());
172  }
173
174  @Pure
175  @Override
176  public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) {
177
178    DiscardInfo super_result = super.isObviousDynamically(vis);
179    if (super_result != null) {
180      return super_result;
181    }
182
183      // any relation across subscripts is made obvious by the same
184      // relation across the original sequence if the subscripts are equal
185      DiscardInfo result = is_subscript(vis);
186      if (result != null) {
187        return result;
188      }
189
190    // Check for invariant specific obvious checks.  The obvious_checks
191    // method returns an array of arrays of antecedents.  If all of the
192    // antecedents in an array are true, then the invariant is obvoius.
193    InvDef[][] obvious_arr = obvious_checks(vis);
194    obvious_loop:
195    for (int i = 0; i < obvious_arr.length; i++) {
196      InvDef[] antecedents = obvious_arr[i];
197      StringBuilder why = null;
198      for (int j = 0; j < antecedents.length; j++) {
199        Invariant inv = antecedents[j].find();
200        if (inv == null) {
201          continue obvious_loop;
202        }
203        if (why == null) {
204          why = new StringBuilder(inv.format());
205        } else {
206          why.append(" and ");
207          why.append(inv.format());
208        }
209      }
210      return new DiscardInfo(this, DiscardCode.obvious, "Implied by " + why);
211    }
212
213    return null;
214  }
215
216  /**
217   * Return a format string for the specified output format. Each instance of %varN% will be
218   * replaced by the correct name for varN.
219   */
220  public abstract String get_format_str(@GuardSatisfied NumericFloat this, OutputFormat format);
221
222  /** Returns true if x and y don't invalidate the invariant. */
223  public abstract boolean eq_check(double x, double y);
224
225  /**
226   * Returns an array of arrays of antecedents. If all of the antecedents in any array are true,
227   * then the invariant is obvious.
228   */
229  public InvDef[][] obvious_checks(VarInfo[] vis) {
230    return new InvDef[][] {};
231  }
232
233  public static List<@Prototype Invariant> get_proto_all() {
234
235    List<@Prototype Invariant> result = new ArrayList<>();
236
237      result.add(Divides.get_proto(false));
238      result.add(Divides.get_proto(true));
239      result.add(Square.get_proto(false));
240      result.add(Square.get_proto(true));
241
242      result.add(ZeroTrack.get_proto(false));
243      result.add(ZeroTrack.get_proto(true));
244
245    // System.out.printf("%s get proto: %s%n", NumericFloat.class, result);
246    return result;
247  }
248
249  // suppressor definitions, used by many of the classes below
250  protected static NISuppressor
251
252      var1_eq_0       = new NISuppressor(0, RangeFloat.EqualZero.class),
253      var2_eq_0       = new NISuppressor(1, RangeFloat.EqualZero.class),
254      var1_ge_0       = new NISuppressor(0, RangeFloat.GreaterEqualZero.class),
255      var2_ge_0       = new NISuppressor(1, RangeFloat.GreaterEqualZero.class),
256      var1_eq_1       = new NISuppressor(0, RangeFloat.EqualOne.class),
257      var2_eq_1       = new NISuppressor(1, RangeFloat.EqualOne.class),
258      var1_eq_minus_1 = new NISuppressor(0, RangeFloat.EqualMinusOne.class),
259      var2_eq_minus_1 = new NISuppressor(1, RangeFloat.EqualMinusOne.class),
260      var1_ne_0       = new NISuppressor(0, NonZeroFloat.class),
261      var2_ne_0       = new NISuppressor(1, NonZeroFloat.class),
262      var1_le_var2    = new NISuppressor(0, 1, FloatLessEqual.class),
263
264    var1_eq_var2    = new NISuppressor(0, 1, FloatEqual.class),
265    var2_eq_var1    = new NISuppressor(0, 1, FloatEqual.class);
266
267  //
268  // Int and Float Numeric Invariants
269  //
270
271  /**
272   * Represents the divides without remainder invariant between two double scalars.
273   * Prints as {@code x % y == 0}.
274   */
275  public static class Divides extends NumericFloat {
276    // We are Serializable, so we specify a version to allow changes to
277    // method signatures without breaking serialization.  If you add or
278    // remove fields, you should change this number to the current date.
279    static final long serialVersionUID = 20040113L;
280
281    protected Divides(PptSlice ppt, boolean swap) {
282      super(ppt, swap);
283    }
284
285    protected Divides(boolean swap) {
286      super(swap);
287    }
288
289    private static @Prototype Divides proto = new @Prototype Divides(false);
290    private static @Prototype Divides proto_swap = new @Prototype Divides(true);
291
292    /** Returns the prototype invariant. */
293    public static @Prototype NumericFloat get_proto(boolean swap) {
294      if (swap) {
295        return proto_swap;
296      } else {
297        return proto;
298      }
299    }
300
301    // Variables starting with dkconfig_ should only be set via the
302    // daikon.config.Configuration interface.
303    /** Boolean. True iff divides invariants should be considered. */
304    public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault;
305
306    @Override
307    public boolean enabled() {
308      return dkconfig_enabled;
309    }
310
311    @Override
312    protected Divides instantiate_dyn(@Prototype Divides this, PptSlice slice) {
313      return new Divides(slice, swap);
314    }
315
316    @Override
317    public String get_format_str(@GuardSatisfied Divides this, OutputFormat format) {
318      if (format == OutputFormat.SIMPLIFY) {
319        return "(EQ 0 (MOD %var1% %var2%))";
320      } else if (format == OutputFormat.CSHARPCONTRACT) {
321        return "%var1% % %var2% == 0";
322      } else if (format.isJavaFamily()) {
323        return "daikon.Quant.fuzzy.eq(%var1% % %var2%, 0)";
324      } else {
325        return "%var1% % %var2% == 0";
326      }
327    }
328
329    @Override
330    public boolean eq_check(double x, double y) {
331      return Global.fuzzy.eq(0, (x % y));
332    }
333
334    /** Returns a list of non-instantiating suppressions for this invariant. */
335    @Pure
336    @Override
337    public NISuppressionSet get_ni_suppressions() {
338      if (swap) {
339        return suppressions_swap;
340      } else {
341        return suppressions;
342      }
343    }
344
345    /** definition of this invariant (the suppressee) (unswapped) */
346    private static NISuppressee suppressee = new NISuppressee(Divides.class, false);
347
348    private static NISuppressionSet suppressions =
349      new NISuppressionSet(
350          new NISuppression[] {
351
352            // These suppressions are only valid on scalars because the length
353            // of var1 and var2 must also be the same and there is no suppressor
354            // for that.
355
356            // var2 == 1 ==> var1 % var2 == 0
357            new NISuppression(var2_eq_1, suppressee),
358
359            // var2 == -1 ==> var1 % var2 == 0
360            new NISuppression(var2_eq_minus_1, suppressee),
361
362            // (var1 == 0) ^ (var2 != 0) ==> var1 % var2 == 0
363            new NISuppression(var1_eq_0, var2_ne_0, suppressee),
364
365            // (var1 == var2) ^ (var2 != 0) ==> var1 % var2 == 0
366            new NISuppression(var1_eq_var2, var2_ne_0, suppressee),
367
368            // (var2 == var1) ^ (var1 != 0) ==> var2 % var1 == 0
369            new NISuppression(var2_eq_var1, var1_ne_0, suppressee),
370
371          });
372    private static NISuppressionSet suppressions_swap = suppressions.swap();
373
374    /**
375     * Returns non-null if this invariant is obvious from an existing, non-falsified linear binary
376     * invariant in the same slice as this invariant. This invariant of the form "x % y == 0" is
377     * falsified if a linear binary invariant is found of the form "a*y - 1*x + 0 == 0"
378     *
379     * @return non-null value iff this invariant is obvious from other invariants in the same slice
380     */
381    @Pure
382    @Override
383    public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) {
384      // First call super type's method, and if it returns non-null, then
385      // this invariant is already known to be obvious, so just return
386      // whatever reason the super type returned.
387      DiscardInfo di = super.isObviousDynamically(vis);
388      if (di != null) {
389        return di;
390      }
391
392      VarInfo var1 = vis[0];
393      VarInfo var2 = vis[1];
394
395      // ensure that var1.varinfo_index <= var2.varinfo_index
396      if (var1.varinfo_index > var2.varinfo_index) {
397        var1 = vis[1];
398        var2 = vis[0];
399      }
400
401      // Find slice corresponding to these two variables.
402      // Ideally, this should always just be ppt if all
403      // falsified invariants have been removed.
404      PptSlice2 ppt2 = ppt.parent.findSlice(var1,var2);
405
406      // If no slice is found , no invariants exist to make this one obvious.
407      if (ppt2 == null) {
408        return null;
409      }
410
411      // For each invariant, check to see if it's a linear binary
412      // invariant of the form "a*y - 1*x + 0 == 0" and if so,
413      // you know this invariant of the form "x % y == 0" is obvious.
414      for(Invariant inv : ppt2.invs) {
415
416        if (inv instanceof LinearBinaryFloat) {
417          LinearBinaryFloat linv = (LinearBinaryFloat) inv;
418
419          // General form for linear binary: a*x + b*y + c == 0,
420          // but a and b can be switched with respect to vis, and either
421          // one may be negative, so instead check:
422          //  - c == 0
423          //  - a*b < 0   (a and b have different signs)
424          //  - |a| == 1 or |b| == 1, so one will divide the other
425          //     While this means that both x % y == 0 and y % x == 0,
426          //     only one of these invariants will still be true at this
427          //     time, and only that one will be falsified by this test.
428          if (!linv.is_false()
429              && Global.fuzzy.eq(linv.core.c, 0)
430              && linv.core.b * linv.core.a < 0
431              && (Global.fuzzy.eq(linv.core.a * linv.core.a, 1)
432                  || Global.fuzzy.eq(linv.core.b * linv.core.b, 1))) {
433            return new DiscardInfo(this, DiscardCode.obvious,
434                                   "Linear binary invariant implies divides");
435          }
436        }
437      }
438
439      return null;
440    }
441
442  }
443
444  /**
445   * Represents the square invariant between two double scalars.
446   * Prints as {@code x = y**2}.
447   */
448  public static class Square extends NumericFloat {
449    // We are Serializable, so we specify a version to allow changes to
450    // method signatures without breaking serialization.  If you add or
451    // remove fields, you should change this number to the current date.
452    static final long serialVersionUID = 20040113L;
453
454    protected Square(PptSlice ppt, boolean swap) {
455      super(ppt, swap);
456    }
457
458    protected Square(boolean swap) {
459      super(swap);
460    }
461
462    private static @Prototype Square proto = new @Prototype Square(false);
463    private static @Prototype Square proto_swap = new @Prototype Square(true);
464
465    /** Returns the prototype invariant. */
466    public static @Prototype Square get_proto(boolean swap) {
467      if (swap) {
468        return proto_swap;
469      } else {
470        return proto;
471      }
472    }
473
474    // Variables starting with dkconfig_ should only be set via the
475    // daikon.config.Configuration interface.
476    /** Boolean. True iff square invariants should be considered. */
477    public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault;
478
479    @Override
480    public boolean enabled() {
481      return dkconfig_enabled;
482    }
483    @Override
484    protected Square instantiate_dyn(@Prototype Square this, PptSlice slice) {
485      return new Square(slice, swap);
486    }
487
488    @Override
489    public String get_format_str(@GuardSatisfied Square this, OutputFormat format) {
490      if (format == OutputFormat.SIMPLIFY) {
491        return "(EQ %var1% (* %var2% %var2))";
492      } else if (format == OutputFormat.CSHARPCONTRACT) {
493        return "%var1% == %var2%*%var2%";
494      } else if (format.isJavaFamily()) {
495
496        return "daikon.Quant.fuzzy.eq(%var1%, %var2%*%var2%)";
497      } else {
498        return "%var1% == %var2%**2";
499      }
500    }
501
502    /** Check to see if x == y squared. */
503    @Override
504    public boolean eq_check(double x, double y) {
505      return Global.fuzzy.eq(x, y*y);
506    }
507
508    // Note there are no NI Suppressions for Square.  Two obvious
509    // suppressions are:
510    //
511    //      (var2 == 1) ^ (var1 == 1)  ==> var1 = var2*var2
512    //      (var2 == 0) ^ (var1 == 0)  ==> var1 = var2*var2
513    //
514    // But all of the antecedents would be constants, so we would
515    // never need to create this slice, so there is no reason to create
516    // these.
517
518  }
519
520  /**
521   * Represents the zero tracks invariant between
522   * two double scalars; that is, when {@code x} is zero,
523   * {@code y} is also zero.
524   * Prints as {@code x = 0 => y = 0}.
525   */
526  public static class ZeroTrack extends NumericFloat {
527    // We are Serializable, so we specify a version to allow changes to
528    // method signatures without breaking serialization.  If you add or
529    // remove fields, you should change this number to the current date.
530    static final long serialVersionUID = 20040313L;
531
532    protected ZeroTrack(PptSlice ppt, boolean swap) {
533      super(ppt, swap);
534    }
535
536    protected @Prototype ZeroTrack(boolean swap) {
537      super(swap);
538    }
539
540    private static @Prototype ZeroTrack proto = new @Prototype ZeroTrack(false);
541    private static @Prototype ZeroTrack proto_swap = new @Prototype ZeroTrack(true);
542
543    /** Returns the prototype invariant. */
544    public static @Prototype ZeroTrack get_proto(boolean swap) {
545      if (swap) {
546        return proto_swap;
547      } else {
548        return proto;
549      }
550    }
551
552    // Variables starting with dkconfig_ should only be set via the
553    // daikon.config.Configuration interface.
554    /** Boolean. True iff zero-track invariants should be considered. */
555    public static boolean dkconfig_enabled = false;
556
557    @Override
558    public boolean enabled() {
559      return dkconfig_enabled;
560    }
561
562    @Override
563    protected ZeroTrack instantiate_dyn(@Prototype ZeroTrack this, PptSlice slice) {
564      return new ZeroTrack(slice, swap);
565    }
566
567    @Override
568    public String get_format_str(@GuardSatisfied ZeroTrack this, OutputFormat format) {
569      if (format == OutputFormat.SIMPLIFY) {
570        return "(IMPLIES (EQ %var1% 0) (EQ %var2% 0))";
571      } else if (format.isJavaFamily() || format == OutputFormat.CSHARPCONTRACT) {
572        return "(!(%var1% == 0)) || (%var2% == 0)";
573      } else {
574        return "(%var1% == 0) ==> (%var2% == 0)";
575      }
576    }
577
578    @Override
579    public boolean eq_check(double x, double y) {
580      if (x == 0) {
581        return y == 0;
582      } else {
583        return true;
584      }
585    }
586
587    /** Returns a list of non-instantiating suppressions for this invariant. */
588    @Pure
589    @Override
590    public NISuppressionSet get_ni_suppressions() {
591      if (swap) {
592        return suppressions_swap;
593      } else {
594        return suppressions;
595      }
596    }
597
598    /** definition of this invariant (the suppressee) (unswapped) */
599    private static NISuppressee suppressee = new NISuppressee(ZeroTrack.class, false);
600
601    private static NISuppressionSet suppressions =
602      new NISuppressionSet(
603          new NISuppression[] {
604            // (var1 == var2) ==> (var1=0 ==> var2=0)
605            new NISuppression(var1_eq_var2, suppressee),
606            // (var1 != 0)    ==> (var1=0 ==> var2=0)
607            new NISuppression(var1_ne_0, suppressee),
608            // (var2 == 0) ==> (var1=0 ==> var2=0)
609            new NISuppression(var2_eq_0, suppressee),
610          });
611    private static NISuppressionSet suppressions_swap = suppressions.swap();
612
613  }
614
615//
616// Standard String invariants
617//
618
619}