001// ***** This file is automatically generated from Bound.java.jpp
002
003package daikon.inv.unary.scalar;
004
005import daikon.*;
006import daikon.inv.*;
007
008  import daikon.inv.binary.sequenceScalar.*;
009  import daikon.inv.unary.sequence.*;
010
011import daikon.derive.unary.*;
012import daikon.inv.unary.*;
013import java.util.*;
014import org.checkerframework.checker.interning.qual.Interned;
015import org.checkerframework.checker.lock.qual.GuardSatisfied;
016import org.checkerframework.checker.nullness.qual.Nullable;
017import org.checkerframework.dataflow.qual.Pure;
018import org.checkerframework.dataflow.qual.SideEffectFree;
019import org.checkerframework.framework.qual.Unused;
020import org.plumelib.util.Intern;
021import typequals.prototype.qual.NonPrototype;
022import typequals.prototype.qual.Prototype;
023
024  /**
025   * Represents the invariant {@code x <= c}, where {@code c} is a constant and
026   * {@code x} is a long scalar.
027   */
028
029// One reason not to combine LowerBound and UpperBound into a single range
030// invariant is that they have separate justifications:  one may be
031// justified when the other is not.
032@SuppressWarnings("UnnecessaryParentheses")  // code generated by macros
033public class UpperBound extends SingleScalar {
034  // We are Serializable, so we specify a version to allow changes to
035  // method signatures without breaking serialization.  If you add or
036  // remove fields, you should change this number to the current date.
037  static final long serialVersionUID = 20030822L;
038
039  // Variables starting with dkconfig_ should only be set via the
040  // daikon.config.Configuration interface.
041  /** Boolean. True iff UpperBound invariants should be considered. */
042  public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault;
043  /**
044   * Long integer. Together with the corresponding {@code maximal_interesting} parameter,
045   * specifies the range of the computed constant that is ``interesting'' --- the range that should
046   * be reported. For instance, setting {@code minimal_interesting} to -1 and
047   * {@code maximal_interesting} to 2 would only permit output of UpperBound invariants whose
048   * cutoff was one of (-1,0,1,2).
049   */
050  public static long dkconfig_minimal_interesting = -1;
051  /**
052   * Long integer. Together with the corresponding {@code minimal_interesting} parameter,
053   * specifies the range of the computed constant that is ``interesting'' --- the range that should
054   * be reported. For instance, setting {@code minimal_interesting} to -1 and
055   * {@code maximal_interesting} to 2 would only permit output of UpperBound invariants whose
056   * cutoff was one of (-1,0,1,2).
057   */
058  public static long dkconfig_maximal_interesting = 2;
059
060  @Unused(when=Prototype.class)
061  private UpperBoundCore core;
062
063  @SuppressWarnings("nullness") // circular initialization
064  private UpperBound(PptSlice slice) {
065    super(slice);
066    assert slice != null;
067    core = new UpperBoundCore(this);
068  }
069
070  private @Prototype UpperBound() {
071    super();
072    // do we need a core?
073  }
074
075  private static @Prototype UpperBound proto = new @Prototype UpperBound();
076
077  /** Returns the prototype invariant for UpperBound */
078  public static @Prototype UpperBound get_proto() {
079    return proto;
080  }
081
082  /** returns whether or not this invariant is enabled */
083  @Override
084  public boolean enabled() {
085    return dkconfig_enabled;
086  }
087
088  /** UpperBound is only valid on integral types. */
089  @Override
090  public boolean instantiate_ok(VarInfo[] vis) {
091
092    if (!valid_types(vis)) {
093      return false;
094    }
095
096    return vis[0].file_rep_type.baseIsIntegral();
097    }
098
099  /** instantiate an invariant on the specified slice */
100  @Override
101  public UpperBound instantiate_dyn(@Prototype UpperBound this, PptSlice slice) {
102    return new UpperBound(slice);
103  }
104
105  @SideEffectFree
106  @Override
107  public UpperBound clone(@GuardSatisfied UpperBound this) {
108    UpperBound result = (UpperBound) super.clone();
109    result.core = core.clone();
110    result.core.wrapper = result;
111    return result;
112  }
113
114  public long max() {
115    return core.max();          // i.e., core.max1
116  }
117
118  @Override
119  public String repr(@GuardSatisfied UpperBound this) {
120    return "UpperBound" + varNames() + ": "
121      + core.repr();
122  }
123
124  @SideEffectFree
125  @Override
126  public String format_using(@GuardSatisfied UpperBound this, OutputFormat format) {
127    String name = var().name_using(format);
128    PptTopLevel pptt = ppt.parent;
129
130    if ((format == OutputFormat.DAIKON)
131        || (format == OutputFormat.ESCJAVA)
132        || format.isJavaFamily()
133        || (format == OutputFormat.CSHARPCONTRACT)) {
134
135      if (PrintInvariants.dkconfig_static_const_infer) {
136        for (VarInfo vi : pptt.var_infos) {
137          // Check is static constant, and variables are comparable
138          if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) {
139            // If variable is a double, then use fuzzy comparison
140            if (vi.rep_type == ProglangType.DOUBLE) {
141              Double constantVal = (Double)vi.constantValue();
142              if (Global.fuzzy.eq(constantVal, (double)(core.max1)) || false) {
143                return name + " <= " + vi.name();
144              }
145            }
146            // Otherwise just use the equals method
147            else {
148              Object constantVal = vi.constantValue();
149              if (constantVal.equals(core.max1)) {
150                return name + " <= " + vi.name();
151              }
152            }
153          }
154        }
155      }
156
157      return name + " <= " + core.max1;
158    }
159
160    if (format == OutputFormat.SIMPLIFY) {
161
162      return "(<= " + name + " " + simplify_format_long(core.max1) + ")";
163    }
164
165    return format_unimplemented(format);
166  }
167
168  @Override
169  public InvariantStatus add_modified(long value, int count) {
170    // System.out.println("UpperBound" + varNames() + ": "
171    //              + "add(" + value + ", " + modified + ", " + count + ")");
172
173    return core.add_modified(value, count);
174
175  }
176
177  @Override
178  public InvariantStatus check_modified(long value, int count) {
179
180    return core.check(value);
181
182  }
183
184  @Override
185  public boolean enoughSamples(@GuardSatisfied UpperBound this) {
186    return core.enoughSamples();
187  }
188
189  @Override
190  protected double computeConfidence() {
191    return core.computeConfidence();
192  }
193
194  @Pure
195  @Override
196  public boolean isExact() {
197    return core.isExact();
198  }
199
200  @Pure
201  @Override
202  public boolean isSameFormula(Invariant other) {
203    return core.isSameFormula(((UpperBound) other).core);
204  }
205
206  @Override
207  public boolean hasUninterestingConstant() {
208    // If the constant bound is not in some small range of interesting
209    // values (by default {-1, 0, 1, 2}), call it uninteresting.
210    if ((core.max1 < dkconfig_minimal_interesting)
211        || (core.max1 > dkconfig_maximal_interesting)) {
212      return true;
213    }
214
215    return false;
216  }
217
218  @Pure
219  @Override
220  public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) {
221    VarInfo var = vis[0];
222    if ((var.derived instanceof SequenceLength)
223         && (((SequenceLength) var.derived).shift != 0)) {
224      return new DiscardInfo(this, DiscardCode.obvious, "Bounds are preferrable over sequence lengths with no shift");
225    }
226
227    if (var.aux.hasValue(VarInfoAux.MAXIMUM_VALUE)) {
228      int minVal = var.aux.getInt(VarInfoAux.MAXIMUM_VALUE);
229      if (minVal == core.max1) {
230        return new DiscardInfo(this, DiscardCode.obvious,
231          var.name() + " GTE " + core.max1 + " is already known");
232      }
233    }
234
235    return super.isObviousStatically(vis);
236  }
237
238  @Pure
239  @Override
240  public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) {
241    DiscardInfo super_result = super.isObviousDynamically(vis);
242    if (super_result != null) {
243      return super_result;
244    }
245
246    PptTopLevel pptt = ppt.parent;
247
248    // This check always lets invariants pass through (even if it is not within
249    // the default range of (-1 to 2) if it matches a static constant
250    // As noted below, this check really doesn't belong here, but should be
251    // moved to hasUninterestingConstant() whenever that is implemented
252    if (PrintInvariants.dkconfig_static_const_infer) {
253      if (core.matchConstant()) {
254        return null;
255      }
256    }
257
258    // if the value is not in some range (like -1,0,1,2) then say that it is obvious
259    if ((core.max1 < dkconfig_minimal_interesting)
260        || (core.max1 > dkconfig_maximal_interesting)) {
261      // XXX This check doesn't really belong here. However It
262      // shouldn't get removed until hasUninterestingConstant() is
263      // suitable to be turned on everywhere by default. -SMcC
264      // if the value is not in some range (like -1,0,1,2) then say that
265      // it is obvious
266      String discardString = "";
267      if (core.max1 < dkconfig_minimal_interesting) {
268        discardString = "MIN1="+core.max1+" is less than dkconfig_minimal_interesting=="
269          + dkconfig_minimal_interesting;
270      } else {
271        discardString = "MIN1="+core.max1+" is greater than dkconfig_maximal_interesting=="+
272          dkconfig_maximal_interesting;
273      }
274      return new DiscardInfo(this, DiscardCode.obvious, discardString);
275    }
276    OneOfScalar oo = OneOfScalar.find(ppt);
277    if ((oo != null) && oo.enoughSamples() && oo.num_elts() > 0) {
278      assert oo.var().isCanonical();
279      // We could also use core.max1 == oo.max_elt(), since the LowerBound
280      // will never have a core.max1 that does not appear in the OneOf.
281      if (core.max1 >= oo.max_elt()) {
282        String varName = vis[0].name();
283        String discardString = varName + ">=" + core.max1 + " is implied by " + varName + ">=" + oo.max_elt();
284        log("%s", discardString);
285        return new DiscardInfo(this, DiscardCode.obvious, discardString);
286      }
287    }
288
289    // NOT: "VarInfo v = var();" because we want to operate not on this
290    // object's own variables, but on the variables that were passed in.
291    VarInfo v = vis[0];
292
293    // For each sequence variable, if this is an obvious member/subsequence, and
294    // it has the same invariant, then this one is obvious.
295    for (int i = 0; i < pptt.var_infos.length; i++) {
296      VarInfo vi = pptt.var_infos[i];
297
298      if (Member.isObviousMember(v, vi))
299      {
300        PptSlice1 other_slice = pptt.findSlice(vi);
301        if (other_slice != null) {
302          EltUpperBound eb = EltUpperBound.find(other_slice);
303          if ((eb != null)
304              && eb.enoughSamples()
305              && eb.max() == max()) {
306            String otherName = other_slice.var_infos[0].name();
307            String varName = v.name();
308            String discardString = varName+" is a subsequence of "+otherName+" for which the invariant holds.";
309            log("%s", discardString);
310            return new DiscardInfo(this, DiscardCode.obvious, discardString);
311          }
312        }
313      }
314    }
315
316    return null;
317  }
318
319  @Pure
320  @Override
321  public boolean isExclusiveFormula(Invariant other) {
322
323    if (other instanceof LowerBound) {
324      if (max() < ((LowerBound) other).min()) {
325        return true;
326      }
327    }
328
329    if (other instanceof OneOfScalar) {
330      return other.isExclusiveFormula(this);
331    }
332    return false;
333  }
334
335  // Look up a previously instantiated invariant.
336  public static @Nullable UpperBound find(PptSlice ppt) {
337    assert ppt.arity() == 1;
338    for (Invariant inv : ppt.invs) {
339      if (inv instanceof UpperBound) {
340        return (UpperBound) inv;
341      }
342    }
343    return null;
344  }
345
346  /**
347   * Bound can merge different formulas from lower points to create a single formula at an upper
348   * point. See merge() below.
349   */
350  @Override
351  public boolean mergeFormulasOk() {
352    return true;
353  }
354
355  /**
356   * Merge the invariants in invs to form a new invariant. Each must be a UpperBound invariant. This
357   * code finds all of the min/max values in each invariant, applies them to a new parent invariant
358   * and returns the merged invariant (if any).
359   *
360   * @param invs list of invariants to merge. The invariants must all be of the same type and should
361   *     come from the children of parent_ppt. They should also all be permuted to match the
362   *     variable order in parent_ppt.
363   * @param parent_ppt slice that will contain the new invariant
364   */
365  @Override
366  public @Nullable Invariant merge(List<Invariant> invs, PptSlice parent_ppt) {
367
368    // Create the initial parent invariant from the first child
369    UpperBound first = (UpperBound) invs.get(0);
370    UpperBound result= first.clone();
371    result.ppt = parent_ppt;
372
373    // Loop through the rest of the child invariants
374    for (int i = 1; i < invs.size(); i++ ) {
375      UpperBound lb = (UpperBound) invs.get(i);
376      result.core.add(lb.core);
377    }
378
379    result.log("Merged '%s' from %s child invariants", result.format(),invs.size());
380    return result;
381  }
382}