/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files * (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package edu.mit.csail.sdg.alloy4whole; import static edu.mit.csail.sdg.alloy4.A4Reporter.NOP; import java.util.LinkedHashSet; import java.util.Set; import edu.mit.csail.sdg.alloy4.Err; import edu.mit.csail.sdg.alloy4compiler.ast.Attr; import edu.mit.csail.sdg.alloy4compiler.ast.Command; import edu.mit.csail.sdg.alloy4compiler.ast.Decl; import edu.mit.csail.sdg.alloy4compiler.ast.Expr; import edu.mit.csail.sdg.alloy4compiler.ast.ExprConstant; import edu.mit.csail.sdg.alloy4compiler.ast.ExprHasName; import edu.mit.csail.sdg.alloy4compiler.ast.Sig; import edu.mit.csail.sdg.alloy4compiler.ast.Sig.Field; import edu.mit.csail.sdg.alloy4compiler.ast.Sig.PrimSig; import edu.mit.csail.sdg.alloy4compiler.translator.A4Options; import edu.mit.csail.sdg.alloy4compiler.translator.A4Solution; import edu.mit.csail.sdg.alloy4compiler.translator.TranslateAlloyToKodkod; /** This class demonstrates how to access Alloy4 via the API, by modeling a simple file system. */ public class DemoFileSystem { /* Helper methods to simplify using the API for this example. */ Set<Sig> sigs = new LinkedHashSet<Sig>(); PrimSig makeSig(String name, boolean isAbstract, boolean isOne) throws Err { PrimSig ans = new PrimSig(name, (isAbstract ? Attr.ABSTRACT : null), (isOne ? Attr.ONE : null)); sigs.add(ans); return ans; } PrimSig makeSig(PrimSig parent, String name, boolean isAbstract, boolean isOne) throws Err { PrimSig ans = new PrimSig(name, parent, (isAbstract ? Attr.ABSTRACT : null), (isOne ? Attr.ONE : null)); sigs.add(ans); return ans; } void runFor3(Expr expr) throws Err { A4Options opt = new A4Options(); Command cmd = new Command(false, 3, 3, 3, expr.and(fact)); A4Solution sol = TranslateAlloyToKodkod.execute_command(NOP, sigs, cmd, opt); System.out.println(sol.toString().trim()); if (sol.satisfiable()) { System.out.println("In particular, File = " + sol.eval(file)); System.out.println("In particular, Dir = " + sol.eval(dir)); System.out.println("In particular, contains = " + sol.eval(contains)); System.out.println("In particular, parent = " + sol.eval(parent)); } System.out.println(); } /* These corresponds to the helper predicates/functions provided in util/*.als */ static Expr acyclic(Expr r) throws Err { Decl d = r.join(Sig.UNIV).oneOf("x"); // x is a variable over the domain of r ExprHasName x = d.get(); return x.in(x.join(r.closure())).not().forAll(d); // (x !in x.^r) for all x } /* Here are definitions common to all instances. */ PrimSig obj=null, dir=null, file=null, root=null; Field parent=null, contains=null; Expr fact=ExprConstant.TRUE; void makeDomain() throws Err { // abstract sig Obj { parent: lone Dir } // abstract sig Dir extends Obj { contains: set Obj } // abstract sig File extends Obj { } // one sig Root extends Dir { } obj = makeSig("Obj", true, false); dir = makeSig(obj, "Dir", true, false); file = makeSig(obj, "File", true, false); root = makeSig(dir, "Root", false, true); parent = obj.addField("parent", dir.loneOf()); contains = dir.addField("contains", obj.setOf()); // fact { all x:Obj-Root | one x.parent } Decl x = obj.minus(root).oneOf("x"); fact = x.get().join(parent).one().forAll(x).and(fact); // fact { contains = ~ parent } fact = contains.equal(parent.transpose()).and(fact); // fact { acyclic[contains] } fact = acyclic(contains).and(fact); } /* Here is instance number 1. */ void makeInstance1() throws Err { // file = F1, F2, F3 // dir = Root, D1, D2 // F1.parent = D1 // F2.parent = D2 // F3.parent = D2 // D2.parent = D1 // D1.parent = Root PrimSig file1 = makeSig(file, "F1", false, true); PrimSig file2 = makeSig(file, "F2", false, true); PrimSig file3 = makeSig(file, "F3", false, true); PrimSig dir1 = makeSig(dir, "D1", false, true); PrimSig dir2 = makeSig(dir, "D2", false, true); fact = file1.join(parent).equal(dir1).and(fact); fact = file2.join(parent).equal(dir2).and(fact); fact = file3.join(parent).equal(dir2).and(fact); fact = dir2.join(parent).equal(dir1).and(fact); fact = dir1.join(parent).equal(root).and(fact); } /* Here is instance number 2. */ void makeInstance2() throws Err { // dir = Root, D1, D2 // D2.parent = D1 // D1.parent = D2 PrimSig dir1 = makeSig(dir, "D1", false, true); PrimSig dir2 = makeSig(dir, "D2", false, true); fact = dir2.join(parent).equal(dir1).and(fact); fact = dir1.join(parent).equal(dir2).and(fact); } private DemoFileSystem() { } /* The main driver. */ public static void main(String[] args) throws Err { DemoFileSystem x; x = new DemoFileSystem(); x.makeDomain(); x.makeInstance1(); x.runFor3(x.file.some()); // run { some file } x = new DemoFileSystem(); x.makeDomain(); x.makeInstance1(); x.runFor3(acyclic(x.contains).not()); // run { !acyclic[contains] } } }