use of edu.mit.csail.sdg.ast.Sig.Field in project org.alloytools.alloy by AlloyTools.
the class SimInstance method validate.
/**
* Checks whether this instance satisfies every fact defined in the given model.
*
* @param world - this must be the root of the Alloy model
* @return an empty String if yes, nonempty String if no
*/
public String validate(Module world) {
try {
for (Sig s : world.getAllReachableSigs()) if (!s.builtin) {
if (s.isLone != null && !(visit(s).longsize() <= 1))
return "There can be at most one " + s;
if (s.isOne != null && !(visit(s).longsize() == 1))
return "There must be exactly one " + s;
if (s.isSome != null && !(visit(s).longsize() >= 1))
return "There must be at least one " + s;
if (s instanceof SubsetSig) {
SubsetSig p = (SubsetSig) s;
Expr sum = null;
for (Sig par : p.parents) sum = par.plus(sum);
if (p.exact) {
if (!equal(s, sum))
return "Sig " + s + " must be equal to the union of its parents " + p.parents;
} else {
if (!isIn(s, sum))
return "Sig " + s + " must be equal or subset of its parents " + p.parents;
}
} else if (s != Sig.UNIV && s != Sig.NONE) {
PrimSig p = (PrimSig) s;
if (!isIn(s, p.parent))
return "Sig " + s + " must be equal or subset of its parent " + p.parent;
}
if (s.isAbstract != null) {
Expr sum = null;
for (Sig x : ((PrimSig) s).children()) sum = x.plus(sum);
if (sum != null && !equal(s, sum))
return "Abstract sig " + s + " must be equal to the union of its subsigs";
}
for (Decl d : s.getFieldDecls()) for (ExprHasName f : d.names) if (!((Field) f).defined) {
if (!cform(s.decl.get().join(f).in(d.expr).forAll(s.decl))) {
return "Field " + f + " violated its bound: " + visit((Field) f) + "\n" + d.expr;
}
SimTupleset setS = visit(s);
SimTupleset setF = visit((Field) f);
for (SimAtom x : setF.getAllAtoms(0)) if (!setS.has(x))
return "Field " + f + " first column has extra atom: " + setF + " not in " + setS;
}
for (Decl d : s.getFieldDecls()) {
if (d.disjoint != null && d.names.size() > 0) {
if (!cform(ExprList.makeDISJOINT(null, null, d.names)))
return "Fields must be disjoint.";
}
if (d.disjoint2 != null)
for (ExprHasName f : d.names) {
Decl that = s.oneOf("that");
Expr formula = s.decl.get().equal(that.get()).not().implies(s.decl.get().join(f).intersect(that.get().join(f)).no());
if (!cform(formula.forAll(that).forAll(s.decl)))
return "Fields must be disjoint.";
}
}
for (Expr f : s.getFacts()) {
if (!cform(f.forAll(s.decl))) {
f = f.deNOP();
if (f instanceof ExprUnary) {
ExprUnary u = (ExprUnary) f;
f = u.sub.deNOP();
if (f instanceof ExprBinary) {
ExprBinary b = (ExprBinary) f;
if (b.op == ExprBinary.Op.JOIN && b.left.isSame(s.decl.get()) && b.right.deNOP() instanceof Field) {
String n = ((Field) (b.right.deNOP())).label;
if (u.op == ExprUnary.Op.SOME)
return "The " + n + " cannot be empty.";
if (u.op == ExprUnary.Op.LONE)
return "The " + n + " cannot have more than one value.";
if (u.op == ExprUnary.Op.ONE)
return "The " + n + " must have exactly one value.";
if (u.op == ExprUnary.Op.NO)
return "The " + n + " must be empty.";
}
}
}
return "Cannot violate a consistency constraint";
}
}
}
for (Module m : world.getAllReachableModules()) for (Pair<String, Expr> f : m.getAllFacts()) if (!cform(f.b)) {
String err = f.a;
if (err.matches("^fact\\$[0-9][0-9]*"))
err = f.b.toString();
if (err.length() >= 2 && err.startsWith("\"") && err.endsWith("\""))
err = err.substring(1, err.length() - 1);
return "Violation: " + err;
}
return "";
} catch (Err ex) {
return "An internal error has occured:\n" + ex.dump();
}
}
use of edu.mit.csail.sdg.ast.Sig.Field in project org.alloytools.alloy by AlloyTools.
the class A4Solution method rename.
/**
* Helper method that chooses a name for each atom based on its most specific
* sig; (external caller should call this method with s==null and nexts==null)
*/
private static void rename(A4Solution frame, PrimSig s, Map<Sig, List<Tuple>> nexts, UniqueNameGenerator un) throws Err {
if (s == null) {
for (ExprVar sk : frame.skolems) un.seen(sk.label);
// Store up the skolems
List<Object> skolems = new ArrayList<Object>();
for (Map.Entry<Relation, Type> e : frame.rel2type.entrySet()) {
Relation r = e.getKey();
if (!frame.eval.instance().contains(r))
continue;
Type t = e.getValue();
if (t.arity() > r.arity())
// Something is wrong; let's skip it
continue;
while (t.arity() < r.arity()) t = UNIV.type().product(t);
String n = Util.tail(r.name());
while (n.length() > 0 && n.charAt(0) == '$') n = n.substring(1);
skolems.add(n);
skolems.add(t);
skolems.add(r);
}
// Find all suitable "next" or "prev" relations
nexts = new LinkedHashMap<Sig, List<Tuple>>();
for (Sig sig : frame.sigs) for (Field f : sig.getFields()) if (f.label.compareToIgnoreCase("next") == 0) {
List<List<PrimSig>> fold = f.type().fold();
if (fold.size() == 1) {
List<PrimSig> t = fold.get(0);
if (t.size() == 3 && t.get(0).isOne != null && t.get(1) == t.get(2) && !nexts.containsKey(t.get(1))) {
TupleSet set = frame.eval.evaluate(frame.a2k(t.get(1)));
if (set.size() <= 1)
continue;
TupleSet next = frame.eval.evaluate(frame.a2k(t.get(0)).join(frame.a2k(f)));
List<Tuple> test = isOrder(next, set);
if (test != null)
nexts.put(t.get(1), test);
} else if (t.size() == 2 && t.get(0) == t.get(1) && !nexts.containsKey(t.get(0))) {
TupleSet set = frame.eval.evaluate(frame.a2k(t.get(0)));
if (set.size() <= 1)
continue;
TupleSet next = frame.eval.evaluate(frame.a2k(f));
List<Tuple> test = isOrder(next, set);
if (test != null)
nexts.put(t.get(1), test);
}
}
}
for (Sig sig : frame.sigs) for (Field f : sig.getFields()) if (f.label.compareToIgnoreCase("prev") == 0) {
List<List<PrimSig>> fold = f.type().fold();
if (fold.size() == 1) {
List<PrimSig> t = fold.get(0);
if (t.size() == 3 && t.get(0).isOne != null && t.get(1) == t.get(2) && !nexts.containsKey(t.get(1))) {
TupleSet set = frame.eval.evaluate(frame.a2k(t.get(1)));
if (set.size() <= 1)
continue;
TupleSet next = frame.eval.evaluate(frame.a2k(t.get(0)).join(frame.a2k(f)).transpose());
List<Tuple> test = isOrder(next, set);
if (test != null)
nexts.put(t.get(1), test);
} else if (t.size() == 2 && t.get(0) == t.get(1) && !nexts.containsKey(t.get(0))) {
TupleSet set = frame.eval.evaluate(frame.a2k(t.get(0)));
if (set.size() <= 1)
continue;
TupleSet next = frame.eval.evaluate(frame.a2k(f).transpose());
List<Tuple> test = isOrder(next, set);
if (test != null)
nexts.put(t.get(1), test);
}
}
}
// Assign atom->name and atom->MostSignificantSig
for (Tuple t : frame.eval.evaluate(Expression.INTS)) {
frame.atom2sig.put(t.atom(0), SIGINT);
}
for (Tuple t : frame.eval.evaluate(KK_SEQIDX)) {
frame.atom2sig.put(t.atom(0), SEQIDX);
}
for (Tuple t : frame.eval.evaluate(KK_STRING)) {
frame.atom2sig.put(t.atom(0), STRING);
}
for (Sig sig : frame.sigs) if (sig instanceof PrimSig && !sig.builtin && ((PrimSig) sig).isTopLevel())
rename(frame, (PrimSig) sig, nexts, un);
// These are redundant atoms that were not chosen to be in the final
// instance
int unused = 0;
for (Tuple tuple : frame.eval.evaluate(Expression.UNIV)) {
Object atom = tuple.atom(0);
if (!frame.atom2sig.containsKey(atom)) {
frame.atom2name.put(atom, "unused" + unused);
unused++;
}
}
// Add the skolems
for (int num = skolems.size(), i = 0; i < num - 2; i = i + 3) {
String n = (String) skolems.get(i);
while (n.length() > 0 && n.charAt(0) == '$') n = n.substring(1);
Type t = (Type) skolems.get(i + 1);
Relation r = (Relation) skolems.get(i + 2);
frame.addSkolem(un.make("$" + n), t, r);
}
return;
}
for (PrimSig c : s.children()) rename(frame, c, nexts, un);
String signame = un.make(s.label.startsWith("this/") ? s.label.substring(5) : s.label);
List<Tuple> list = new ArrayList<Tuple>();
for (Tuple t : frame.eval.evaluate(frame.a2k(s))) list.add(t);
List<Tuple> order = nexts.get(s);
if (order != null && order.size() == list.size() && order.containsAll(list)) {
list = order;
}
int i = 0;
for (Tuple t : list) {
if (frame.atom2sig.containsKey(t.atom(0)))
// This means one of the subsig has already claimed
continue;
// this atom.
String x = signame + "$" + i;
i++;
frame.atom2sig.put(t.atom(0), s);
frame.atom2name.put(t.atom(0), x);
ExprVar v = ExprVar.make(null, x, s.type());
TupleSet ts = t.universe().factory().range(t, t);
Relation r = Relation.unary(x);
frame.eval.instance().add(r, ts);
frame.a2k.put(v, r);
frame.atoms.add(v);
}
}
use of edu.mit.csail.sdg.ast.Sig.Field in project org.alloytools.alloy by AlloyTools.
the class CompModule method resolveMeta.
// ============================================================================================================================//
private static void resolveMeta(final CompModule root) throws Err {
// Now, add the meta sigs and fields if needed
Map<Sig, PrimSig> sig2meta = new LinkedHashMap<Sig, PrimSig>();
Map<Field, PrimSig> field2meta = new LinkedHashMap<Field, PrimSig>();
boolean hasMetaSig = false, hasMetaField = false;
root.new2old.put(root.metaSig, root.metaSig);
root.sigs.put(base(root.metaSig), root.metaSig);
root.new2old.put(root.metaField, root.metaField);
root.sigs.put(base(root.metaField), root.metaField);
for (CompModule m : root.allModules) for (Sig s : new ArrayList<Sig>(m.sigs.values())) if (m != root || (s != root.metaSig && s != root.metaField)) {
PrimSig ka = new PrimSig(s.label + "$", root.metaSig, Attr.ONE, PRIVATE.makenull(s.isPrivate), Attr.META);
sig2meta.put(s, ka);
ka.addDefinedField(Pos.UNKNOWN, null, Pos.UNKNOWN, "value", s);
m.new2old.put(ka, ka);
m.sigs.put(base(ka), ka);
hasMetaSig = true;
Expr allfields = ExprConstant.EMPTYNESS;
for (Field field : s.getFields()) {
Pos priv = field.isPrivate;
if (priv == null)
priv = s.isPrivate;
PrimSig kb = new PrimSig(s.label + "$" + field.label, root.metaField, Attr.ONE, PRIVATE.makenull(priv), Attr.META);
field2meta.put(field, kb);
m.new2old.put(kb, kb);
m.sigs.put(base(kb), kb);
hasMetaField = true;
kb.addDefinedField(Pos.UNKNOWN, null, Pos.UNKNOWN, "value", field);
if (allfields == ExprConstant.EMPTYNESS)
allfields = kb;
else
allfields = allfields.plus(kb);
}
ka.addDefinedField(Pos.UNKNOWN, null, Pos.UNKNOWN, "fields", allfields);
}
for (Map.Entry<Sig, PrimSig> e : sig2meta.entrySet()) {
Expr expr = null;
if ((e.getKey()) instanceof PrimSig) {
PrimSig a = (PrimSig) (e.getKey());
if (a.parent != null && a.parent != UNIV)
expr = sig2meta.get(a.parent);
}
e.getValue().addDefinedField(Pos.UNKNOWN, null, Pos.UNKNOWN, "parent", (expr == null ? ExprConstant.EMPTYNESS : expr));
}
for (Map.Entry<Sig, PrimSig> e : sig2meta.entrySet()) {
Sig s = e.getKey();
PrimSig s2 = e.getValue();
Expr allfields = ExprConstant.EMPTYNESS;
for (Field f : s.getFields()) {
PrimSig metaF = field2meta.get(f);
if (allfields == ExprConstant.EMPTYNESS)
allfields = metaF;
else
allfields = allfields.plus(metaF);
}
if (s instanceof PrimSig)
for (Sig c : (((PrimSig) s).descendents())) for (Field f : c.getFields()) {
PrimSig metaF = field2meta.get(f);
if (allfields == ExprConstant.EMPTYNESS)
allfields = metaF;
else
allfields = allfields.plus(metaF);
}
s2.addDefinedField(Pos.UNKNOWN, null, Pos.UNKNOWN, "subfields", allfields);
}
if (hasMetaSig == false)
root.facts.add(new Pair<String, Expr>("sig$fact", root.metaSig.no().and(root.metaField.no())));
else if (hasMetaField == false)
root.facts.add(new Pair<String, Expr>("sig$fact", root.metaField.no()));
}
use of edu.mit.csail.sdg.ast.Sig.Field in project org.alloytools.alloy by AlloyTools.
the class CompModule method resolveFieldDecl.
// ============================================================================================================================//
private static void resolveFieldDecl(CompModule res, final A4Reporter rep, final Sig s, final List<ErrorWarning> warns, boolean defined) throws Err {
// When typechecking each field:
// * it is allowed to refer to earlier fields in the same SIG or in any
// visible ancestor sig
// * it is allowed to refer to visible sigs
// * it is NOT allowed to refer to any predicate or function
// For example, if A.als opens B.als, and B/SIGX extends A/SIGY,
// then B/SIGX's fields cannot refer to A/SIGY, nor any fields in
// A/SIGY)
final List<Decl> oldDecls = res.old2fields.get(res.new2old.get(s));
if (oldDecls == null)
return;
final CompModule m = res.sig2module.get(s);
final Context cx = new Context(m, warns);
final ExprHasName dup = Decl.findDuplicateName(oldDecls);
if (dup != null)
throw new ErrorSyntax(dup.span(), "sig \"" + s + "\" cannot have 2 fields named \"" + dup.label + "\"");
for (final Decl d : oldDecls) {
if (d.expr.mult() != ExprUnary.Op.EXACTLYOF) {
if (defined)
continue;
} else {
if (!defined)
continue;
}
// The name "this" does matter, since the parser and the typechecker
// both refer to it as "this"
cx.rootfield = d;
cx.rootsig = s;
cx.put("this", s.decl.get());
Expr bound = cx.check(d.expr).resolve_as_set(warns);
cx.remove("this");
String[] names = new String[d.names.size()];
for (int i = 0; i < names.length; i++) names[i] = d.names.get(i).label;
Field[] fields = s.addTrickyField(d.span(), d.isPrivate, d.disjoint, d.disjoint2, null, names, bound);
for (Field f : fields) {
rep.typecheck("Sig " + s + ", Field " + f.label + ": " + f.type() + "\n");
}
}
}
use of edu.mit.csail.sdg.ast.Sig.Field in project org.alloytools.alloy by AlloyTools.
the class BoundsComputer method sim.
// ==============================================================================================================//
/**
* If ex is a simple combination of Relations, then return that combination,
* else return null.
*/
private Expression sim(Expr ex) {
while (ex instanceof ExprUnary) {
ExprUnary u = (ExprUnary) ex;
if (u.op != ExprUnary.Op.NOOP && u.op != ExprUnary.Op.EXACTLYOF)
break;
ex = u.sub;
}
if (ex instanceof ExprBinary) {
ExprBinary b = (ExprBinary) ex;
if (b.op == ExprBinary.Op.ARROW || b.op == ExprBinary.Op.PLUS || b.op == ExprBinary.Op.JOIN) {
Expression left = sim(b.left);
if (left == null)
return null;
Expression right = sim(b.right);
if (right == null)
return null;
if (b.op == ExprBinary.Op.ARROW)
return left.product(right);
if (b.op == ExprBinary.Op.PLUS)
return left.union(right);
else
return left.join(right);
}
}
if (ex instanceof ExprConstant) {
switch(((ExprConstant) ex).op) {
case EMPTYNESS:
return Expression.NONE;
}
}
if (ex == Sig.NONE)
return Expression.NONE;
if (ex == Sig.SIGINT)
return Expression.INTS;
if (ex instanceof Sig)
return sol.a2k((Sig) ex);
if (ex instanceof Field)
return sol.a2k((Field) ex);
return null;
}
Aggregations