org.chocosolver.solver.constraints.ISatFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of choco-solver Show documentation
Show all versions of choco-solver Show documentation
Open-source constraint solver.
/**
* Copyright (c) 2016, Ecole des Mines de Nantes
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the .
* 4. Neither the name of the nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.chocosolver.solver.constraints;
import gnu.trove.list.TIntList;
import gnu.trove.list.array.TIntArrayList;
import org.chocosolver.sat.PropSat;
import org.chocosolver.solver.ISelf;
import org.chocosolver.solver.Model;
import org.chocosolver.solver.constraints.nary.cnf.ILogical;
import org.chocosolver.solver.constraints.nary.cnf.LogOp;
import org.chocosolver.solver.constraints.nary.cnf.LogicTreeToolBox;
import org.chocosolver.solver.constraints.reification.LocalConstructiveDisjunction;
import org.chocosolver.solver.constraints.reification.PropConDis;
import org.chocosolver.solver.variables.BoolVar;
/**
* A factory dedicated to SAT.
*
*
*
* @author Charles Prud'homme
* @since 15/07/13
*/
public interface ISatFactory extends ISelf {
/**
* Ensures that the clauses defined in the Boolean logic formula TREE are satisfied.
*
* @param TREE the syntactic tree
* @return true if the clause has been added to the clause store
*/
default boolean addClauses(LogOp TREE) {
ILogical tree = LogicTreeToolBox.toCNF(TREE, _me());
boolean ret = true;
if (_me().boolVar(true).equals(tree)) {
ret = addClauseTrue(_me().boolVar(true));
} else if (_me().boolVar(false).equals(tree)) {
ret = addClauseTrue(_me().boolVar(false));
} else {
ILogical[] clauses;
if (!tree.isLit() && ((LogOp) tree).is(LogOp.Operator.AND)) {
clauses = ((LogOp) tree).getChildren();
} else {
clauses = new ILogical[]{tree};
}
for (int i = 0; i < clauses.length; i++) {
ILogical clause = clauses[i];
if (clause.isLit()) {
BoolVar bv = (BoolVar) clause;
ret &= addClauseTrue(bv);
} else {
LogOp n = (LogOp) clause;
BoolVar[] bvars = n.flattenBoolVar();
if (_me().getSettings().enableSAT()) {
TIntList lits = new TIntArrayList(bvars.length);
PropSat sat = _me().getMinisat().getPropSat();
// init internal structures
sat.beforeAddingClauses();
for (int j = 0; j < bvars.length; j++) {
lits.add(sat.makeLiteral(bvars[j], true));
}
// TODO: pass by satsolver directly
ret &= sat.addClause(lits);
sat.afterAddingClauses();
}else{
_me().sum(bvars, ">", 0).post();
ret &= true;
}
}
}
}
return ret;
}
/**
* Ensures that the clause defined by POSLITS and NEGLITS is satisfied.
*
* @param POSLITS positive literals
* @param NEGLITS negative literals
* @return true if the clause has been added to the clause store
*/
default boolean addClauses(BoolVar[] POSLITS, BoolVar[] NEGLITS) {
if (_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
int[] pos = new int[POSLITS.length];
for (int i = 0; i < POSLITS.length; i++) {
pos[i] = sat.makeVar(POSLITS[i]);
}
int[] neg = new int[NEGLITS.length];
for (int i = 0; i < NEGLITS.length; i++) {
neg[i] = sat.makeVar(NEGLITS[i]);
}
boolean add = sat.getSatSolver().addClause(pos, neg);
sat.afterAddingClauses();
return add;
}else{
int PL = POSLITS.length;
int NL = NEGLITS.length;
BoolVar[] LITS = new BoolVar[PL + NL];
System.arraycopy(POSLITS, 0, LITS, 0, PL);
for (int i = 0; i < NL; i++) {
LITS[i + PL] = NEGLITS[i].not();
}
_me().sum(LITS, ">", 0).post();
return true;
}
}
/**
* Add a unit clause stating that BOOLVAR must be true
*
* @param BOOLVAR a boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClauseTrue(BoolVar BOOLVAR) {
if (_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addTrue(sat.makeVar(BOOLVAR));
sat.afterAddingClauses();
return add;
}else{
_me().arithm(BOOLVAR, "=", 1).post();
return true;
}
}
/**
* Add a unit clause stating that BOOLVAR must be false
*
* @param BOOLVAR a boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClauseFalse(BoolVar BOOLVAR) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addFalse(sat.makeVar(BOOLVAR));
sat.afterAddingClauses();
return add;
}else{
_me().arithm(BOOLVAR, "=", 0).post();
return true;
}
}
/**
* Add a clause stating that: LEFT == RIGHT
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolEq(BoolVar LEFT, BoolVar RIGHT) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolEq(sat.makeVar(LEFT), sat.makeVar(RIGHT));
sat.afterAddingClauses();
return add;
}else{
_me().arithm(LEFT, "=", RIGHT).post();
return true;
}
}
/**
* Add a clause stating that: LEFT ≤ RIGHT
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolLe(BoolVar LEFT, BoolVar RIGHT) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolLe(sat.makeVar(LEFT), sat.makeVar(RIGHT));
sat.afterAddingClauses();
return add;
}else{
_me().arithm(LEFT, "<=", RIGHT).post();
return true;
}
}
/**
* Add a clause stating that: LEFT < RIGHT
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolLt(BoolVar LEFT, BoolVar RIGHT) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolLt(sat.makeVar(LEFT), sat.makeVar(RIGHT));
sat.afterAddingClauses();
return add;
}else{
_me().arithm(LEFT, "<", RIGHT).post();
return true;
}
}
/**
* Add a clause stating that: LEFT != RIGHT
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolNot(BoolVar LEFT, BoolVar RIGHT) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolNot(sat.makeVar(LEFT), sat.makeVar(RIGHT));
sat.afterAddingClauses();
return add;
}else{
_me().arithm(LEFT, "!=", RIGHT).post();
return true;
}
}
/**
* Add a clause stating that: (BOOLVARS1∨BOOLVARS2∨...∨BOOLVARSn) ⇔ TARGET
*
* @param BOOLVARS a list of boolean variables
* @param TARGET the reified boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolOrArrayEqVar(BoolVar[] BOOLVARS, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
int[] vars = new int[BOOLVARS.length];
for (int i = 0; i < BOOLVARS.length; i++) {
vars[i] = sat.makeVar(BOOLVARS[i]);
}
boolean add = sat.getSatSolver().addBoolOrArrayEqVar(vars, sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().sum(BOOLVARS, ">", 0).reifyWith(TARGET);
return true;
}
}
/**
* Add a clause stating that: (BOOLVARS1∧BOOLVARS2∧...∧BOOLVARSn) ⇔ TARGET
*
* @param BOOLVARS a list of boolean variables
* @param TARGET the reified boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolAndArrayEqVar(BoolVar[] BOOLVARS, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
int[] vars = new int[BOOLVARS.length];
for (int i = 0; i < BOOLVARS.length; i++) {
vars[i] = sat.makeVar(BOOLVARS[i]);
}
boolean add = sat.getSatSolver().addBoolAndArrayEqVar(vars, sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().sum(BOOLVARS, "=", BOOLVARS.length).reifyWith(TARGET);
return true;
}
}
/**
* Add a clause stating that: (LEFT ∨ RIGHT) ⇔ TARGET
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @param TARGET the reified boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolOrEqVar(BoolVar LEFT, BoolVar RIGHT, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolOrEqVar(sat.makeVar(LEFT), sat.makeVar(RIGHT), sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().arithm(LEFT, "+", RIGHT, ">", 0).reifyWith(TARGET);
return true;
}
}
/**
* Add a clause stating that: (LEFT ∧ RIGHT) ⇔ TARGET
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @param TARGET the reified boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolAndEqVar(BoolVar LEFT, BoolVar RIGHT, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolAndEqVar(sat.makeVar(LEFT), sat.makeVar(RIGHT), sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().arithm(LEFT, "+", RIGHT, "=", 2).reifyWith(TARGET);
return true;
}
}
/**
* Add a clause stating that: (LEFT ⊕ RIGHT) ⇔ TARGET
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @param TARGET the reified boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolXorEqVar(BoolVar LEFT, BoolVar RIGHT, BoolVar TARGET) {
return addClausesBoolIsNeqVar(LEFT, RIGHT, TARGET);
}
/**
* Add a clause stating that: (LEFT == RIGHT) ⇔ TARGET
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @param TARGET the reified boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolIsEqVar(BoolVar LEFT, BoolVar RIGHT, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolIsEqVar(sat.makeVar(LEFT), sat.makeVar(RIGHT), sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().reifyXeqY(LEFT, RIGHT, TARGET);
return true;
}
}
/**
* Add a clause stating that: (LEFT ≠ RIGHT) ⇔ TARGET
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @param TARGET the reified boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolIsNeqVar(BoolVar LEFT, BoolVar RIGHT, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolIsNeqVar(sat.makeVar(LEFT), sat.makeVar(RIGHT), sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().reifyXneY(LEFT, RIGHT, TARGET);
return true;
}
}
/**
* Add a clause stating that: (LEFT ≤ RIGHT) ⇔ TARGET
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @param TARGET the reified boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolIsLeVar(BoolVar LEFT, BoolVar RIGHT, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolIsLeVar(sat.makeVar(LEFT), sat.makeVar(RIGHT), sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().reifyXleY(LEFT, RIGHT, TARGET);
return true;
}
}
/**
* Add a clause stating that: (LEFT < RIGHT) ⇔ TARGET
*
* @param LEFT a boolean variable
* @param RIGHT another boolean variable
* @param TARGET the reified boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolIsLtVar(BoolVar LEFT, BoolVar RIGHT, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add = sat.getSatSolver().addBoolIsLtVar(sat.makeVar(LEFT), sat.makeVar(RIGHT), sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().reifyXltY(LEFT, RIGHT, TARGET);
return true;
}
}
/**
* Add a clause stating that: BOOLVARS1∨BOOLVARS2∨...∨BOOLVARSn
*
* @param BOOLVARS a list of boolean variables
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolOrArrayEqualTrue(BoolVar[] BOOLVARS) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
int[] vars = new int[BOOLVARS.length];
for (int i = 0; i < BOOLVARS.length; i++) {
vars[i] = sat.makeVar(BOOLVARS[i]);
}
boolean add = sat.getSatSolver().addBoolOrArrayEqualTrue(vars);
sat.afterAddingClauses();
return add;
}else{
_me().sum(BOOLVARS, ">", 0).post();
return true;
}
}
/**
* Add a clause stating that: BOOLVARS1∧BOOLVARS2∧...∧BOOLVARSn
*
* @param BOOLVARS a list of boolean variables
* @return true if the clause has been added to the clause store
*/
default boolean addClausesBoolAndArrayEqualFalse(BoolVar[] BOOLVARS) {
return addClausesAtMostNMinusOne(BOOLVARS);
}
/**
* Add a clause stating that: ∑ BOOLVARSi ≤ 1
*
* @param BOOLVARS a list of boolean variables
* @return true if the clause has been added to the clause store
*/
default boolean addClausesAtMostOne(BoolVar[] BOOLVARS) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
int[] vars = new int[BOOLVARS.length];
for (int i = 0; i < BOOLVARS.length; i++) {
vars[i] = sat.makeVar(BOOLVARS[i]);
}
boolean add = sat.getSatSolver().addAtMostOne(vars);
sat.afterAddingClauses();
return add;
}else{
_me().sum(BOOLVARS, "<", 2).post();
return true;
}
}
/**
* Add a clause stating that: ∑ BOOLVARSi ≤ n-1
*
* @param BOOLVARS a list of boolean variables
* @return true if the clause has been added to the clause store
*/
default boolean addClausesAtMostNMinusOne(BoolVar[] BOOLVARS) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
int[] vars = new int[BOOLVARS.length];
for (int i = 0; i < BOOLVARS.length; i++) {
vars[i] = sat.makeVar(BOOLVARS[i]);
}
boolean add = sat.getSatSolver().addAtMostNMinusOne(vars);
sat.afterAddingClauses();
return add;
}else{
_me().sum(BOOLVARS, "<", BOOLVARS.length).post();
return true;
}
}
/**
* Add a clause stating that: sum(BOOLVARSi) ≥ TARGET
*
* @param BOOLVARS a list of boolean variables
* @param TARGET a boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesSumBoolArrayGreaterEqVar(BoolVar[] BOOLVARS, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
int[] vars = new int[BOOLVARS.length];
for (int i = 0; i < BOOLVARS.length; i++) {
vars[i] = sat.makeVar(BOOLVARS[i]);
}
boolean add = sat.getSatSolver().addSumBoolArrayGreaterEqVar(vars, sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().sum(BOOLVARS, ">=", TARGET).post();
return true;
}
}
/**
* Add a clause stating that: max(BOOLVARSi) ≤ TARGET
*
* @param BOOLVARS a list of boolean variables
* @param TARGET a boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesMaxBoolArrayLessEqVar(BoolVar[] BOOLVARS, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
int[] vars = new int[BOOLVARS.length];
for (int i = 0; i < BOOLVARS.length; i++) {
vars[i] = sat.makeVar(BOOLVARS[i]);
}
boolean add = sat.getSatSolver().addMaxBoolArrayLessEqVar(vars, sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
BoolVar max =_me().boolVar(_me().generateName("bool_max"));
_me().max(max, BOOLVARS).post();
max.le(TARGET).post();
return true;
}
}
/**
* Add a clause stating that: sum(BOOLVARSi) ≤ TARGET
*
* @param BOOLVARS a list of boolean variables
* @param TARGET a boolean variable
* @return true if the clause has been added to the clause store
*/
default boolean addClausesSumBoolArrayLessEqVar(BoolVar[] BOOLVARS, BoolVar TARGET) {
if(_me().getSettings().enableSAT()) {
PropSat sat = _me().getMinisat().getPropSat();
sat.beforeAddingClauses();
boolean add;
if (BOOLVARS.length == 1) {
add = addClausesBoolLe(BOOLVARS[0], TARGET);
}
int[] vars = new int[BOOLVARS.length];
for (int i = 0; i < BOOLVARS.length; i++) {
vars[i] = sat.makeVar(BOOLVARS[i]);
}
add = sat.getSatSolver().addSumBoolArrayLessEqVar(vars, sat.makeVar(TARGET));
sat.afterAddingClauses();
return add;
}else{
_me().sum(BOOLVARS, "<=", TARGET).post();
return true;
}
}
/**
* Make an constructive disjunction constraint
*
* @param global set to true to enable constructive disjunction over all the constraint network of the CSP
* (presumably filters more values, but slower),
* set to false to restrict propagation to variables directly involved in cstrs.
* In the latter, make sure at least one variable is shared by all constraints otherwise no filtering
* will happen.
* @param cstrs constraint in disjunction
* @return true if the disjunction has been added to the constructive disjunction store.
*/
default boolean addConstructiveDisjunction(boolean global, Constraint... cstrs) {
Model model = cstrs[0].propagators[0].getModel();
if (global) {
PropConDis condis = model.getConDisStore().getPropCondis();
condis.addDisjunction(cstrs);
} else {
new LocalConstructiveDisjunction(cstrs).post();
}
return true;
}
}