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

org.chocosolver.solver.constraints.binary.PropAbsolute 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.constraints.binary;

import org.chocosolver.sat.Reason;
import org.chocosolver.solver.constraints.Explained;
import org.chocosolver.solver.constraints.Propagator;
import org.chocosolver.solver.constraints.PropagatorPriority;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.events.IntEventType;
import org.chocosolver.util.ESat;
import org.chocosolver.util.tools.ArrayUtils;

/**
 * Enforces X = |Y|
 * 
* * @author Charles Prud'homme * @author Jean-Guillaume Fages * @since 18/05/11 */ @Explained public class PropAbsolute extends Propagator { private final IntVar X; private final IntVar Y; private final boolean bothEnumerated; public PropAbsolute(IntVar X, IntVar Y) { super(ArrayUtils.toArray(X, Y), PropagatorPriority.BINARY, true); this.X = vars[0]; this.Y = vars[1]; bothEnumerated = X.hasEnumeratedDomain() && Y.hasEnumeratedDomain(); } @Override public int getPropagationConditions(int vIdx) { if (vars[0].hasEnumeratedDomain() && vars[1].hasEnumeratedDomain()) { return IntEventType.all(); } else { return IntEventType.boundAndInst(); } } @Override public ESat isEntailed() { if (vars[0].getUB() < 0) { return ESat.FALSE; } else if (vars[0].isInstantiated()) { if (vars[1].isInstantiated()) { return ESat.eval(vars[0].getValue() == Math.abs(vars[1].getValue())); } else if (vars[1].getDomainSize() == 2 && vars[1].contains(vars[0].getValue()) && vars[1].contains(-vars[0].getValue())) { return ESat.TRUE; } else if (!vars[1].contains(vars[0].getValue()) && !vars[1].contains(-vars[0].getValue())) { return ESat.FALSE; } else { return ESat.UNDEFINED; } } else { return ESat.UNDEFINED; } } @Override public String toString() { return String.format("%s = |%s|", vars[0].toString(), vars[1].toString()); } //*********************************************************************************** // FILTERING //*********************************************************************************** @Override public void propagate(int evtmask) throws ContradictionException { X.updateLowerBound(0, this, Reason.undef()); setBounds(); if (bothEnumerated) { enumeratedFiltering(); } } @Override public void propagate(int varIdx, int mask) throws ContradictionException { if (IntEventType.isInstantiate(mask)) { if (varIdx == 1) { X.instantiateTo(Math.abs(Y.getValue()), this, lcg() ? Reason.r(Y.getValLit()) : Reason.undef()); setPassive(); } else if (Y.hasEnumeratedDomain()) { int val = X.getValue(); Y.updateLowerBound(-val, this, lcg() ? Reason.r(X.getValLit()) : Reason.undef()); Y.updateUpperBound(val, this, lcg() ? Reason.r(X.getValLit()) : Reason.undef()); val--; for (int v = -val; v <= val; v = Y.nextValue(v)) { Y.removeValue(v, this, lcg() ? Reason.r(X.getValLit()) : Reason.undef()); } setPassive(); } else { setBounds(); } } else { if (IntEventType.isBound(mask)) { setBounds(); } if (IntEventType.isRemove(mask) && bothEnumerated) { enumeratedFiltering(); } } } private void setBounds() throws ContradictionException { // X = |Y| int max = X.getUB(); int min = X.getLB(); Y.updateLowerBound(-max, this, lcg() ? Reason.r(X.getMaxLit()) : Reason.undef()); Y.updateUpperBound(max, this, lcg() ? Reason.r(X.getMaxLit()) : Reason.undef()); for (int v = 1 - min; v <= min - 1; v = Y.nextValue(v)) { Y.removeValue(v, this, lcg() ? Reason.r(X.getMinLit()) : Reason.undef()); } //if (!lcg()) Y.removeInterval(1 - min, min - 1, this); ///////////////////////////////////////////////// int prevLB = X.getLB(); int prevUB = X.getUB(); min = Y.getLB(); max = Y.getUB(); if (max <= 0) { X.updateLowerBound(-max, this, lcg() ? Reason.r(Y.getMaxLit()) : Reason.undef()); X.updateUpperBound(-min, this, lcg() ? Reason.r(Y.getMinLit(), Y.getMaxLit()) : Reason.undef()); } else if (min >= 0) { X.updateLowerBound(min, this, lcg() ? Reason.r(Y.getMinLit()) : Reason.undef()); X.updateUpperBound(max, this, lcg() ? Reason.r(Y.getMinLit(), Y.getMaxLit()) : Reason.undef()); } else { if (Y.hasEnumeratedDomain() && !lcg()) { int mP = Y.nextValue(-1); int mN = -Y.previousValue(1); X.updateLowerBound(Math.min(mP, mN), this); } if(max >= -min){ X.updateLowerBound(-max, this, lcg() ? Reason.r(Y.getMaxLit()) : Reason.undef()); }else{ X.updateLowerBound(min, this, lcg() ? Reason.r(Y.getMinLit()) : Reason.undef()); } } if (prevLB != X.getLB() || prevUB != X.getUB()) setBounds(); } private void enumeratedFiltering() throws ContradictionException { int min = X.getLB(); int max = X.getUB(); for (int v = min; v <= max; v = X.nextValue(v)) { if (!(Y.contains(v) || Y.contains(-v))) { X.removeValue(v, this, lcg() ? Reason.r(Y.getLit(v, IntVar.LR_EQ), Y.getLit(-v, IntVar.LR_EQ)) : Reason.undef()); } } min = Y.getLB(); max = Y.getUB(); for (int v = min; v <= max; v = Y.nextValue(v)) { if (!(X.contains(Math.abs(v)))) { Y.removeValue(v, this, lcg() ? Reason.r(X.getLit(Math.abs(v), IntVar.LR_EQ)) : Reason.undef()); } } } //*********************************************************************************** // EXPLANATIONS //*********************************************************************************** }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy