001// ***** This file is automatically generated from OneOf.java.jpp
002
003package daikon.inv.unary.scalar;
004
005import daikon.*;
006import daikon.inv.*;
007import daikon.inv.unary.OneOf;
008
009  import daikon.derive.unary.*;
010  import daikon.inv.binary.sequenceScalar.*;
011  import daikon.inv.unary.sequence.*;
012
013import java.io.*;
014import java.util.logging.Logger;
015import java.util.logging.Level;
016import java.util.*;
017
018import org.checkerframework.checker.initialization.qual.Initialized;
019import org.checkerframework.checker.interning.qual.Interned;
020import org.checkerframework.checker.lock.qual.GuardSatisfied;
021import org.checkerframework.checker.nullness.qual.NonNull;
022import org.checkerframework.checker.nullness.qual.Nullable;
023import org.checkerframework.dataflow.qual.Pure;
024import org.checkerframework.dataflow.qual.SideEffectFree;
025import org.checkerframework.framework.qual.Unused;
026import daikon.SignaturesUtil;
027import org.plumelib.reflection.Signatures;
028import org.plumelib.util.ArraysPlume;
029import org.plumelib.util.Intern;
030import org.plumelib.util.StringsPlume;
031import org.plumelib.util.UtilPlume;
032import typequals.prototype.qual.NonPrototype;
033import typequals.prototype.qual.Prototype;
034
035// This subsumes an "exact" invariant that says the value is always exactly
036// a specific value.  Do I want to make that a separate invariant
037// nonetheless?  Probably not, as this will simplify implication and such.
038
039  /**
040   * Represents double variables that take on only a few distinct values. Prints as either
041   * {@code x == c} (when there is only one value) or as {@code x one of {c1, c2, c3}}
042   * (when there are multiple values).
043
044   */
045
046@SuppressWarnings("UnnecessaryParentheses")  // generated code, parentheses are sometimes needed
047public final class OneOfFloat extends SingleFloat implements OneOf {
048  static final long serialVersionUID = 20030822L;
049
050  /** Debugging logger. */
051  public static final Logger debug =
052    Logger.getLogger(OneOfFloat.class.getName());
053
054  // Variables starting with dkconfig_ should only be set via the
055  // daikon.config.Configuration interface.
056  /** Boolean. True iff OneOf invariants should be considered. */
057  public static boolean dkconfig_enabled = Invariant.invariantEnabledDefault;
058
059  /**
060   * Positive integer. Specifies the maximum set size for this type of invariant (x is one of
061   * {@code size} items).
062   */
063
064  public static int dkconfig_size = 3;
065
066  // Probably needs to keep its own list of the values, and number of each seen.
067  // (That depends on the slice; maybe not until the slice is cleared out.
068  // But so few values is cheap, so this is quite fine for now and long-term.)
069
070  @Unused(when=Prototype.class)
071  private double[] elts;
072  @Unused(when=Prototype.class)
073  private int num_elts;
074
075  @Prototype OneOfFloat() {
076    super();
077  }
078
079  OneOfFloat(PptSlice slice) {
080    super(slice);
081
082    elts = new double[dkconfig_size];
083
084    num_elts = 0;
085
086  }
087
088  private static @Prototype OneOfFloat proto = new @Prototype OneOfFloat();
089
090  /** Returns the prototype invariant for OneOfFloat */
091  public static @Prototype OneOfFloat get_proto() {
092    return proto;
093  }
094
095  @Override
096  public boolean enabled() {
097    return dkconfig_enabled;
098  }
099
100  @Override
101  public OneOfFloat instantiate_dyn(@Prototype OneOfFloat this, PptSlice slice) {
102    return new OneOfFloat(slice);
103  }
104
105  @Pure
106  public boolean is_boolean(@GuardSatisfied OneOfFloat this) {
107    return var().file_rep_type.elementType() == ProglangType.BOOLEAN;
108  }
109  @Pure
110  public boolean is_hashcode(@GuardSatisfied OneOfFloat this) {
111    return var().file_rep_type.elementType() == ProglangType.HASHCODE;
112  }
113
114  @SideEffectFree
115  @Override
116  public OneOfFloat clone(@GuardSatisfied OneOfFloat this) {
117    OneOfFloat result = (OneOfFloat) super.clone();
118    result.elts = elts.clone();
119
120    result.num_elts = this.num_elts;
121    return result;
122  }
123
124  @Override
125  public int num_elts() {
126    return num_elts;
127  }
128
129  @Override
130  public Object elt() {
131    return elt(0);
132  }
133
134  public Object elt(int index) {
135    if (num_elts <= index) {
136      throw new Error("Represents " + num_elts + " elements, index " + index + " not valid");
137    }
138
139    return Intern.internedDouble(elts[index]);
140  }
141
142  private void sort_rep(@GuardSatisfied OneOfFloat this) {
143    Arrays.sort(elts, 0, num_elts );
144  }
145
146  public double min_elt() {
147    if (num_elts == 0) {
148      throw new Error("Represents no elements");
149    }
150    sort_rep();
151    return elts[0];
152  }
153
154  public double max_elt() {
155    if (num_elts == 0) {
156      throw new Error("Represents no elements");
157    }
158    sort_rep();
159    return elts[num_elts - 1];
160  }
161
162  // Assumes the other array is already sorted
163  public boolean compare_rep(int num_other_elts, double[] other_elts) {
164    if (num_elts != num_other_elts) {
165      return false;
166    }
167    sort_rep();
168    for (int i = 0; i < num_elts; i++) {
169      if (!(Global.fuzzy.eq(elts[i], other_elts[i]) || (Double.isNaN(elts[i]) && Double.isNaN(other_elts[i])))) { // elements are interned
170        return false;
171      }
172    }
173    return true;
174  }
175
176  private String subarray_rep(@GuardSatisfied OneOfFloat this) {
177    // Not so efficient an implementation, but simple;
178    // and how often will we need to print this anyway?
179    sort_rep();
180    StringJoiner sj = new StringJoiner(", ", "{ ", " }");
181    for (int i = 0; i < num_elts; i++) {
182
183      if (PrintInvariants.dkconfig_static_const_infer) {
184        boolean curVarMatch = false;
185        PptTopLevel pptt = ppt.parent;
186        for (VarInfo vi : pptt.var_infos) {
187          if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) {
188            // If variable is a double, then use fuzzy comparison
189            if (vi.rep_type == ProglangType.DOUBLE) {
190              Double constantVal = (Double)vi.constantValue();
191              if (Global.fuzzy.eq(constantVal, elts[i]) || (Double.isNaN(constantVal) && Double.isNaN(elts[i]))) {
192                sj.add(vi.name());
193                curVarMatch = true;
194              }
195            }
196            // Otherwise just use the equals method
197            else {
198              Object constantVal = vi.constantValue();
199              if (constantVal.equals(elts[i])) {
200                sj.add(vi.name());
201                curVarMatch = true;
202              }
203            }
204          }
205        }
206
207        if (curVarMatch == false) {
208          sj.add((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])));
209        }
210      } else {
211        sj.add((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])));
212      }
213
214    }
215    return sj.toString();
216  }
217
218  @Override
219  public String repr(@GuardSatisfied OneOfFloat this) {
220    return "OneOfFloat" + varNames() + ": falsified=" + falsified
221      + ", num_elts=" + num_elts
222      + ", elts=" + subarray_rep();
223  }
224
225  public double[] getElts() {
226    double[] temp = new double[elts.length];
227    for (int i = 0; i < elts.length; i++) {
228      temp[i] = elts[i];
229    }
230    return temp;
231  }
232
233  @SideEffectFree
234  @Override
235  public String format_using(@GuardSatisfied OneOfFloat this, OutputFormat format) {
236    sort_rep();
237
238    if (format.isJavaFamily()) {
239      return format_java_family(format);
240    }
241
242    if (format == OutputFormat.DAIKON) {
243      return format_daikon();
244    } else if (format == OutputFormat.SIMPLIFY) {
245      return format_simplify();
246    } else if (format == OutputFormat.ESCJAVA) {
247      String result = format_esc();
248      return result;
249    } else if (format == OutputFormat.CSHARPCONTRACT) {
250      return format_csharp_contract();
251    } else {
252      return format_unimplemented(format);
253    }
254  }
255
256  public String format_daikon(@GuardSatisfied OneOfFloat this) {
257    String varname = var().name();
258    if (num_elts == 1) {
259
260        if (PrintInvariants.dkconfig_static_const_infer) {
261          PptTopLevel pptt = ppt.parent;
262          for (VarInfo vi : pptt.var_infos) {
263            if (vi.isStaticConstant() && VarComparability.comparable(vi, var())) {
264              if (vi.rep_type == ProglangType.DOUBLE) {
265                Double constantVal = (Double)vi.constantValue();
266                if (Global.fuzzy.eq(constantVal, elts[0]) || (Double.isNaN(constantVal) && Double.isNaN(elts[0]))) {
267                  return varname + " == " + vi.name();
268                }
269              } else {
270                Object constantVal = vi.constantValue();
271                if (constantVal.equals(elts[0])) {
272                  return varname + " == " + vi.name();
273                }
274              }
275            }
276          }
277        }
278        return varname + " == " + (Double.isNaN(elts[0]) ? "Double.NaN" : String.valueOf(elts[0]));
279    } else {
280      return varname + " one of " + subarray_rep();
281    }
282  }
283
284  public String format_esc(@GuardSatisfied OneOfFloat this) {
285    sort_rep();
286
287    String varname = var().esc_name();
288
289    String result;
290
291    {
292      result = "";
293      for (int i = 0; i < num_elts; i++) {
294        if (i != 0) { result += " || "; }
295        result += varname + " == " + (Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i]));
296      }
297    }
298
299    return result;
300  }
301
302public String format_csharp_contract(@GuardSatisfied OneOfFloat this) {
303
304    @NonNull @Initialized String result;
305
306  String varname = var().csharp_name();
307
308      if (num_elts == 1) {
309        result = varname + " == " + elts[0];
310      } else {
311        List<String> e = new ArrayList<>();
312        for (int i = 0; i < num_elts; i++) {
313          e.add((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])));
314        }
315        String exp = String.join(", ", e);
316
317        if (var().is_array() && !var().isDerived()) {
318          String[] split = var().csharp_array_split();
319          result = "Contract.ForAll(" + split[0] + ", x => x" + split[1] + ".OneOf(" + exp + "))";
320        } else {
321          result = varname + ".OneOf(" + exp + ")";
322        }
323      }
324
325    return result;
326  }
327
328  public String format_java_family(@GuardSatisfied OneOfFloat this, OutputFormat format) {
329
330    String result;
331
332    // Setting up the name of the unary variable
333    String varname = var().name_using(format);
334
335    {
336      result = "";
337      for (int i = 0; i < num_elts; i++) {
338        if (i != 0) {
339          result += " || ";
340        }
341
342        result += "daikon.Quant.fuzzy.eq(" + varname + ", " + (Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])) + ")";
343
344      }
345    }
346
347    return result;
348  }
349
350  public String format_simplify(@GuardSatisfied OneOfFloat this) {
351
352    sort_rep();
353
354    String varname =
355      var().simplifyFixup(var().name_using(OutputFormat.SIMPLIFY));
356
357    String result;
358
359    {
360      result = "";
361      for (int i = 0; i < num_elts; i++) {
362        result += " (EQ " + varname + " " + simplify_format_double(elts[i]) + ")";
363      }
364      if (num_elts > 1) {
365        result = "(OR" + result + ")";
366      } else if (num_elts == 1) {
367        // chop leading space
368        result = result.substring(1);
369      } else {
370        // Haven't actually seen any data, so we're vacuously true
371        return format_too_few_samples(OutputFormat.SIMPLIFY, null);
372      }
373    }
374
375    if (result.indexOf("format_simplify") == -1) {
376      daikon.simplify.SimpUtil.assert_well_formed(result);
377    }
378    return result;
379  }
380
381  @Override
382  public InvariantStatus add_modified(double a, int count) {
383    return runValue(a, count, true);
384  }
385
386  @Override
387  public InvariantStatus check_modified(double a, int count) {
388    return runValue(a, count, false);
389  }
390
391  private InvariantStatus runValue(double v, int count, boolean mutate) {
392    InvariantStatus status;
393    if (mutate) {
394      status = add_mod_elem(v, count);
395    } else {
396      status = check_mod_elem(v, count);
397    }
398    if (status == InvariantStatus.FALSIFIED) {
399      if (logOn() && mutate) {
400        StringBuilder eltString = new StringBuilder();
401        for (int i = 0; i < num_elts; i++) {
402          eltString.append((Double.isNaN(elts[i]) ? "Double.NaN" : String.valueOf(elts[i])) + " ");
403        }
404        log("destroyed on sample %s previous vals = {%s} num_elts = %s",
405             (Double.isNaN(v) ? "Double.NaN" : String.valueOf(v)), eltString, num_elts);
406      }
407      return InvariantStatus.FALSIFIED;
408    }
409    return status;
410  }
411
412  /**
413   * Adds a single sample to the invariant. Returns
414   * the appropriate InvariantStatus from the result
415   * of adding the sample to this.
416   */
417  public InvariantStatus add_mod_elem(double v, int count) {
418    InvariantStatus status = check_mod_elem(v, count);
419    if (status == InvariantStatus.WEAKENED) {
420      elts[num_elts] = v;
421      num_elts++;
422    }
423    return status;
424  }
425
426  /**
427   * Checks a single sample to the invariant. Returns
428   * the appropriate InvariantStatus from the result
429   * of adding the sample to this.
430   */
431  public InvariantStatus check_mod_elem(double v, int count) {
432
433    // Look for v in our list of previously seen values.  If it's
434    // found, we're all set.
435    for (int i = 0; i < num_elts; i++) {
436      // if (logDetail())
437      //  log ("add_modified (" + v + ")");
438      if ((Global.fuzzy.eq(elts[i], v) || (Double.isNaN(elts[i]) && Double.isNaN( v)))) {
439        return InvariantStatus.NO_CHANGE;
440      }
441    }
442
443    if (num_elts == dkconfig_size) {
444      return InvariantStatus.FALSIFIED;
445    }
446
447    return InvariantStatus.WEAKENED;
448  }
449
450  @Override
451  protected double computeConfidence() {
452    // This is not ideal.
453    if (num_elts == 0) {
454      return Invariant.CONFIDENCE_UNJUSTIFIED;
455    } else {
456      return Invariant.CONFIDENCE_JUSTIFIED;
457    }
458  }
459
460  @Pure
461  @Override
462  public @Nullable DiscardInfo isObviousStatically(VarInfo[] vis) {
463    // Static constants are necessarily OneOf precisely one value.
464    // This removes static constants from the output, which might not be
465    // desirable if the user doesn't know their actual value.
466    if (vis[0].isStaticConstant()) {
467      assert num_elts <= 1;
468      return new DiscardInfo(this, DiscardCode.obvious, vis[0].name() + " is a static constant.");
469    }
470    return super.isObviousStatically(vis);
471  }
472
473  @Pure
474  @Override
475  public @Nullable DiscardInfo isObviousDynamically(VarInfo[] vis) {
476    DiscardInfo super_result = super.isObviousDynamically(vis);
477    if (super_result != null) {
478      return super_result;
479    }
480
481    VarInfo v = vis[0];
482
483    Debug dlog = new Debug(getClass(), ppt, vis);
484
485    if (logOn()) {
486      dlog.log("enter isObviousDynamically");
487    }
488
489      // We can use the minvalue and maxvalue custom attributes here: if
490      // minimum value and maximum value are the same as the reported
491      // value, then we can suppress this invariant
492      if (num_elts == 1
493          && v.aux.hasValue(VarInfoAux.MINIMUM_VALUE)
494          && v.aux.hasValue(VarInfoAux.MAXIMUM_VALUE)) {
495        int min = v.aux.getInt(VarInfoAux.MINIMUM_VALUE),
496            max = v.aux.getInt(VarInfoAux.MAXIMUM_VALUE);
497        if (min == max && min == elts[0]) {
498          return new DiscardInfo(
499              this,
500              DiscardCode.obvious,
501              v.name() + "'s value matches with the expected value");
502        }
503      }
504
505      // We can check if all values in the list match with the ones we know about
506      // (useful for booleans and numeric enumerations).
507      if (v.aux.hasValue(VarInfoAux.VALID_VALUES)) {
508        String[] vsValidValues         = v.aux.getList(VarInfoAux.VALID_VALUES);
509        Set<Double> setValidValues = new TreeSet<>();
510        for (String s : vsValidValues) {
511          setValidValues.add(Double.valueOf(s));
512        }
513        Set<Double> setValuesInvariant = new TreeSet<>();
514        for (double e : elts) {
515          setValuesInvariant.add(e);
516        }
517        if (setValidValues.equals(setValuesInvariant)) {
518          return new DiscardInfo(this, DiscardCode.obvious,
519            "The value list matches the allowed value list");
520        }
521      }
522
523    // Obvious if we are 'size(array) == 0'  The thinking is that this
524    // will also always show up as 'array == []' which is a little more
525    // illuminating.  At this point we insist that we are a SequenceLength
526    // derivation of a base (underived) array.  Its quite possible this should
527    // just apply to all arrays.
528    if (v.isDerived() && (v.derived instanceof SequenceLength)
529      && (num_elts == 1) && (elts[0] == 0)) {
530      @NonNull VarInfo b = v.derived.getBase(0);
531      if (!b.isDerived()) {
532        if (logOn()) {
533          dlog.log("isObviousDynamically '" + v.name()
534                    + " == 0' ==> '" + b.name() + " == []'");
535        }
536        return new DiscardInfo(this, DiscardCode.obvious, "size(array) == 0 is implied by array == []");
537      }
538    }
539
540    if (v.isDerived() && (v.derived instanceof SequenceLength)) {
541      @NonNull SequenceLength sl = (SequenceLength) v.derived;
542      if (sl.shift != 0) {
543        String discardString = v.name() + " is derived with shift!=0 (shift==" + sl.shift + ")";
544        return new DiscardInfo(this, DiscardCode.obvious, discardString);
545      }
546    }
547
548    // For every EltOneOfFloat at this program point, see if this variable is
549    // an obvious member of that sequence.
550    PptTopLevel parent = ppt.parent;
551    for (Iterator<Invariant> itor = parent.invariants_iterator(); itor.hasNext(); ) {
552      Invariant inv = itor.next();
553      if ((inv instanceof EltOneOfFloat) && inv.enoughSamples()) {
554        VarInfo v1 = var();
555        VarInfo v2 = inv.ppt.var_infos[0];
556        // System.out.println("isObviousImplied: calling  Member.isObviousMember(" + v1.name + ", " + v2.name + ")");
557        // Don't use isEqualToObviousMember:  that is too subtle
558        // and eliminates desirable invariants such as "return == null".
559        if (Member.isObviousMember(v1, v2)) {
560          EltOneOfFloat other = (EltOneOfFloat) inv;
561          if (num_elts == other.num_elts()) {
562            sort_rep();
563            if (other.compare_rep(num_elts, elts)) {
564              // System.out.println("isObviousImplied true");
565              String discardString = v1.name()+" is a member of "+v2.name()+" for which this Invariant also holds";
566              return new DiscardInfo(this, DiscardCode.obvious, discardString);
567            }
568          }
569        }
570      }
571    }
572
573    return null;
574  }
575
576  /**
577   * Oneof can merge different formulas from lower points to create a single formula at an upper
578   * point.
579   */
580  @Override
581  public boolean mergeFormulasOk() {
582    return true;
583  }
584
585  @Pure
586  @Override
587  public boolean isSameFormula(Invariant o) {
588    OneOfFloat other = (OneOfFloat) o;
589    if (num_elts != other.num_elts) {
590      return false;
591    }
592    if (num_elts == 0 && other.num_elts == 0) {
593      return true;
594    }
595
596    sort_rep();
597    other.sort_rep();
598
599    for (int i = 0; i < num_elts; i++) {
600      if (!(Global.fuzzy.eq(elts[i], other.elts[i]) || (Double.isNaN(elts[i]) && Double.isNaN(other.elts[i])))) {
601        return false;
602      }
603    }
604
605    return true;
606  }
607
608  @Pure
609  @Override
610  public boolean isExclusiveFormula(Invariant o) {
611    if (o instanceof OneOfFloat) {
612      OneOfFloat other = (OneOfFloat) o;
613
614      if (num_elts == 0 || other.num_elts == 0) {
615        return false;
616      }
617      for (int i = 0; i < num_elts; i++) {
618        for (int j = 0; j < other.num_elts; j++) {
619          if ((Global.fuzzy.eq(elts[i], other.elts[j]) || (Double.isNaN(elts[i]) && Double.isNaN(other.elts[j])))) // elements are interned
620            return false;
621        }
622      }
623
624      return true;
625    }
626
627    // Many more checks can be added here:  against nonzero, modulus, etc.
628    if ((o instanceof NonZeroFloat) && (num_elts == 1) && (elts[0] == 0)) {
629      return true;
630    }
631    double elts_min = Double.MAX_VALUE;
632    double elts_max = Double.MIN_VALUE;
633    for (int i = 0; i < num_elts; i++) {
634      elts_min = Math.min(elts_min, elts[i]);
635      elts_max = Math.max(elts_max, elts[i]);
636    }
637    if ((o instanceof LowerBoundFloat) && (elts_max < ((LowerBoundFloat)o).min())) {
638      return true;
639    }
640    if ((o instanceof UpperBoundFloat) && (elts_min > ((UpperBoundFloat)o).max())) {
641      return true;
642    }
643
644    return false;
645  }
646
647  @Override
648  public boolean hasUninterestingConstant() {
649
650    for (int i = 0; i < num_elts; i++) {
651      if (elts[i] < -1.0 || elts[i] > 2.0 || elts[i] != (long)elts[i]) {
652        return true;
653      }
654    }
655
656    return false;
657  }
658
659  @Pure
660  @Override
661  public boolean isExact() {
662    return num_elts == 1;
663  }
664
665  // Look up a previously instantiated invariant.
666  public static @Nullable OneOfFloat find(PptSlice ppt) {
667    assert ppt.arity() == 1;
668    for (Invariant inv : ppt.invs) {
669      if (inv instanceof OneOfFloat) {
670        return (OneOfFloat) inv;
671      }
672    }
673    return null;
674  }
675
676  // Interning is lost when an object is serialized and deserialized.
677  // Manually re-intern any interned fields upon deserialization.
678  private void readObject(ObjectInputStream in) throws IOException,
679    ClassNotFoundException {
680    in.defaultReadObject();
681
682    for (int i = 0; i < num_elts; i++) {
683      elts[i] = Intern.intern(elts[i]);
684    }
685  }
686
687  /**
688   * Merge the invariants in invs to form a new invariant. Each must be a OneOfFloat invariant.
689   * This code finds all of the oneof values from each of the invariants and returns the merged
690   * invariant (if any).
691   *
692   * @param invs list of invariants to merge. The invariants must all be of the same type and should
693   *     come from the children of parent_ppt. They should also all be permuted to match the
694   *     variable order in parent_ppt.
695   * @param parent_ppt slice that will contain the new invariant
696   */
697  @Override
698  public @Nullable OneOfFloat merge(List<Invariant> invs, PptSlice parent_ppt) {
699
700    // Create the initial parent invariant from the first child
701    OneOfFloat  first = (OneOfFloat) invs.get(0);
702    OneOfFloat result = first.clone();
703    result.ppt = parent_ppt;
704
705    // Loop through the rest of the child invariants
706    for (int i = 1; i < invs.size(); i++ ) {
707
708      // Get this invariant
709      OneOfFloat inv = (OneOfFloat) invs.get(i);
710
711      // Loop through each distinct value found in this child and add
712      // it to the parent.  If the invariant is falsified, there is no parent
713      // invariant
714      for (int j = 0; j < inv.num_elts; j++) {
715        double val = inv.elts[j];
716
717        InvariantStatus status = result.add_mod_elem(val, 1);
718        if (status == InvariantStatus.FALSIFIED) {
719
720          result.log("%s", "child value '" + val + "' destroyed oneof");
721
722          return null;
723        }
724      }
725    }
726
727    result.log("Merged '%s' from %s child invariants", result.format(), invs.size());
728    return result;
729  }
730
731  /**
732   * Setup the invariant with the specified elements. Normally used when searching for a specified
733   * OneOf. The elements of vals are not necessarily interned; this method interns each element.
734   */
735  public void set_one_of_val(double[] vals) {
736
737    num_elts = vals.length;
738    for (int i = 0; i < num_elts; i++) {
739      elts[i] = Intern.intern(vals[i]);
740    }
741  }
742
743  /**
744   * Returns true if every element in this invariant is contained in the specified state. For
745   * example if x = 1 and the state contains 1 and 2, true will be returned.
746   */
747  @Override
748  public boolean state_match(Object state) {
749
750    if (num_elts == 0) {
751      return false;
752    }
753
754    if (!(state instanceof double[])) {
755      // Daikon is about to crash.  Produce some debugging output.
756      System.out.printf("state = %s [%s]%n", state, state.getClass());
757      System.out.printf("problem with %s%n", this);
758    }
759    double[] e = (double[]) state;
760    for (int i = 0; i < num_elts; i++) {
761      boolean match = false;
762      for (int j = 0; j < e.length; j++) {
763        if (elts[i] == e[j]) {
764          match = true;
765          break;
766        }
767      }
768      if (!match) {
769        return false;
770      }
771    }
772    return true;
773  }
774
775}