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

org.chocosolver.solver.constraints.ternary.PropXplusYeqZ Maven / Gradle / Ivy

The newest version!
/*
 * 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.ternary;

import org.chocosolver.solver.constraints.Propagator;
import org.chocosolver.solver.constraints.PropagatorPriority;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.learn.ExplanationForSignedClause;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.events.IntEventType;
import org.chocosolver.util.ESat;
import org.chocosolver.util.objects.setDataStructures.iterable.IntIterableRangeSet;

/**
 * A propagator to ensure that X + Y = Z holds, where X, Y and Z are IntVar.
 * This propagator ensures AC when all variables are enumerated, BC otherwise.
 * 

* Project: choco. * * @author Charles Prud'homme * @since 03/02/2016. */ public class PropXplusYeqZ extends Propagator { private static final int THRESHOLD = 300; /** * Position of X in {@link #vars} */ private final int x = 0; /** * Position of Y in {@link #vars} */ private final int y = 1; /** * Position of Z in {@link #vars} */ private final int z = 2; /** * Set to true if X, Y and Z are bounded */ private final boolean allbounded; /** * Temporary structure to ease filtering */ private final IntIterableRangeSet set; /** * Create propagator for ternary sum: X + Y =Z * * @param X an integer variable * @param Y an integer variable * @param Z an integer variable */ public PropXplusYeqZ(IntVar X, IntVar Y, IntVar Z) { super(new IntVar[]{X, Y, Z}, PropagatorPriority.TERNARY, false); allbounded = (!X.hasEnumeratedDomain() & !Y.hasEnumeratedDomain() & !Z.hasEnumeratedDomain()); set = new IntIterableRangeSet(); } @Override public void propagate(int evtmask) throws ContradictionException { /*while */ boolean loop; do { loop = filterPlus(z, x, y); loop |= filterMinus(x, z, y); loop |= filterMinus(y, z, x); loop &= allbounded; // loop only when BC is selected } while (loop); } /** * Remove from vars[vr] holes resulting of vars[v1] + vars[v2] * * @param vr position of in vars * @param v1 position of in vars * @param v2 position of in vars * @return true if vars[vr] has changed * @throws ContradictionException if failure occurs */ private boolean filterPlus(int vr, int v1, int v2) throws ContradictionException { int lb = vars[v1].getLB() + vars[v2].getLB(); int ub = vars[v1].getUB() + vars[v2].getUB(); boolean change = vars[vr].updateBounds(lb, ub, this); if ((long) vars[v1].getDomainSize() * vars[v2].getDomainSize() > THRESHOLD) return change; if (!allbounded) { set.clear(); int ub1 = vars[v1].getUB(); int ub2 = vars[v2].getUB(); int l1 = vars[v1].getLB(); int u1 = vars[v1].nextValueOut(l1) - 1; while (u1 <= ub1) { int l2 = vars[v2].getLB(); int u2 = vars[v2].nextValueOut(l2) - 1; while (u2 <= ub2) { set.addBetween(l1 + l2, u1 + u2); l2 = vars[v2].nextValue(u2); u2 = vars[v2].nextValueOut(l2) - 1; } l1 = vars[v1].nextValue(u1); u1 = vars[v1].nextValueOut(l1) - 1; } change |= vars[vr].removeAllValuesBut(set, this); } return change; } /** * Remove from vars[vr] holes resulting of vars[v1] - vars[v2] * * @param vr position of in vars * @param v1 position of in vars * @param v2 position of in vars * @return true if vars[vr] has changed * @throws ContradictionException if failure occurs */ private boolean filterMinus(int vr, int v1, int v2) throws ContradictionException { int lb = vars[v1].getLB() - vars[v2].getUB(); int ub = vars[v1].getUB() - vars[v2].getLB(); boolean change = vars[vr].updateBounds(lb, ub, this); if ((long) vars[v1].getDomainSize() * vars[v2].getDomainSize() > THRESHOLD) return change; if (!allbounded) { set.clear(); int ub1 = vars[v1].getUB(); int ub2 = vars[v2].getUB(); int l1 = vars[v1].getLB(); int u1 = vars[v1].nextValueOut(l1) - 1; while (u1 <= ub1) { int l2 = vars[v2].getLB(); int u2 = vars[v2].nextValueOut(l2) - 1; while (u2 <= ub2) { set.addBetween(l1 - u2, u1 - l2); l2 = vars[v2].nextValue(u2); u2 = vars[v2].nextValueOut(l2) - 1; } l1 = vars[v1].nextValue(u1); u1 = vars[v1].nextValueOut(l1) - 1; } change |= vars[vr].removeAllValuesBut(set, this); } return change; } @Override public ESat isEntailed() { int sumUB = 0, sumLB = 0, i = 0; for (; i < 2; i++) { // first the positive coefficients sumLB += vars[i].getLB(); sumUB += vars[i].getUB(); } for (; i < 3; i++) { // then the negative ones sumLB -= vars[i].getUB(); sumUB -= vars[i].getLB(); } if (sumLB == 0 && sumUB == 0) { return ESat.TRUE; } if (sumUB < 0 || sumLB > 0) { return ESat.FALSE; } return ESat.UNDEFINED; } @Override public void explain(int p, ExplanationForSignedClause explanation) { // super.explain(explanation, front, ig, p); int m = explanation.readMask(p); IntVar pivot = explanation.readVar(p); IntIterableRangeSet dx, dy, dz; if (IntEventType.isInclow(m)) { if (pivot == vars[z]) { int a = explanation.readDom(vars[x]).min(); int b = explanation.readDom(vars[y]).min(); dx = explanation.universe(); dx.removeBetween(a, IntIterableRangeSet.MAX); dy = explanation.universe(); dy.removeBetween(b, IntIterableRangeSet.MAX); vars[x].unionLit(dx, explanation); vars[y].unionLit(dy, explanation); vars[z].intersectLit(a + b, IntIterableRangeSet.MAX, explanation); } else if (pivot == vars[x]) { int a = explanation.readDom(vars[y]).max(); int b = explanation.readDom(vars[z]).min(); dy = explanation.universe(); dy.removeBetween(IntIterableRangeSet.MIN, a); dz = explanation.universe(); dz.removeBetween(b, IntIterableRangeSet.MAX); vars[x].intersectLit(b - a, IntIterableRangeSet.MAX, explanation); vars[y].unionLit(dy, explanation); vars[z].unionLit(dz, explanation); } else { int a = explanation.readDom(vars[x]).max(); int b = explanation.readDom(vars[z]).min(); dx = explanation.universe(); dx.removeBetween(IntIterableRangeSet.MIN, a); dz = explanation.universe(); dz.removeBetween(b, IntIterableRangeSet.MAX); vars[x].unionLit(dx, explanation); vars[y].intersectLit(b - a, IntIterableRangeSet.MAX, explanation); vars[z].unionLit(dz, explanation); } } else if (IntEventType.isDecupp(m)) { if (pivot == vars[z]) { int a = explanation.readDom(vars[x]).max(); int b = explanation.readDom(vars[y]).max(); dx = explanation.universe(); dx.removeBetween(IntIterableRangeSet.MIN, a); dy = explanation.universe(); dy.removeBetween(IntIterableRangeSet.MIN, b); vars[x].unionLit(dx, explanation); vars[y].unionLit(dy, explanation); vars[z].intersectLit(IntIterableRangeSet.MIN, a + b, explanation); } else if (pivot == vars[x]) { int a = explanation.readDom(vars[y]).min(); int b = explanation.readDom(vars[z]).max(); dy = explanation.universe(); dy.removeBetween(a, IntIterableRangeSet.MAX); dz = explanation.universe(); dz.removeBetween(IntIterableRangeSet.MIN, b); vars[x].intersectLit(IntIterableRangeSet.MIN, b - a, explanation); vars[y].unionLit(dy, explanation); vars[z].unionLit(dz, explanation); } else { int a = explanation.readDom(vars[x]).min(); int b = explanation.readDom(vars[z]).max(); dx = explanation.universe(); dx.removeBetween(a, IntIterableRangeSet.MAX); dz = explanation.universe(); dz.removeBetween(IntIterableRangeSet.MIN, b); vars[x].unionLit(dx, explanation); vars[y].intersectLit(IntIterableRangeSet.MIN, b - a, explanation); vars[z].unionLit(dz, explanation); } } else { // remove assert IntEventType.isRemove(m); Propagator.defaultExplain(this, p, explanation); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy