org.chocosolver.solver.constraints.IReificationFactory Maven / Gradle / Ivy
Show all versions of choco-solver Show documentation
/*
* This file is part of choco-solver, http://choco-solver.org/
*
* Copyright (c) 2024, IMT Atlantique. All rights reserved.
*
* Licensed under the BSD 4-clause license.
*
* See LICENSE file in the project root for full license information.
*/
package org.chocosolver.solver.constraints;
import org.chocosolver.solver.ISelf;
import org.chocosolver.solver.Model;
import org.chocosolver.solver.constraints.reification.*;
import org.chocosolver.solver.search.SearchState;
import org.chocosolver.solver.variables.BoolVar;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.ESat;
import org.chocosolver.util.objects.setDataStructures.iterable.IntIterableRangeSet;
/**
* Interface to reify constraints
* A kind of factory relying on interface default implementation to allow (multiple) inheritance
*
* @author Jean-Guillaume FAGES
* @since 4.0.0
*/
public interface IReificationFactory extends ISelf {
//***********************************************************************************
// Non-reifiable reification constraints
//***********************************************************************************
/**
* Posts a constraint ensuring that if ifCstr is satisfied, then thenCstr must be satisfied as well
* Otherwise, elseCstr must be satisfied
* ifCstr => ThenCstr
* not(ifCstr) => ElseCstr
*
* BEWARE : it is automatically posted (it cannot be reified)
*
* @param ifCstr a constraint
* @param thenCstr a constraint
* @param elseCstr a constraint
*/
default void ifThenElse(Constraint ifCstr, Constraint thenCstr, Constraint elseCstr) {
ifThenElse(ifCstr.reify(), thenCstr, elseCstr);
}
/**
* Posts an implication constraint: ifVar => thenCstr && not(ifVar) => elseCstr.
*
* Ensures:
*
- ifVar = 1 => thenCstr is satisfied,
* - ifVar = 0 => elseCstr is satisfied,
* - thenCstr is not satisfied => ifVar = 0
* - elseCstr is not satisfied => ifVar = 1
*
* In order to get ifVar <=> thenCstr, use reification
*
* BEWARE : it is automatically posted (it cannot be reified)
*
* @param ifVar variable of reification
* @param thenCstr the constraint to be satisfied when ifVar = 1
* @param elseCstr the constraint to be satisfied when ifVar = 0
*/
default void ifThenElse(BoolVar ifVar, Constraint thenCstr, Constraint elseCstr) {
ifThen(ifVar, thenCstr);
ifThen(ifVar.not(), elseCstr);
}
/**
* Posts a constraint ensuring that if ifCstr is satisfied, then thenCstr is satisfied as well
*
* BEWARE : it is automatically posted (it cannot be reified)
*
* @param ifCstr a constraint
* @param thenCstr a constraint
*/
default void ifThen(Constraint ifCstr, Constraint thenCstr) {
ifThen(ifCstr.reify(), thenCstr);
}
/**
* Posts an implication constraint: ifVar => thenCstr
* Also called half reification constraint
* Ensures:
*
- ifVar = 1 => thenCstr is satisfied,
* - thenCstr is not satisfied => ifVar = 0
*
* Example :
* - ifThen(b1, arithm(v1, "=", 2));
:
* b1 is equal to 1 => v1 = 2, so v1 != 2 => b1 is equal to 0
* But if b1 is equal to 0, nothing happens
*
* BEWARE : it is automatically posted (it cannot be reified)
*
*
* @param ifVar variable of reification
* @param thenCstr the constraint to be satisfied when ifVar = 1
*/
default void ifThen(BoolVar ifVar, Constraint thenCstr) {
// PRESOLVE
if (ifVar.contains(1)) {
if (ifVar.isInstantiated()) {
thenCstr.post();
} else if (thenCstr.isSatisfied() == ESat.FALSE) {
thenCstr.ignore();
ref().arithm(ifVar, "=", 0).post();
}
// END OF PRESOLVE
else {
ref().arithm(ifVar, "<=", thenCstr.reify()).post();
}
}else{
thenCstr.ignore();
}
}
/**
* Posts an equivalence constraint stating that
* cstr1 is satisfied <=> cstr2 is satisfied,
*
* BEWARE : it is automatically posted (it cannot be reified)
*
* @param cstr1 a constraint to be satisfied if and only if cstr2 is satisfied
* @param cstr2 a constraint to be satisfied if and only if cstr1 is satisfied
*/
default void ifOnlyIf(Constraint cstr1, Constraint cstr2) {
reification(cstr1.reify(), cstr2);
}
/**
* Reify a constraint with a boolean variable:
* var = 1 <=> cstr is satisfied,
*
* Equivalent to ifOnlyIf
*
* BEWARE : it is automatically posted (it cannot be reified)
*
* @param var variable of reification
* @param cstr the constraint to be satisfied if and only if var = 1
*/
default void reification(BoolVar var, Constraint cstr) {
// PRESOLVE
ESat entail = cstr.isSatisfied();
if (var.isInstantiatedTo(1)) {
cstr.post();
} else if (var.isInstantiatedTo(0)) {
cstr.getOpposite().post();
} else if (entail == ESat.TRUE) {
cstr.ignore();
ref().arithm(var, "=", 1).post();
} else if (entail == ESat.FALSE) {
cstr.ignore();
ref().arithm(var, "=", 0).post();
}
// END OF PRESOLVE
else {
cstr.reifyWith(var);
}
}
/**
* Posts one constraint that expresses : (x = c) ⇔ b.
* Bypasses the reification system.
*
* @param X a integer variable
* @param C an int
* @param B a boolean variable
*/
default void reifyXeqC(IntVar X, int C, BoolVar B) {
// no check to allow addition during resolution
if (ref().getSolver().getSearchState() == SearchState.NEW) {
if (X.isInstantiatedTo(C)) {
ref().arithm(B, "=", 1).post();
return;
} else if (!X.contains(C)) {
ref().arithm(B, "=", 0).post();
return;
}
}
ref().post(new Constraint(ConstraintsName.BASIC_REI, new PropXeqCReif(X, C, B)));
}
/**
* Posts one constraint that expresses : (x ≠ c) ⇔ b.
* Bypasses the reification system.
*
* @param X a integer variable
* @param C an int
* @param B a boolean variable
*/
default void reifyXneC(IntVar X, int C, BoolVar B) {
// no check to allow addition during resolution
reifyXeqC(X, C, B.not());
}
/**
* Posts one constraint that expresses : (x = y) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param B a boolean variable
*/
@SuppressWarnings("SuspiciousNameCombination")
default void reifyXeqY(IntVar X, IntVar Y, BoolVar B) {
if(X == Y){
ref().arithm(B, "=", 1).post();
}else if (X.isAConstant()) {
reifyXeqC(Y, X.getValue(), B);
} else if (Y.isAConstant()) {
reifyXeqC(X, Y.getValue(), B);
} else {
// no check to allow addition during resolution
ref().post(new Constraint(ConstraintsName.BASIC_REI, new PropXeqYCReif(X, Y, 0, B)));
}
}
/**
* Posts one constraint that expresses : (x ≠ y) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param B a boolean variable
*/
@SuppressWarnings("SuspiciousNameCombination")
default void reifyXneY(IntVar X, IntVar Y, BoolVar B) {
if (X.isAConstant()) {
reifyXneC(Y, X.getValue(), B);
} else if (Y.isAConstant()) {
reifyXneC(X, Y.getValue(), B);
} else {
// no check to allow addition during resolution
reifyXeqY(X, Y, B.not());
}
}
/**
* Posts one constraint that expresses : (x = y + c) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param C an int
* @param B a boolean variable
*/
@SuppressWarnings("SuspiciousNameCombination")
default void reifyXeqYC(IntVar X, IntVar Y, int C, BoolVar B) {
if(C == 0){
reifyXeqY(X, Y, B);
}else if (X.isAConstant()) {
reifyXeqC(Y, X.getValue() - C, B);
} else if (Y.isAConstant()) {
reifyXeqC(X, Y.getValue() + C, B);
} else {
// no check to allow addition during resolution
ref().post(new Constraint(ConstraintsName.BASIC_REI, new PropXeqYCReif(X, Y, C, B)));
}
}
/**
* Posts one constraint that expresses : (x ≠ y + c) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param C an int
* @param B a boolean variable
*/
@SuppressWarnings("SuspiciousNameCombination")
default void reifyXneYC(IntVar X, IntVar Y, int C, BoolVar B) {
if (X.isAConstant()) {
reifyXneC(Y, X.getValue() - C, B);
} else if (Y.isAConstant()) {
reifyXneC(X, Y.getValue() + C, B);
} else {
// no check to allow addition during resolution
reifyXeqYC(X, Y, C, B.not());
}
}
/**
* Posts one constraint that expresses : (x < c) ⇔ b.
* Bypasses the reification system.
*
* @param X a integer variable
* @param C an int
* @param B a boolean variable
*/
default void reifyXltC(IntVar X, int C, BoolVar B) {
// no check to allow addition during resolution
if (ref().getSolver().getSearchState() == SearchState.NEW) {
if (X.getUB() < C) {
ref().arithm(B, "=", 1).post();
return;
} else if (X.getLB() >= C) {
ref().arithm(B, "=", 0).post();
return;
}
}
ref().post(new Constraint(ConstraintsName.BASIC_REI, new PropXltCReif(X, C, B)));
}
/**
* Posts one constraint that expresses : (x > c) ⇔ b.
* Bypasses the reification system.
*
* @param X a integer variable
* @param C an int
* @param B a boolean variable
*/
default void reifyXgtC(IntVar X, int C, BoolVar B) {
// no check to allow addition during resolution
reifyXltC(X, C + 1, B.not());
}
/**
* Posts one constraint that expresses : (x < y) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param B a boolean variable
*/
@SuppressWarnings("SuspiciousNameCombination")
default void reifyXltY(IntVar X, IntVar Y, BoolVar B) {
if (X.isAConstant()) {
reifyXgtC(Y, X.getValue(), B);
} else if (Y.isAConstant()) {
reifyXltC(X, Y.getValue(), B);
} else {
// no check to allow addition during resolution
reifyXltYC(X, Y, 0, B);
}
}
/**
* Posts one constraint that expresses : (x > y) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param B a boolean variable
*/
default void reifyXgtY(IntVar X, IntVar Y, BoolVar B) {
reifyXltYC(X, Y, 1, B.not());
}
/**
* Posts one constraint that expresses : (x ≤ y) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param B a boolean variable
*/
default void reifyXleY(IntVar X, IntVar Y, BoolVar B) {
// no check to allow addition during resolution
reifyXltYC(X, Y, 1, B);
}
/**
* Posts one constraint that expresses : (x ≥ y) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param B a boolean variable
*/
default void reifyXgeY(IntVar X, IntVar Y, BoolVar B) {
// no check to allow addition during resolution
reifyXltYC(X, Y, 0, B.not());
}
/**
* Posts one constraint that expresses : (x < y + c) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param C an int
* @param B a boolean variable
*/
@SuppressWarnings("SuspiciousNameCombination")
default void reifyXltYC(IntVar X, IntVar Y, int C, BoolVar B) {
// no check to allow addition during resolution
if(X == Y){
if(C > 0){
ref().arithm(B, "=", 1).post();
}else{
ref().arithm(B, "=", 0).post();
}
}else if (X.isAConstant()) {
reifyXgtC(Y, X.getValue() - C, B);
} else if (Y.isAConstant()) {
reifyXltC(X, Y.getValue() + C, B);
} else {
ref().post(new Constraint(ConstraintsName.BASIC_REI, new PropXltYCReif(X, Y, C, B)));
}
}
/**
* Posts one constraint that expresses : (x > y + c) ⇔ b.
* Bypasses the reification system.
*
* @param X an integer variable
* @param Y an integer variable
* @param C an int
* @param B a boolean variable
*/
default void reifyXgtYC(IntVar X, IntVar Y, int C, BoolVar B) {
// no check to allow addition during resolution
reifyXltYC(X, Y, C + 1, B.not());
}
/**
* Posts one constraint that expresses : (X ∈ S) ⇔ B.
* Bypasses the reification system.
*
* @param X an integer variable
* @param S a set of values
* @param B a boolean variable
*/
default void reifyXinS(IntVar X, IntIterableRangeSet S, BoolVar B) {
// no check to allow addition during resolution
ref().post(new Constraint(ConstraintsName.BASIC_REI, new PropXinSReif(X, S, B)));
}
/**
* Posts one constraint that expresses : (X ∉ S) ⇔ B.
* Bypasses the reification system.
*
* @param X an integer variable
* @param S a set of values
* @param B a boolean variable
*/
default void reifyXnotinS(IntVar X, IntIterableRangeSet S, BoolVar B) {
// no check to allow addition during resolution
ref().post(new Constraint(ConstraintsName.BASIC_REI, new PropXinSReif(X, S, B.not())));
}
}