/* * Kodkod -- Copyright (c) 2005-present, Emina Torlak * * 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 kodkod.examples.csp; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import kodkod.ast.Expression; import kodkod.ast.Formula; import kodkod.ast.IntConstant; import kodkod.ast.IntExpression; import kodkod.ast.Relation; import kodkod.ast.Variable; import kodkod.engine.Evaluator; import kodkod.engine.Solution; import kodkod.engine.Solver; import kodkod.engine.config.ConsoleReporter; import kodkod.engine.config.Options; import kodkod.engine.satlab.SATFactory; import kodkod.instance.Bounds; import kodkod.instance.Instance; import kodkod.instance.TupleFactory; import kodkod.instance.TupleSet; import kodkod.instance.Universe; import kodkod.util.nodes.PrettyPrinter; /** * Relational Kodkod encoding of the BlockedNQueensProblem. * The files should be supplied in the same format as those * at http://asparagus.cs.uni-potsdam.de/?action=instances&id=15 * @author Emina Torlak */ public final class BlockedNQueens2 { private final Relation queen, num, ord; private final String file; /** * Constructs an instance of BlockedNQueens from the file * with the given name. */ public BlockedNQueens2(final String file) { this.file = file; this.queen = Relation.binary("Queen"); this.num = Relation.unary("num"); this.ord = Relation.binary("ord"); } /** * Returns a relational encoding of the problem. * @return a relational encoding of the problem. */ public Formula rules() { final List<Formula> rules = new ArrayList<Formula>(); final Variable x = Variable.unary("x"), y = Variable.unary("y"); // one queen in each row rules.add( x.join(queen).one().forAll(x.oneOf(num)) ); // one queen in each column rules.add( queen.join(y).one().forAll(y.oneOf(num)) ); // one queen on each diagonal final Variable x2 = Variable.unary("p"); final Expression ords = ord.closure(); final Expression y1 = x.join(queen), y2 = x2.join(queen); final IntExpression xdiff = x.sum().minus(x2.sum()).abs(); final IntExpression ydiff = y1.sum().minus(y2.sum()).abs(); rules.add( xdiff.eq(ydiff).not().forAll(x.oneOf(num).and(x2.oneOf(ords.join(x)))) ); return Formula.and(rules); } /** * Returns the bounds for relational encoding of the problem based on the input file. * @return the bounds for relational encoding of the problem based on the input file. */ public Bounds bounds() { try(BufferedReader reader = new BufferedReader(new FileReader(new File(file)))) { final Pattern np = Pattern.compile("num\\((\\d+)\\)\\."); final Pattern bp = Pattern.compile("block\\((\\d+),\\s*(\\d+)\\)\\."); String line = ""; final Matcher m = np.matcher(line); int n = 0; for(line = reader.readLine(); line != null && m.reset(line).matches(); line = reader.readLine()) { n++; if (Integer.parseInt(m.group(1))!=n) throw new IOException(); } if (n==0) throw new IOException(); final List<Object> atoms = new ArrayList<Object>(n); for(int i =0; i < n; i++) { atoms.add(Integer.valueOf(i)); } final Universe u = new Universe(atoms); final Bounds b = new Bounds(u); final TupleFactory f = u.factory(); b.boundExactly(num, f.allOf(1)); final TupleSet obound = f.noneOf(2); for(int i = 1; i < n; i++) { obound.add(f.tuple((Object)Integer.valueOf(i-1), Integer.valueOf(i))); } b.boundExactly(ord, obound); for(int i = 0; i < n; i++) { b.boundExactly(i, f.setOf(Integer.valueOf(i))); } // extract the partial instance for the grid final TupleSet qbound = f.noneOf(2); for(m.usePattern(bp); line != null && m.reset(line).matches(); line = reader.readLine()) { Integer i = Integer.parseInt(m.group(1))-1; Integer j = Integer.parseInt(m.group(2))-1; if (i < 0 || i >= n || j < 0 || j >= n) throw new IOException(); qbound.add(f.tuple((Object)i, j)); } if (line != null) throw new IOException(); b.bound(queen, qbound); return b; } catch (FileNotFoundException e) { System.out.println("Could not find " + file); usage(); } catch (IOException e) { System.out.println("Badly formatted file: " + file); usage(); } catch (NumberFormatException e) { System.out.println("Badly formatted file: " + file); usage(); } return null; } /** * Prints the given solution using the given options to the console */ void print(Instance instance, Options options) { final Evaluator eval = new Evaluator(instance, options); final int n = instance.universe().size(); for(int i = 0; i < n; i++) { Expression x = IntConstant.constant(i).toExpression(); for(int j = 0; j < n; j++) { Expression y = IntConstant.constant(j).toExpression(); if (eval.evaluate(x.product(y).in(queen))) { System.out.print(" Q"); } else { System.out.print(" ."); } } System.out.println(); } // System.out.println(instance); } private static void usage() { System.out.println("Usage: java BlockedNQueens <file name>"); System.exit(1); } /** * Usage: java BlockedNQueens <file name> */ public static void main(String[] args) { if (args.length < 1) usage(); try { final BlockedNQueens2 model = new BlockedNQueens2(args[0]); final Formula f = model.rules(); final Bounds b = model.bounds(); final Solver s = new Solver(); System.out.println(b); System.out.println(PrettyPrinter.print(f, 1)); s.options().setSolver(SATFactory.MiniSat); s.options().setBitwidth(33 - Integer.numberOfLeadingZeros(b.universe().size())); s.options().setReporter(new ConsoleReporter()); final Solution sol = s.solve(f, b); if (sol.instance()!=null) { System.out.println("solution:"); model.print(sol.instance(), s.options()); } else { System.out.println("no solution"); } System.out.println(sol.stats()); } catch (NumberFormatException nfe) { usage(); } } }