/** Allocate relations for SubsetSig top-down. */ private Expression allocateSubsetSig(SubsetSig sig) throws Err { // We must not visit the same SubsetSig more than once, so if we've been here already, then // return the old value right away Expression sum = sol.a2k(sig); if (sum != null && sum != Expression.NONE) return sum; // Recursively form the union of all parent expressions TupleSet ts = factory.noneOf(1); for (Sig parent : sig.parents) { Expression p = (parent instanceof PrimSig) ? sol.a2k(parent) : allocateSubsetSig((SubsetSig) parent); ts.addAll(sol.query(true, p, false)); if (sum == null) sum = p; else sum = sum.union(p); } // If subset is exact, then just use the "sum" as is if (sig.exact) { sol.addSig(sig, sum); return sum; } // Allocate a relation for this subset sig, then bound it rep.bound("Sig " + sig + " in " + ts + "\n"); Relation r = sol.addRel(sig.label, null, ts); sol.addSig(sig, r); // Add a constraint that it is INDEED a subset of the union of its parents sol.addFormula(r.in(sum), sig.isSubset); return r; }
/** Allocate relations for nonbuiltin PrimSigs bottom-up. */ private Expression allocatePrimSig(PrimSig sig) throws Err { // Recursively allocate all children expressions, and form the union of them Expression sum = null; for (PrimSig child : sig.children()) { Expression childexpr = allocatePrimSig(child); if (sum == null) { sum = childexpr; continue; } // subsigs are disjoint sol.addFormula(sum.intersection(childexpr).no(), child.isSubsig); sum = sum.union(childexpr); } TupleSet lower = lb.get(sig).clone(), upper = ub.get(sig).clone(); if (sum == null) { // If sig doesn't have children, then sig should make a fresh relation for itself sum = sol.addRel(sig.label, lower, upper); } else if (sig.isAbstract == null) { // If sig has children, and sig is not abstract, then create a new relation to act as the // remainder. for (PrimSig child : sig.children()) { // Remove atoms that are KNOWN to be in a subsig; // it's okay to mistakenly leave some atoms in, since we will never solve for the // "remainder" relation directly; // instead, we union the remainder with the children, then solve for the combined solution. // (Thus, the more we can remove, the more efficient it gets, but it is not crucial for // correctness) TupleSet childTS = sol.query(false, sol.a2k(child), false); lower.removeAll(childTS); upper.removeAll(childTS); } sum = sum.union(sol.addRel(sig.label + " remainder", lower, upper)); } sol.addSig(sig, sum); return sum; }