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

org.chocosolver.solver.variables.impl.IntVarLazyLit 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.constraints.Explained;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.delta.IDelta;
import org.chocosolver.solver.variables.delta.IIntDeltaMonitor;
import org.chocosolver.solver.variables.events.IntEventType;
import org.chocosolver.solver.variables.impl.lazyness.ILazyBound;
import org.chocosolver.solver.variables.impl.lazyness.StrongBound;
import org.chocosolver.solver.variables.impl.lazyness.WeakBound;
import org.chocosolver.solver.variables.impl.scheduler.IntEvtScheduler;
import org.chocosolver.util.iterators.DisposableRangeIterator;
import org.chocosolver.util.iterators.DisposableValueIterator;
import org.chocosolver.util.iterators.EvtScheduler;
import org.chocosolver.util.objects.setDataStructures.iterable.IntIterableSet;

import java.util.Iterator;

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

/**
 * A wrapper for integer 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 only. * So, the domain is supposed to be large quit large and value removal are ignored. * Consequently, the observed variable can only be of type {@link IntervalIntVarImpl}. * * @author Charles Prud'homme * @since 12/10/2023 */ @Explained public final class IntVarLazyLit extends AbstractVariable implements IntVar, LitVar { final IntVar var; // the observed variable final MiniSat sat; // the sat solver boolean channeling = true; // to communicate with the sat solver or not private final ILazyBound bnd; int valLit; final int min0; final int max0; /** * Create a variable wrapper with eager literals * * @param var variable to wrap */ public IntVarLazyLit(IntVar var) { super(var.getName(), var.getModel()); this.model.unassociates(var); this.var = var; this.min0 = var.getLB(); this.max0 = var.getUB(); if (var.hasEnumeratedDomain()) { throw new UnsupportedOperationException("IntVarLazyLit can only wrap bounded integer variables"); } this.sat = getModel().getSolver().getSat(); if (getModel().getSettings().intVarLazyLitWithWeakBounds()) { bnd = new WeakBound(getModel()); } else { bnd = new StrongBound(getModel(), min0, max0); } valLit = MiniSat.makeLiteral(sat.nVars(), true); sat.newVariable(new MiniSat.ChannelInfo(this, 1, 2, 0, false)); if (var.isInstantiated()) { sat.cEnqueue(getLit(valLit, LR_EQ), Reason.undef()); } } // duplicated code from IntVarEagerLit @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: updateLowerBound(val + 1, Cause.Null, Reason.undef()); break; case LR_LE: updateUpperBound(val, Cause.Null, Reason.undef()); break; default: throw new UnsupportedOperationException("IntVarLazyLit#channel : are you trying to fix valLit?"); } } 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 < getLB()) { return 1 ^ (type & 1); // undefined, undefined, true, false } if (val > getUB()) { return type & 1; // undefined, undefined, false, true } switch (type) { case LR_GE: return getGELit(val); case LR_LE: return getLELit(val); default: throw new UnsupportedOperationException("IntVarLazyLit does not support this type of literal"); } } @Override public int getMinLit() { return MiniSat.makeLiteral(bnd.currentMinVar(), false); } @Override public int getMaxLit() { return MiniSat.makeLiteral(bnd.currentMaxVar(), true); } @Override public int getValLit() { assert (isInstantiated()); return MiniSat.neg(valLit); } @Override public int getGELit(int v) { if (v < min0) { return 1; } else if (v > max0) { return 0; } else if (v > getUB()) { return getMaxLit(); } assert (v >= getLB()) : var + " >= " + v; return extracted(v); } private int extracted(int v) { int prev = previousValue(v); prev = (prev == Integer.MIN_VALUE) ? v - 1 : prev; int var = bnd.getSATVar(prev, this, sat); return MiniSat.makeLiteral(var, true); } @Override public int getLELit(int v) { if (v < min0) { return 0; } else if (v > max0) { return 1; } else if (v < getLB()) { return getMinLit(); } return MiniSat.neg(getGELit(v + 1)); } void channelMin(int v, int p) { Reason r = Reason.r(MiniSat.neg(p)); int prev = previousValue(v); bnd.channelMin(prev, sat, r); } void channelMax(int v, int p) { Reason r = Reason.r(MiniSat.neg(p)); bnd.channelMax(v, sat, r); } void updateFixed() { Reason r = Reason.r(getMinLit(), getMaxLit()); sat.cEnqueue(valLit, r); } @Override public boolean removeValue(int value, ICause cause, Reason reason) throws ContradictionException { assert cause != null; if (value == getLB()) { return updateLowerBound(value + 1, cause, Reason.gather(reason, getMinLit())); } else if (value == getUB()) { return updateUpperBound(value - 1, cause, Reason.gather(reason, getMaxLit())); } return false; } @Override public boolean removeValues(IntIterableSet values, ICause cause, Reason reason) throws ContradictionException { throw new UnsupportedOperationException("#removeValues"); } @Override public boolean removeAllValuesBut(IntIterableSet values, ICause cause, Reason reason) throws ContradictionException { throw new UnsupportedOperationException("#removeAllValuesBut"); } @Override public boolean instantiateTo(int value, ICause cause, Reason reason) throws ContradictionException { return updateLowerBound(value, cause, reason) | updateUpperBound(value, cause, reason); } @Override public boolean updateLowerBound(int value, ICause cause, Reason reason) throws ContradictionException { if (value > getLB()) { int p = getGELit(value); if (channeling) { this.notify(reason, cause, sat, p); } if (value > getUB()) { // ignore: should be detected by the SAT assert (sat.confl != C_Undef); this.contradiction(cause, "sat failure"); } channelMin(value, p); int ub = getUB(); IntEventType e = IntEventType.INCLOW; if (value == ub) {// || var.nextValue(value - 1) == ub) { updateFixed(); e = IntEventType.INSTANTIATE; } // then update the variable, should not fail... var.updateLowerBound(value, Cause.Null); this.notifyPropagators(e, cause); return true; } return false; } @Override public boolean updateUpperBound(int value, ICause cause, Reason reason) throws ContradictionException { if (value < getUB()) { int p = getLELit(value); if (channeling) { this.notify(reason, cause, sat, p); } if (value < getLB()) { // ignore: should be detected by the SAT assert (sat.confl != C_Undef); this.contradiction(cause, "sat failure"); } channelMax(value, p); int lb = getLB(); IntEventType e = IntEventType.DECUPP; if (value == lb) {// || var.previousValue(value + 1) == lb) { updateFixed(); e = IntEventType.INSTANTIATE; } // then update the variable, should not fail... var.updateUpperBound(value, Cause.Null); this.notifyPropagators(e, cause); return true; } return false; } @Override public boolean updateBounds(int lb, int ub, ICause cause, Reason reason) throws ContradictionException { throw new UnsupportedOperationException("#updateBounds"); } @Override public boolean removeInterval(int from, int to, ICause cause) throws ContradictionException { throw new UnsupportedOperationException("#removeInterval"); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // THE REST IS DELEGATED TO var // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @Override public boolean contains(int value) { return var.contains(value); } @Override public boolean isInstantiatedTo(int value) { return var.isInstantiatedTo(value); } @Override public int getValue() throws IllegalStateException { return var.getValue(); } @Override public int getLB() { return var.getLB(); } @Override public int getUB() { return var.getUB(); } @Override public int getRange() { return var.getRange(); } @Override public int nextValue(int v) { return var.nextValue(v); } @Override public int nextValueOut(int v) { return var.nextValueOut(v); } @Override public int previousValue(int v) { return var.previousValue(v); } @Override public int previousValueOut(int v) { return var.previousValueOut(v); } @Override public DisposableValueIterator getValueIterator(boolean bottomUp) { return var.getValueIterator(bottomUp); } @Override public DisposableRangeIterator getRangeIterator(boolean bottomUp) { return var.getRangeIterator(bottomUp); } @Override public boolean hasEnumeratedDomain() { return var.hasEnumeratedDomain(); } @Override public IIntDeltaMonitor monitorDelta(ICause propagator) { return var.monitorDelta(propagator); } @Override public Iterator iterator() { return var.iterator(); } @Override public boolean isInstantiated() { return var.isInstantiated(); } @Override public int getDomainSize() { return var.getDomainSize(); } @Override public IDelta getDelta() { return var.getDelta(); } @Override public void createDelta() { var.createDelta(); } @Override public int getTypeAndKind() { return var == null ? VAR | INT : var.getTypeAndKind(); } @Override protected EvtScheduler createScheduler() { return new IntEvtScheduler(); } @Override public String toString() { return var.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy