All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sosy_lab.java_smt.example.NQueens Maven / Gradle / Ivy

The newest version!
// This file is part of JavaSMT,
// an API wrapper for a collection of SMT solvers:
// https://github.com/sosy-lab/java-smt
//
// SPDX-FileCopyrightText: 2020 Dirk Beyer 
//
// SPDX-License-Identifier: Unlicense OR Apache-2.0 OR MIT

package org.sosy_lab.java_smt.example;

import com.google.common.collect.ImmutableList;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Scanner;
import java.util.logging.Level;
import org.sosy_lab.common.ShutdownNotifier;
import org.sosy_lab.common.configuration.Configuration;
import org.sosy_lab.common.configuration.InvalidConfigurationException;
import org.sosy_lab.common.log.BasicLogManager;
import org.sosy_lab.common.log.LogManager;
import org.sosy_lab.java_smt.SolverContextFactory;
import org.sosy_lab.java_smt.SolverContextFactory.Solvers;
import org.sosy_lab.java_smt.api.BooleanFormula;
import org.sosy_lab.java_smt.api.BooleanFormulaManager;
import org.sosy_lab.java_smt.api.Model;
import org.sosy_lab.java_smt.api.ProverEnvironment;
import org.sosy_lab.java_smt.api.SolverContext;
import org.sosy_lab.java_smt.api.SolverContext.ProverOptions;
import org.sosy_lab.java_smt.api.SolverException;

/**
 * This example program solves a NQueens problem of given size and prints a possible solution.
 *
 * 

For example, the Queen can be placed in these ways for a field size of 4: * *

 *   .Q..
 *   ...Q
 *   Q...
 *   ..Q.
 * 
*/ public final class NQueens { private final SolverContext context; private final BooleanFormulaManager bmgr; private final int n; private NQueens(SolverContext pContext, int n) { context = pContext; bmgr = context.getFormulaManager().getBooleanFormulaManager(); this.n = n; } public static void main(String... args) throws InvalidConfigurationException, SolverException, InterruptedException { Configuration config = Configuration.defaultConfiguration(); LogManager logger = BasicLogManager.create(config); ShutdownNotifier notifier = ShutdownNotifier.createDummy(); Solvers solver = Solvers.SMTINTERPOL; try (SolverContext context = SolverContextFactory.createSolverContext(config, logger, notifier, solver)) { try (Scanner sc = new Scanner(System.in, Charset.defaultCharset())) { // Takes input from the user for number of queens to be placed System.out.println("Enter the number of Queens to be " + "placed on the board:"); int n = sc.nextInt(); NQueens myQueen = new NQueens(context, n); Optional solutions = myQueen.solve(); if (solutions.isEmpty()) { System.out.println("No solutions found."); } else { System.out.println("Solution:"); for (boolean[] row : solutions.orElseThrow()) { for (boolean col : row) { System.out.print(col ? "Q " : "_ "); } System.out.println(); } System.out.println(); } } } catch (InvalidConfigurationException | UnsatisfiedLinkError e) { logger.logUserException(Level.INFO, e, "Solver " + solver + " is not available."); } catch (UnsupportedOperationException e) { logger.logUserException(Level.INFO, e, e.getMessage()); } } /** * Creates a 2D array of BooleanFormula objects to represent the variables for each cell in a grid * of size N x N. * * @return a 2D array of BooleanFormula objects, where each BooleanFormula object represents a * variable for a cell in the grid. */ private BooleanFormula[][] getSymbols() { final BooleanFormula[][] symbols = new BooleanFormula[n][n]; for (int row = 0; row < n; row++) { for (int col = 0; col < n; col++) { symbols[row][col] = bmgr.makeVariable("q_" + row + "_" + col); } } return symbols; } /** * Rule 1: At least one queen per row, or we can say make sure that there are N Queens on the * board. * * @param symbols a 2D Boolean array representing the board. Each element is true if there is a * queen in that cell, false otherwise. * @return a List of BooleanFormulas representing the rules for this constraint. */ private List rowRule1(BooleanFormula[][] symbols) { final List rules = new ArrayList<>(); for (BooleanFormula[] rowSymbols : symbols) { List clause = new ArrayList<>(); for (int i = 0; i < n; i++) { clause.add(rowSymbols[i]); } rules.add(bmgr.or(clause)); } return rules; } /** * Rule 2: Add constraints to ensure that at most one queen is placed in each row. For n=4: * *
   *   0123
   * 0 ----
   * 1 ----
   * 2 ----
   * 3 ----
   * 
* *

We add a negation of the conjunction of all possible pairs of variables in each row. * * @param symbols a 2D array of BooleanFormula objects representing the variables for each cell on * the board. * @return a list of BooleanFormula objects representing the constraints added by this rule. */ private List rowRule2(BooleanFormula[][] symbols) { final List rules = new ArrayList<>(); for (BooleanFormula[] rowSymbol : symbols) { for (int j1 = 0; j1 < n; j1++) { for (int j2 = j1 + 1; j2 < n; j2++) { rules.add(bmgr.not(bmgr.and(rowSymbol[j1], rowSymbol[j2]))); } } } return rules; } /** * Rule 3: Add constraints to ensure that at most one queen is placed in each column. For n=4: * *

   *   0123
   * 0 ||||
   * 1 ||||
   * 2 ||||
   * 3 ||||
   * 
* *

We add a negation of the conjunction of all possible pairs of variables in each column. * * @param symbols a 2D array of BooleanFormula representing the placement of queens on the * chessboard * @return a list of BooleanFormula objects representing the constraints added by this rule. */ private List columnRule(BooleanFormula[][] symbols) { final List rules = new ArrayList<>(); for (int j = 0; j < n; j++) { for (int i1 = 0; i1 < n; i1++) { for (int i2 = i1 + 1; i2 < n; i2++) { rules.add(bmgr.not(bmgr.and(symbols[i1][j], symbols[i2][j]))); } } } return rules; } /** * Rule 4: At most one queen per diagonal transform the field (=symbols) from square shape into a * (downwards/upwards directed) rhombus that is embedded in a rectangle * (=downwardDiagonal/upwardDiagonal). For example for N=4 from this square: * *

   *   0123
   * 0 xxxx
   * 1 xxxx
   * 2 xxxx
   * 3 xxxx
   * 
* *

to this rhombus/rectangle: * *

   *   0123
   * 0 x---
   * 1 xx--
   * 2 xxx-
   * 3 xxxx
   * 4 -xxx
   * 5 --xx
   * 6 ---x
   * 
* * @param symbols a two-dimensional array of Boolean formulas representing the chessboard * configuration * @return a list of BooleanFormula objects representing the constraints added by this rule. */ private List diagonalRule(BooleanFormula[][] symbols) { final List rules = new ArrayList<>(); int numDiagonals = 2 * n - 1; BooleanFormula[][] downwardDiagonal = new BooleanFormula[numDiagonals][n]; BooleanFormula[][] upwardDiagonal = new BooleanFormula[numDiagonals][n]; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { downwardDiagonal[i + j][i] = symbols[i][j]; upwardDiagonal[i - j + n - 1][i] = symbols[i][j]; } } for (int d = 0; d < numDiagonals; d++) { BooleanFormula[] diagonal1 = downwardDiagonal[d]; BooleanFormula[] diagonal2 = upwardDiagonal[d]; List downwardDiagonalQueen = new ArrayList<>(); List upwardDiagonalQueen = new ArrayList<>(); for (int i = 0; i < n; i++) { if (diagonal1[i] != null) { downwardDiagonalQueen.add(diagonal1[i]); } if (diagonal2[i] != null) { upwardDiagonalQueen.add(diagonal2[i]); } } for (int i = 0; i < downwardDiagonalQueen.size(); i++) { for (int j = i + 1; j < downwardDiagonalQueen.size(); j++) { rules.add(bmgr.not(bmgr.and(downwardDiagonalQueen.get(i), downwardDiagonalQueen.get(j)))); } } for (int i = 0; i < upwardDiagonalQueen.size(); i++) { for (int j = i + 1; j < upwardDiagonalQueen.size(); j++) { rules.add(bmgr.not(bmgr.and(upwardDiagonalQueen.get(i), upwardDiagonalQueen.get(j)))); } } } return rules; } /** * Returns a boolean value indicating whether a queen is placed on the cell corresponding to the * given row and column. * * @param symbols a 2D BooleanFormula array representing the cells of the chess board. * @param model the Model object representing the current state of the board. * @param row the row index of the cell to check. * @param col the column index of the cell to check. * @return true if a queen is placed on the cell, false otherwise. */ private boolean getValue(BooleanFormula[][] symbols, Model model, int row, int col) { return Boolean.TRUE.equals(model.evaluate(symbols[row][col])); } /** * Solves the N-Queens problem for the given board size and returns a possible solution. * * @return A two-dimensional array of booleans representing the solution. Returns {@code empty * object } if no solution exists. * @throws InterruptedException if the solving process is interrupted * @throws SolverException if an error occurs during the solving process */ private Optional solve() throws InterruptedException, SolverException { BooleanFormula[][] symbols = getSymbols(); List rules = ImmutableList.builder() .addAll(rowRule1(symbols)) .addAll(rowRule2(symbols)) .addAll(columnRule(symbols)) .addAll(diagonalRule(symbols)) .build(); // solve N-Queens try (ProverEnvironment prover = context.newProverEnvironment(ProverOptions.GENERATE_MODELS)) { prover.push(bmgr.and(rules)); boolean isUnsolvable = prover.isUnsat(); if (isUnsolvable) { return Optional.empty(); } // get model and convert it boolean[][] solution = new boolean[n][n]; try (Model model = prover.getModel()) { for (int row = 0; row < n; row++) { for (int col = 0; col < n; col++) { solution[row][col] = getValue(symbols, model, row, col); } } return Optional.of(solution); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy