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

org.chocosolver.solver.variables.impl.BoolVarEagerLit Maven / Gradle / Ivy

The newest version!
/*
 * This file is part of choco-solver, http://choco-solver.org/
 *
 * Copyright (c) 2025, 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.variables.impl;

import org.chocosolver.sat.MiniSat;
import org.chocosolver.sat.Reason;
import org.chocosolver.solver.Cause;
import org.chocosolver.solver.ICause;
import org.chocosolver.solver.Model;
import org.chocosolver.solver.constraints.Explained;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.BoolVar;
import org.chocosolver.solver.variables.delta.IEnumDelta;
import org.chocosolver.solver.variables.delta.IIntDeltaMonitor;
import org.chocosolver.solver.variables.delta.NoDelta;
import org.chocosolver.solver.variables.delta.OneValueDelta;
import org.chocosolver.solver.variables.delta.monitor.OneValueDeltaMonitor;
import org.chocosolver.solver.variables.events.IntEventType;
import org.chocosolver.solver.variables.impl.scheduler.BoolEvtScheduler;
import org.chocosolver.util.ESat;
import org.chocosolver.util.iterators.*;

import java.util.Iterator;

import static org.chocosolver.sat.MiniSat.C_Undef;

/**
 * A wrapper for boolean variables, that maintains an internal data structure to ease the creation of clauses.
 * This class is based on the paper: "Lazy Clause Generation Reengineered", Thibaut Feydy & Peter J. Stuckey , CP 2009.
 * 
* It is designed to manage bound lits and also value lits. * So, the domain is supposed to be small enough to avoid too many lits. * Consequently, the observed variable can either be of type {@link BitsetIntVarImpl} * or {@link FixedIntVarImpl}. * * @author Charles Prud'homme * @since 04/09/2023 */ @Explained public class BoolVarEagerLit extends AbstractVariable implements BoolVar, LitVar { MiniSat sat; // the sat solver boolean channeling = true; // to communicate with the sat solver or not int vlit; // the value literal /** * To iterate over removed values */ private IEnumDelta delta = NoDelta.singleton; /** * To iterate over values in the domain */ private DisposableValueIterator _viterator; /** * To iterate over ranges */ private DisposableRangeIterator _riterator; /** * Value iterator allowing for(int i:this) loops */ private IntVarValueIterator _javaIterator; /** * Set to true if this variable reacts is associated with at least one propagator which reacts * on value removal */ private boolean reactOnRemoval = false; /** * Associate boolean variable expressing not(this) */ private BoolVar not; /** * For boolean expression purpose */ private boolean isNot = false; int type; /** * Create a boolean variable for LCG. */ public BoolVarEagerLit(String name, Model model, int min, int max) { super(name, model); this.sat = getModel().getSolver().getSat(); this.vlit = MiniSat.makeLiteral(sat.nVars(), true); sat.newVariable(new MiniSat.ChannelInfo(this, 1, 0, 1)); int t = VAR; if (min == 1) { sat.cEnqueue(vlit, Reason.undef()); t = CSTE; } if (max == 0) { sat.cEnqueue(MiniSat.neg(vlit), Reason.undef()); t = CSTE; } type = t; } @Override public boolean removeValue(int value, ICause cause, Reason reason) throws ContradictionException { assert cause != null; if (value == kFALSE) return this.instantiateTo(kTRUE, cause, reason); else if (value == kTRUE) return this.instantiateTo(kFALSE, cause, reason); return false; } @Override public boolean instantiateTo(int value, ICause cause, Reason reason) throws ContradictionException { if (!channeling) { channeling = true; // to prevent infinite loop // the variable is instantiated by the SAT solver if (sat.confl != C_Undef) { this.contradiction(cause, "sat failure"); } this.notifyPropagators(IntEventType.INSTANTIATE, cause); return true; } else if (!isInstantiatedTo(value)) { boolean inconsistent = (isInstantiated() || (value < kFALSE || value > kTRUE)); this.notify(reason, cause, sat, getLit(value, LR_EQ)); if (inconsistent) { assert (sat.confl != C_Undef); this.contradiction(cause, "sat failure"); } int cval = sat.valueLit(vlit); if ((cval == MiniSat.lTrue && value != kTRUE) || (cval == MiniSat.lFalse && value != kFALSE)) { assert (sat.confl != C_Undef); this.contradiction(cause, "sat failure"); } this.notifyPropagators(IntEventType.INSTANTIATE, cause); return true; } return false; } @Override public boolean updateLowerBound(int value, ICause cause, Reason reason) throws ContradictionException { assert cause != null; return value > kFALSE && this.instantiateTo(value, cause, reason); } @Override public boolean updateUpperBound(int value, ICause cause, Reason reason) throws ContradictionException { assert cause != null; return value < kTRUE && this.instantiateTo(value, cause, reason); } @Override public void channel(int val, int val_type, int sign) { channeling = false; int op = val_type * 3 ^ sign; try { switch (op) { case LR_NE: removeValue(val, Cause.Null, Reason.undef()); break; case LR_EQ: instantiateTo(val, Cause.Null, Reason.undef()); break; case LR_GE: case LR_LE: default: throw new UnsupportedOperationException("BoolVarEagerLit#channel"); } } catch (ContradictionException ce) { // ignore: should be detected by the SAT assert (sat.confl != C_Undef); } channeling = true; } @Override public int getLit(int val, int type) { if (val < 0) { return 1 ^ (type & 1); // true, false, true, false } if (val > 1) { return type - 1 >> 1 & 1; // true, false, false, true } switch (type) { case LR_NE: return vlit - val; case LR_EQ: return vlit - 1 + val; case LR_GE: return val == 1 ? vlit - 1 + val : 1; case LR_LE: return val == 0 ? vlit - 1 + val : 1; default: throw new UnsupportedOperationException("BoolVarEagerLit#getLit"); } } @Override public int getMinLit() { return MiniSat.neg(getLit(getLB(), LR_GE)); } @Override public int getMaxLit() { return MiniSat.neg(getLit(getUB(), LR_LE)); } @Override public int getValLit() { assert (isInstantiated()) : this + " is not instantiated"; return getLit(getLB(), LR_NE); } @Override public boolean isInstantiated() { return sat.valueLit(vlit) != MiniSat.lUndef; } @Override public boolean isInstantiatedTo(int aValue) { switch (sat.valueLit(vlit)) { case MiniSat.lTrue: return aValue == kTRUE; case MiniSat.lFalse: return aValue == kFALSE; default: return false; } } @Override public boolean contains(int aValue) { switch (sat.valueLit(vlit)) { case MiniSat.lTrue: return aValue == kTRUE; case MiniSat.lFalse: return aValue == kFALSE; default: return aValue == kFALSE || aValue == kTRUE; } } @Override public int getValue() throws IllegalStateException { if (!isInstantiated()) { throw new IllegalStateException("getValue() can be only called on instantiated variable. " + name + " is not instantiated"); } return getLB(); } @Override public ESat getBooleanValue() { if (isInstantiated()) { return ESat.eval(getLB() != kFALSE); } return ESat.UNDEFINED; } /** * Retrieves the lower bound of the variable * * @return the lower bound */ @Override public int getLB() { switch (sat.valueLit(vlit)) { case MiniSat.lTrue: return kTRUE; default: case MiniSat.lFalse: return kFALSE; } } /** * Retrieves the upper bound of the variable * * @return the upper bound */ @Override public int getUB() { switch (sat.valueLit(vlit)) { default: case MiniSat.lTrue: return kTRUE; case MiniSat.lFalse: return kFALSE; } } @Override public int getDomainSize() { return (isInstantiated() ? 1 : 2); } @Override public int getRange() { return getDomainSize(); } @Override public int nextValue(int v) { if (isInstantiated()) { final int val = getLB(); return (val > v) ? val : Integer.MAX_VALUE; } else { if (v < kFALSE) return kFALSE; if (v == kFALSE) return kTRUE; return Integer.MAX_VALUE; } } @Override public int nextValueOut(int v) { int lb = 0, ub = 1; if (isInstantiated()) { // if this is instantiated lb = ub = getLB(); } if (lb - 1 <= v && v <= ub) { return ub + 1; } else { return v + 1; } } @Override public int previousValue(int v) { if (v > getUB()) return getUB(); if (v > getLB()) return getLB(); return Integer.MIN_VALUE; } @Override public int previousValueOut(int v) { int lb = 0, ub = 1; if (isInstantiated()) { // if this is instantiated lb = ub = getLB(); } if (lb <= v && v <= ub + 1) { return lb - 1; } else { return v - 1; } } @Override public boolean hasEnumeratedDomain() { return true; } @Override public IEnumDelta getDelta() { return delta; } @Override public String toString() { if (isInstantiated()) { return this.name + " = " + getLB(); } else { return this.name + " = " + "[0,1]"; } } //////////////////////////////////////////////////////////////// ///// methode liees au fait qu'une variable est observable ///// //////////////////////////////////////////////////////////////// @Override public void createDelta() { if (!reactOnRemoval) { delta = new OneValueDelta(model.getEnvironment()); reactOnRemoval = true; } } @Override public IIntDeltaMonitor monitorDelta(ICause propagator) { createDelta(); return new OneValueDeltaMonitor(delta, propagator); } @Override public int getTypeAndKind() { return BOOL | type; } @Override protected EvtScheduler createScheduler() { return new BoolEvtScheduler(); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @Override public DisposableValueIterator getValueIterator(boolean bottomUp) { if (_viterator == null || _viterator.isNotReusable()) { _viterator = new DisposableValueBoundIterator(this); } if (bottomUp) { _viterator.bottomUpInit(); } else { _viterator.topDownInit(); } return _viterator; } @Override public DisposableRangeIterator getRangeIterator(boolean bottomUp) { if (_riterator == null || _riterator.isNotReusable()) { _riterator = new DisposableRangeBoundIterator(this); } if (bottomUp) { _riterator.bottomUpInit(); } else { _riterator.topDownInit(); } return _riterator; } @Override public Iterator iterator() { if (_javaIterator == null) { _javaIterator = new IntVarValueIterator(this); } _javaIterator.reset(); return _javaIterator; } @Override public void _setNot(BoolVar neg) { this.not = neg; } @Override public BoolVar not() { if (!hasNot()) { not = model.boolNotView(this); not._setNot(this); } return not; } @Override public boolean hasNot() { return not != null; } @Override public boolean isLit() { return true; } @Override public boolean isNot() { return isNot; } @Override public void setNot(boolean isNot) { this.isNot = isNot; } /** * Creates, or returns if already existing, the SAT variable twin of this. * * @return the SAT variable of this */ public int satVar() { return MiniSat.var(this.vlit); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy