Skip to content

Commit dd4ea36

Browse files
committed
support both upper and exact record sig scopes
1 parent c8492e1 commit dd4ea36

File tree

4 files changed

+133
-66
lines changed

4 files changed

+133
-66
lines changed

org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/A4Solution.java

+11
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import edu.mit.csail.sdg.translator.A4Options.SatSolver;
7474
import kodkod.ast.BinaryExpression;
7575
import kodkod.ast.BinaryFormula;
76+
import kodkod.ast.ConstantExpression;
7677
import kodkod.ast.Decl;
7778
import kodkod.ast.Expression;
7879
import kodkod.ast.Formula;
@@ -2088,6 +2089,16 @@ public Expression visit(Relation rel) {
20882089
else
20892090
return rel;
20902091
}
2092+
2093+
@Override
2094+
public Expression visit(BinaryExpression bexp) {
2095+
if (bexp.left().equals(a2k) && bexp.right().equals(ConstantExpression.UNIV) && bexp.op().equals(ExprOperator.JOIN))
2096+
return a2k.join(((BinaryExpression) ((BinaryExpression) fldDom).right()).right().union(A4Solution.KK_DUMMY));
2097+
else
2098+
return super.visit(bexp);
2099+
}
2100+
2101+
20912102
};
20922103
for (Expr exp : this.a2k.keySet())
20932104
this.a2k.put(exp, this.a2k.get(exp).accept(replacer));

org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/BoundsComputer.java

+24-15
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,14 @@ private void computeUpperBound(PrimSig sig) throws Err {
144144
// potentionally get any of the atom from X.
145145
for (PrimSig c : sig.children()) {
146146
if (sc.sig2scope(c) > lb.get(c).size())
147-
ub.get(c).addAll(x);
147+
if (c.isRecord == null || TranslateAlloyToKodkod.EXACT_REC_BOUNDS)
148+
ub.get(c).addAll(x);
149+
else {
150+
Iterator<Tuple> it = ub.get(sig).iterator();
151+
while (sc.sig2scope(c) > ub.get(c).size())
152+
ub.get(c).add(it.next());
153+
ub.get(sig).removeAll(ub.get(c));
154+
}
148155
computeUpperBound(c);
149156
}
150157
}
@@ -491,7 +498,7 @@ private BoundsComputer(A4Reporter rep, A4Solution sol, ScopeComputer sc, Iterabl
491498
ub.add(sigTuple.product(factory.tuple(typeTupleSet_it.next().get(ctr))));
492499
Relation r = (Relation) sol.a2k(lbl);
493500
if (r == null) {
494-
r = sol.addRel(s.label + "." + lbl.label, ub, ub, true);
501+
r = sol.addRel(((Field) lbl).sig.label + "." + lbl.label, ub, ub, true);
495502
sol.addField((Field) lbl, r);
496503
} else
497504
sol.updRel(r, ub, ub);
@@ -501,20 +508,22 @@ private BoundsComputer(A4Reporter rep, A4Solution sol, ScopeComputer sc, Iterabl
501508
}
502509
}
503510

504-
for (Sig s : sigs) {
505-
if (s.isRecord != null) {
506-
List<Decl> anc_fields = getAllFields((PrimSig) s);
507-
Expression rel = sol.a2k(s);
508-
if (rel instanceof BinaryExpression)
509-
rel = ((BinaryExpression) rel).right();
510-
Expression fldDom = rel;
511-
for (Decl dcl : anc_fields) {
512-
for (ExprHasName lbl : dcl.names) {
513-
Relation r = (Relation) sol.a2k(lbl);
514-
fldDom = fldDom.intersection(r.join(ConstantExpression.UNIV));
511+
if (TranslateAlloyToKodkod.EXACT_REC_BOUNDS) {
512+
for (Sig s : sigs) {
513+
if (s.isRecord != null) {
514+
List<Decl> anc_fields = getAllFields((PrimSig) s);
515+
Expression rel = sol.a2k(s);
516+
if (rel instanceof BinaryExpression)
517+
rel = ((BinaryExpression) rel).right();
518+
Expression fldDom = rel;
519+
for (Decl dcl : anc_fields) {
520+
for (ExprHasName lbl : dcl.names) {
521+
Relation r = (Relation) sol.a2k(lbl);
522+
fldDom = fldDom.intersection(r.join(ConstantExpression.UNIV));
523+
}
515524
}
525+
sol.updateA2K(rel, fldDom);
516526
}
517-
sol.updateA2K(rel, fldDom);
518527
}
519528
}
520529

@@ -530,7 +539,7 @@ private BoundsComputer(A4Reporter rep, A4Solution sol, ScopeComputer sc, Iterabl
530539

531540
// Add any additional SIZE constraints
532541
for (Sig s : sigs)
533-
if (!s.builtin && s.isRecord == null) {
542+
if (!s.builtin && (s.isRecord == null && TranslateAlloyToKodkod.EXACT_REC_BOUNDS)) {
534543
Expression exp = sol.a2k(s);
535544
TupleSet upper = sol.query(true, exp, false), lower = sol.query(false, exp, false);
536545
final int n = sc.sig2scope(s);

org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/ScopeComputer.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,8 @@ private boolean derive_record_scope(Iterable<Sig> sigs) throws Err {
357357
cscp += n;
358358
}
359359
if (allfound) {
360-
makeExact(null, s);
360+
if (TranslateAlloyToKodkod.EXACT_REC_BOUNDS)
361+
makeExact(null, s);
361362
sig2scope(s, cscp);
362363
changed = true;
363364
} else {

org.alloytools.alloy.core/src/main/java/edu/mit/csail/sdg/translator/TranslateAlloyToKodkod.java

+96-50
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
import edu.mit.csail.sdg.ast.Type;
5959
import edu.mit.csail.sdg.ast.VisitReturn;
6060
import kodkod.ast.BinaryExpression;
61-
import kodkod.ast.ConstantExpression;
6261
import kodkod.ast.Decls;
6362
import kodkod.ast.ExprToIntCast;
6463
import kodkod.ast.Expression;
@@ -90,6 +89,8 @@
9089

9190
public final class TranslateAlloyToKodkod extends VisitReturn<Object> {
9291

92+
static public final boolean EXACT_REC_BOUNDS = false;
93+
9394
static int cnt = 0;
9495

9596
/**
@@ -258,66 +259,111 @@ private void makeFacts(Expr facts) throws Err {
258259
facts = (new ConvToConjunction()).visitThis(facts);
259260
// add the field facts and appended facts
260261
for (Sig s : frame.getAllReachableSigs()) {
261-
for (Decl d : s.getFieldDecls()) {
262-
k2pos_enabled = false;
263-
for (ExprHasName n : d.names) {
264-
Field f = (Field) n;
265-
Expr rhs;
266-
if (s.isRecord == null)
267-
rhs = d.expr;
268-
else {
269-
rhs = ((ExprUnary) d.expr.deNOP()).sub;
270-
if (((ExprUnary) d.expr.deNOP()).op == Op.LONEOF)
271-
rhs = rhs.plus(A4Solution.dummyS);
272-
frame.updateA2K(a2k(f), a2k(f).intersection(ConstantExpression.UNIV.product(cset(rhs))));
273-
}
274-
Expr form = s.decl.get().join(f).in(rhs);
275-
form = s.isOne == null ? form.forAll(s.decl) : ExprLet.make(null, (ExprVar) (s.decl.get()), s, form);
276-
Formula ff = cform(form);
277-
if (TemporalTranslator.isTemporal(ff))
278-
ff = ff.always();
279-
frame.addFormula(ff, f);
280-
// Given the above, we can be sure that every column is
281-
// well-bounded (except possibly the first column).
282-
// Thus, we need to add a bound that the first column is a
283-
// subset of s.
284-
// [electrum] mutable singletons sigs cannot be simplified
285-
if ((s.isOne == null || s.isVariable != null) && s.isRecord == null) {
286-
Expression sr = a2k(s), fr = a2k(f);
287-
for (int i = f.type().arity(); i > 1; i--)
288-
fr = fr.join(Expression.UNIV);
289-
ff = fr.in(sr);
262+
if (s.isRecord == null || !EXACT_REC_BOUNDS) {
263+
for (Decl d : s.getFieldDecls()) {
264+
k2pos_enabled = false;
265+
for (ExprHasName n : d.names) {
266+
Field f = (Field) n;
267+
Expr rhs;
268+
if (s.isRecord == null)
269+
rhs = d.expr;
270+
else {
271+
rhs = ((ExprUnary) d.expr.deNOP()).sub;
272+
if (((ExprUnary) d.expr.deNOP()).op == Op.LONEOF)
273+
rhs = rhs.plus(A4Solution.dummyS);
274+
}
275+
Expr form = s.decl.get().join(f).in(rhs);
276+
form = s.isOne == null ? form.forAll(s.decl) : ExprLet.make(null, (ExprVar) (s.decl.get()), s, form);
277+
Formula ff = cform(form);
290278
if (TemporalTranslator.isTemporal(ff))
291279
ff = ff.always();
292280
frame.addFormula(ff, f);
281+
// Given the above, we can be sure that every column is
282+
// well-bounded (except possibly the first column).
283+
// Thus, we need to add a bound that the first column is a
284+
// subset of s.
285+
// [electrum] mutable singletons sigs cannot be simplified
286+
if ((s.isOne == null || s.isVariable != null) && s.isRecord == null) {
287+
Expression sr = a2k(s), fr = a2k(f);
288+
for (int i = f.type().arity(); i > 1; i--)
289+
fr = fr.join(Expression.UNIV);
290+
ff = fr.in(sr);
291+
if (TemporalTranslator.isTemporal(ff))
292+
ff = ff.always();
293+
frame.addFormula(ff, f);
294+
}
293295
}
294-
}
295-
if (s.isOne == null && d.disjoint2 != null)
296-
for (ExprHasName f : d.names) {
297-
Decl that = s.oneOf("that");
298-
Expr formula = s.decl.get().equal(that.get()).not().implies(s.decl.get().join(f).intersect(that.get().join(f)).no());
299-
Formula ff = cform(formula.forAll(that).forAll(s.decl));
296+
if (s.isOne == null && d.disjoint2 != null)
297+
for (ExprHasName f : d.names) {
298+
Decl that = s.oneOf("that");
299+
Expr formula = s.decl.get().equal(that.get()).not().implies(s.decl.get().join(f).intersect(that.get().join(f)).no());
300+
Formula ff = cform(formula.forAll(that).forAll(s.decl));
301+
if (d.isVar != null)
302+
ff = ff.always();
303+
frame.addFormula(ff, d.disjoint2);
304+
}
305+
if (d.names.size() > 1 && d.disjoint != null) {
306+
Formula ff = cform(ExprList.makeDISJOINT(d.disjoint, null, d.names));
300307
if (d.isVar != null)
301308
ff = ff.always();
302-
frame.addFormula(ff, d.disjoint2);
309+
frame.addFormula(ff, d.disjoint);
310+
}
311+
k2pos_enabled = true;
312+
for (Expr f : s.getFacts()) {
313+
Expr form = s.isOne == null ? f.forAll(s.decl) : ExprLet.make(null, (ExprVar) (s.decl.get()), s, f);
314+
Formula kdorm = cform(form);
315+
// [electrum] avoid "always" over statics (not only efficiency, total orders would not by detected in SB)
316+
if (TemporalTranslator.isTemporal(kdorm))
317+
kdorm = kdorm.always();
318+
frame.addFormula(kdorm, f);
303319
}
304-
if (d.names.size() > 1 && d.disjoint != null) {
305-
Formula ff = cform(ExprList.makeDISJOINT(d.disjoint, null, d.names));
306-
if (d.isVar != null)
307-
ff = ff.always();
308-
frame.addFormula(ff, d.disjoint);
309320
}
310321
}
311-
k2pos_enabled = true;
312-
for (Expr f : s.getFacts()) {
313-
Expr form = s.isOne == null ? f.forAll(s.decl) : ExprLet.make(null, (ExprVar) (s.decl.get()), s, f);
314-
Formula kdorm = cform(form);
315-
// [electrum] avoid "always" over statics (not only efficiency, total orders would not by detected in SB)
316-
if (TemporalTranslator.isTemporal(kdorm))
317-
kdorm = kdorm.always();
318-
frame.addFormula(kdorm, f);
322+
}
323+
for (Sig s : frame.getAllReachableSigs()) {
324+
if (s.isRecord != null && s.isAbstract == null && !EXACT_REC_BOUNDS) {
325+
326+
Decls ds = null;
327+
Formula body = Formula.TRUE;
328+
329+
List<Decl> anc_fields = getAllFields((PrimSig) s);
330+
if (anc_fields.isEmpty()) {
331+
frame.addFormula(a2k(s).one().always(), s.pos);
332+
} else {
333+
Variable rv = Variable.unary("r");
334+
for (int i = 0; i < anc_fields.size(); i++) {
335+
ExprUnary ft = (ExprUnary) anc_fields.get(i).expr;
336+
Expression tp = cset(ft.sub);
337+
if (ft.op == Op.LONEOF)
338+
tp = tp.union(A4Solution.KK_DUMMY);
339+
for (ExprHasName lbl : anc_fields.get(i).names) {
340+
Variable v = Variable.unary("v" + i);
341+
ds = ds == null ? v.oneOf(tp) : ds.and(v.oneOf(tp));
342+
body = body.and(rv.join(a2k((Field) lbl)).eq(v));
343+
}
344+
}
345+
346+
Expression sum = Expression.NONE;
347+
for (Sig cs : ((PrimSig) s).children())
348+
sum = sum.union(a2k(cs));
349+
350+
frame.addFormula(body.forSome(rv.oneOf(a2k(s).difference(sum))).forAll(ds).always(), s.pos);
351+
352+
}
319353
}
320354
}
355+
for (Sig s : frame.getAllReachableSigs()) {
356+
if (s.isRecord != null)
357+
for (Decl d : s.getFieldDecls()) {
358+
for (ExprHasName n : d.names) {
359+
Field f = (Field) n;
360+
Expr rhs = ((ExprUnary) d.expr.deNOP()).sub;
361+
// if (((ExprUnary) d.expr.deNOP()).op == Op.LONEOF)
362+
// rhs = rhs.plus(A4Solution.dummyS);
363+
frame.updateA2K(a2k(f), a2k(f).intersection(a2k(s).product(cset(rhs))));
364+
}
365+
}
366+
}
321367
k2pos_enabled = true;
322368
recursiveAddFormula(facts);
323369
}

0 commit comments

Comments
 (0)