org.chocosolver.solver.search.strategy.decision.IntDecision 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.
/*
* This file is part of choco-solver, http://choco-solver.org/
*
* Copyright (c) 2023, 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.search.strategy.decision;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.learn.ExplanationForSignedClause;
import org.chocosolver.solver.search.strategy.assignments.DecisionOperator;
import org.chocosolver.solver.search.strategy.assignments.DecisionOperatorFactory;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.PoolManager;
import org.chocosolver.util.objects.setDataStructures.iterable.IntIterableRangeSet;
import org.chocosolver.util.objects.setDataStructures.iterable.IntIterableSetUtils;
import java.util.function.Consumer;
/**
* A decision based on a {@link IntVar}
*
*
* @author Charles Prud'homme
* @since 2 juil. 2010
*/
public class IntDecision extends Decision {
private static final long serialVersionUID = 4319290465131546449L;
/**
* The decision value
*/
private int value;
/**
* The assignment operator
*/
private DecisionOperator assignment;
/**
* Decision pool manager, to recycle decisions
*/
transient private final PoolManager poolManager;
/**
* Create an decision based on an {@link IntVar}
* @param poolManager decision pool manager, to recycle decisions
*/
public IntDecision(PoolManager poolManager) {
super(2);
this.poolManager = poolManager;
}
@Override
public Integer getDecisionValue() {
return value;
}
@Override
public void apply() throws ContradictionException {
if (branch == 1) {
var.getModel().getSolver().getEventObserver().pushDecisionLevel();
assignment.apply(var, value, this);
} else if (branch == 2) {
assignment.unapply(var, value, this);
}
// TODO #538 assert modif: "(un-)applying decision "+ this + " does not modify the variable's domain.";
}
/**
* Instantiate this decision with the parameters
* @param v a variable
* @param value a value
* @param assignment a decision operator
*/
public void set(IntVar v, int value, DecisionOperator assignment) {
super.set(v);
this.value = value;
this.assignment = assignment;
}
@SuppressWarnings("unchecked")
@Override
public void reverse() {
this.assignment = assignment.opposite();
}
@Override
public void free() {
poolManager.returnE(this);
}
@Override
public IntDecision duplicate() {
IntDecision d = poolManager.getE();
if (d == null) {
d = new IntDecision(poolManager);
}
d.set(var, value, assignment);
return d;
}
@Override
public boolean isEquivalentTo(Decision dec) {
if (dec instanceof IntDecision) {
IntDecision id = (IntDecision) dec;
return (id.var == this.var
&& id.assignment == this.assignment
&& id.value == this.value
&& id.max_branching == this.max_branching
&& id.branch == this.branch);
} else {
return false;
}
}
/**
* @return the current decision operator
*/
public DecisionOperator getDecOp() {
return assignment;
}
/**
* @return a copy of this decision wherein the he decision operator is reversed
*/
@SuppressWarnings("unchecked")
public IntDecision flip(){
IntDecision d = poolManager.getE();
if (d == null) {
d = new IntDecision(poolManager);
}
int val = value;
if(assignment == DecisionOperatorFactory.makeIntSplit()){
val++;
}
else if(assignment == DecisionOperatorFactory.makeIntReverseSplit()){
val--;
}
d.set(var, val, assignment.opposite());
return d;
}
@Override
public String toString() {
boolean nonrefuted = ((branch < max_branching) || (max_branching == 1 && branch == max_branching));
if (assignment.getClass().equals(DecisionOperatorFactory.makeIntEq().getClass())) {
return String.format("d_%d: %s%s%d",
getPosition(),
var.getName(),
nonrefuted ? "=": '\\',
value);
} else if (assignment.getClass().equals(DecisionOperatorFactory.makeIntNeq().getClass())) {
return String.format("d_%d: %s%s%d",
getPosition(),
var.getName(),
nonrefuted ? "\u2260" : '=',
value);
} else if (assignment.getClass().equals(DecisionOperatorFactory.makeIntSplit().getClass())) {
return String.format("d_%d: %s%s%s%d,%d]",
getPosition(),
var.getName(),
"\u2208",
nonrefuted ? '[' : ']',
nonrefuted ? var.getLB() : value,
nonrefuted ? value : var.getUB());
} else if (assignment.getClass().equals(DecisionOperatorFactory.makeIntReverseSplit().getClass())) {
return String.format("d_%d: %s%s[%d,%d%s",
getPosition(),
var.getName(),
"\u2208",
nonrefuted ? value : var.getLB(),
nonrefuted ? var.getUB() : value,
nonrefuted ? ']' : '[');
} else {
return String.format("d_%d: %s%s{%s}",
getPosition(),
var.getName(),
nonrefuted ? assignment.toString() : assignment.opposite().toString(),
value);
}
}
/**
* @implSpec
* Since a decision only relies on a unique variable, designed by 'p' and this decision,
* this can be treated as unary constraint, depending on this {@link #assignment}
* and {@link #branch}.
*
*
* Let's consider an assignment decisions, (X = a) and that Dx is the domain of x just
* before applying this decision.
* Then, we can formalize the application of this like:
*
*
* (v1 ∈ D1) → v1 ∈ a
*
* Converting to DNF:
*
* (v1 ∈ (U \ D1) ∪ a)
*
*
*
*/
@Override
public void explain(int p, ExplanationForSignedClause explanation) {
IntIterableRangeSet dom = explanation.complement(var);
IntIterableSetUtils.unionOf(dom, explanation.readDom(p));
var.intersectLit(dom, explanation);
}
@Override
public void forEachIntVar(Consumer action) {
// nothing to do
}
}