|
58 | 58 | import edu.mit.csail.sdg.ast.Type;
|
59 | 59 | import edu.mit.csail.sdg.ast.VisitReturn;
|
60 | 60 | import kodkod.ast.BinaryExpression;
|
61 |
| -import kodkod.ast.ConstantExpression; |
62 | 61 | import kodkod.ast.Decls;
|
63 | 62 | import kodkod.ast.ExprToIntCast;
|
64 | 63 | import kodkod.ast.Expression;
|
|
90 | 89 |
|
91 | 90 | public final class TranslateAlloyToKodkod extends VisitReturn<Object> {
|
92 | 91 |
|
| 92 | + static public final boolean EXACT_REC_BOUNDS = false; |
| 93 | + |
93 | 94 | static int cnt = 0;
|
94 | 95 |
|
95 | 96 | /**
|
@@ -258,66 +259,111 @@ private void makeFacts(Expr facts) throws Err {
|
258 | 259 | facts = (new ConvToConjunction()).visitThis(facts);
|
259 | 260 | // add the field facts and appended facts
|
260 | 261 | 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); |
290 | 278 | if (TemporalTranslator.isTemporal(ff))
|
291 | 279 | ff = ff.always();
|
292 | 280 | 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 | + } |
293 | 295 | }
|
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)); |
300 | 307 | if (d.isVar != null)
|
301 | 308 | 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); |
303 | 319 | }
|
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); |
309 | 320 | }
|
310 | 321 | }
|
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 | + } |
319 | 353 | }
|
320 | 354 | }
|
| 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 | + } |
321 | 367 | k2pos_enabled = true;
|
322 | 368 | recursiveAddFormula(facts);
|
323 | 369 | }
|
|
0 commit comments