Пример #1
0
  @Test
  public final void testAcyclic() {
    bounds.bound(ac1, factory.area(factory.tuple("0", "0"), factory.tuple("4", "4")));
    assertNotNull(solve(ac1.some().and(ac1.acyclic())));
    assertPrimVarNum(10);

    bounds.bound(r1, factory.range(factory.tuple("0"), factory.tuple("4")));
    assertNotNull(solve(ac1.join(r1).some().and(ac1.acyclic())));
    assertPrimVarNum(10 + bounds.upperBound(r1).size());

    TupleSet ac2b = factory.setOf("5", "6", "7", "8");
    ac2b = ac2b.product(ac2b);
    bounds.bound(ac2, ac2b);
    assertNotNull(solve(ac1.difference(ac2).some().and(ac1.acyclic()).and(ac2.acyclic())));
    assertPrimVarNum(10 + 6);

    bounds.boundExactly(r2, factory.setOf(factory.tuple("5", "6")));
    assertNotNull(solve(ac2.join(r2).some().and(ac2.acyclic())));

    final TupleSet ac3Bound = factory.allOf(2);
    ac3Bound.remove(factory.tuple("9", "9"));
    bounds.bound(ac3, ac3Bound);

    assertNotNull(
        solve(ac1.difference(ac2).union(ac3).some().and(ac1.acyclic()).and(ac2.acyclic())));
    assertPrimVarNum(ac3Bound.size() + 10 + 6);

    bounds.bound(to3, factory.allOf(2));
    bounds.bound(ord3, factory.setOf("0", "1", "2"));
    bounds.bound(first3, bounds.upperBound(ord3));
    bounds.bound(last3, bounds.upperBound(ord3));
    assertNotNull(
        solve(to3.product(ac1).some().and(ac1.acyclic()).and(to3.totalOrder(ord3, first3, last3))));
    assertPrimVarNum(bounds.upperBound(ac1).size());
  }
Пример #2
0
 /**
  * Computes the lowerbound from bottom-up; it will also set a suitable initial value for each
  * sig's upperbound. Precondition: sig is not a builtin sig
  */
 private TupleSet computeLowerBound(List<Tuple> atoms, final PrimSig sig) throws Err {
   int n = sc.sig2scope(sig);
   TupleSet lower = factory.noneOf(1);
   for (PrimSig c : sig.children()) lower.addAll(computeLowerBound(atoms, c));
   TupleSet upper = lower.clone();
   boolean isExact = sc.isExact(sig);
   if (isExact || sig.isTopLevel())
     for (n = n - upper.size(); n > 0; n--) {
       Tuple atom = atoms.remove(atoms.size() - 1);
       // If MUST<SCOPE and s is exact, then add fresh atoms to both LOWERBOUND and UPPERBOUND.
       // If MUST<SCOPE and s is inexact but toplevel, then add fresh atoms to the UPPERBOUND.
       if (isExact) lower.add(atom);
       upper.add(atom);
     }
   lb.put(sig, lower);
   ub.put(sig, upper);
   return lower;
 }
Пример #3
0
 /**
  * Computes the bounds for sigs/fields, then construct a BoundsComputer object that you can query.
  */
 private BoundsComputer(A4Reporter rep, A4Solution sol, ScopeComputer sc, Iterable<Sig> sigs)
     throws Err {
   this.sc = sc;
   this.factory = sol.getFactory();
   this.rep = rep;
   this.sol = sol;
   // Figure out the sig bounds
   final Universe universe = factory.universe();
   final int atomN = universe.size();
   final List<Tuple> atoms = new ArrayList<Tuple>(atomN);
   for (int i = atomN - 1; i >= 0; i--) atoms.add(factory.tuple(universe.atom(i)));
   for (Sig s : sigs) if (!s.builtin && s.isTopLevel()) computeLowerBound(atoms, (PrimSig) s);
   for (Sig s : sigs) if (!s.builtin && s.isTopLevel()) computeUpperBound((PrimSig) s);
   // Bound the sigs
   for (Sig s : sigs) if (!s.builtin && s.isTopLevel()) allocatePrimSig((PrimSig) s);
   for (Sig s : sigs) if (s instanceof SubsetSig) allocateSubsetSig((SubsetSig) s);
   // Bound the fields
   again:
   for (Sig s : sigs) {
     while (s.isOne != null
         && s.getFieldDecls().size() == 2
         && s.getFields().size() == 2
         && s.getFacts().size() == 1) {
       // Let's check whether this is a total ordering on an enum...
       Expr fact = s.getFacts().get(0).deNOP(),
           b1 = s.getFieldDecls().get(0).expr.deNOP(),
           b2 = s.getFieldDecls().get(1).expr.deNOP(),
           b3;
       if (!(fact instanceof ExprList)
           || !(b1 instanceof ExprUnary)
           || !(b2 instanceof ExprBinary)) break;
       ExprList list = (ExprList) fact;
       if (list.op != ExprList.Op.TOTALORDER || list.args.size() != 3) break;
       if (((ExprUnary) b1).op != ExprUnary.Op.SETOF) break;
       else b1 = ((ExprUnary) b1).sub.deNOP();
       if (((ExprBinary) b2).op != ExprBinary.Op.ARROW) break;
       else {
         b3 = ((ExprBinary) b2).right.deNOP();
         b2 = ((ExprBinary) b2).left.deNOP();
       }
       if (!(b1 instanceof PrimSig) || b1 != b2 || b1 != b3) break;
       PrimSig sub = (PrimSig) b1;
       Field f1 = s.getFields().get(0), f2 = s.getFields().get(1);
       if (sub.isEnum == null
           || !list.args.get(0).isSame(sub)
           || !list.args.get(1).isSame(s.join(f1))
           || !list.args.get(2).isSame(s.join(f2))) break;
       // Now, we've confirmed it is a total ordering on an enum. Let's pre-bind the relations
       TupleSet me = sol.query(true, sol.a2k(s), false),
           firstTS = factory.noneOf(2),
           lastTS = null,
           nextTS = factory.noneOf(3);
       if (me.size() != 1 || me.arity() != 1) break;
       int n = sub.children().size();
       for (PrimSig c : sub.children()) {
         TupleSet TS = sol.query(true, sol.a2k(c), false);
         if (TS.size() != 1 || TS.arity() != 1) {
           firstTS = factory.noneOf(2);
           nextTS = factory.noneOf(3);
           break;
         }
         if (lastTS == null) {
           firstTS = me.product(TS);
           lastTS = TS;
           continue;
         }
         nextTS.addAll(me.product(lastTS).product(TS));
         lastTS = TS;
       }
       if (firstTS.size() != (n > 0 ? 1 : 0) || nextTS.size() != n - 1) break;
       sol.addField(f1, sol.addRel(s.label + "." + f1.label, firstTS, firstTS));
       sol.addField(f2, sol.addRel(s.label + "." + f2.label, nextTS, nextTS));
       rep.bound("Field " + s.label + "." + f1.label + " == " + firstTS + "\n");
       rep.bound("Field " + s.label + "." + f2.label + " == " + nextTS + "\n");
       continue again;
     }
     for (Field f : s.getFields()) {
       boolean isOne = s.isOne != null;
       if (isOne && f.decl().expr.mult() == ExprUnary.Op.EXACTLYOF) {
         Expression sim = sim(f.decl().expr);
         if (sim != null) {
           rep.bound("Field " + s.label + "." + f.label + " defined to be " + sim + "\n");
           sol.addField(f, sol.a2k(s).product(sim));
           continue;
         }
       }
       Type t = isOne ? Sig.UNIV.type().join(f.type()) : f.type();
       TupleSet ub = factory.noneOf(t.arity());
       for (List<PrimSig> p : t.fold()) {
         TupleSet upper = null;
         for (PrimSig b : p) {
           TupleSet tmp = sol.query(true, sol.a2k(b), false);
           if (upper == null) upper = tmp;
           else upper = upper.product(tmp);
         }
         ub.addAll(upper);
       }
       Relation r = sol.addRel(s.label + "." + f.label, null, ub);
       sol.addField(f, isOne ? sol.a2k(s).product(r) : r);
     }
   }
   // Add any additional SIZE constraints
   for (Sig s : sigs)
     if (!s.builtin) {
       Expression exp = sol.a2k(s);
       TupleSet upper = sol.query(true, exp, false), lower = sol.query(false, exp, false);
       final int n = sc.sig2scope(s);
       if (s.isOne != null && (lower.size() != 1 || upper.size() != 1)) {
         rep.bound("Sig " + s + " in " + upper + " with size==1\n");
         sol.addFormula(exp.one(), s.isOne);
         continue;
       }
       if (s.isSome != null && lower.size() < 1) sol.addFormula(exp.some(), s.isSome);
       if (s.isLone != null && upper.size() > 1) sol.addFormula(exp.lone(), s.isLone);
       if (n < 0) continue; // This means no scope was specified
       if (lower.size() == n && upper.size() == n && sc.isExact(s)) {
         rep.bound("Sig " + s + " == " + upper + "\n");
       } else if (sc.isExact(s)) {
         rep.bound("Sig " + s + " in " + upper + " with size==" + n + "\n");
         sol.addFormula(size(s, n, true), Pos.UNKNOWN);
       } else if (upper.size() <= n) {
         rep.bound("Sig " + s + " in " + upper + "\n");
       } else {
         rep.bound("Sig " + s + " in " + upper + " with size<=" + n + "\n");
         sol.addFormula(size(s, n, false), Pos.UNKNOWN);
       }
     }
 }