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

org.chocosolver.solver.constraints.nary.sum.PropScalarWithLong Maven / Gradle / Ivy

There is a newer version: 4.10.17
Show newest version
/*
 * 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.constraints.nary.sum;

import org.chocosolver.solver.constraints.Operator;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.util.ESat;

/**
 * A propagator for SUM(x_i*c_i) = b
 * 
* Based on "Bounds Consistency Techniques for Long Linear Constraint"
* W. Harvey and J. Schimpf *

* * @author Charles Prud'homme * @since 18/03/11 */ public class PropScalarWithLong extends PropSumWithLong { /** * The coefficients */ private final long[] c; /** * Create a scalar product: SUM(x_i*c_i) o b * Variables and coefficients are excepted to be ordered wrt to coefficients: first positive ones then negative ones. * @param variables list of integer variables * @param coeffs list of coefficients * @param pos position of the last positive coefficient * @param o operator * @param b bound to respect. */ public PropScalarWithLong(IntVar[] variables, long[] coeffs, int pos, Operator o, long b) { super(variables, pos, o, b); this.c = coeffs; } @Override protected void prepare() { sumLB = sumUB = 0; int i = 0; long lb, ub; maxI = 0; for (; i < pos; i++) { // first the positive coefficients lb = vars[i].getLB() * c[i]; ub = vars[i].getUB() * c[i]; sumLB += lb; sumUB += ub; I[i] = (ub - lb); if(maxI < I[i])maxI = I[i]; } for (; i < l; i++) { // then the negative ones lb = vars[i].getUB() * c[i]; ub = vars[i].getLB() * c[i]; sumLB += lb; sumUB += ub; I[i] = (ub - lb); if(maxI < I[i])maxI = I[i]; } } @Override protected void filterOnEq() throws ContradictionException { boolean anychange; long F = b - sumLB; long E = sumUB - b; do { anychange = false; // When explanations are on, no global failure allowed if (model.getSolver().isLearnOff() && F < 0 || E < 0) { fails(); } if (maxI > F || maxI > E) { maxI = 0; long lb, ub; int i = 0; // positive coefficients first while (i < pos) { if (I[i] - F > 0) { lb = vars[i].getLB() * c[i]; ub = lb + I[i]; if (vars[i].updateUpperBound(divFloor(F + lb, c[i]), this)) { long nub = vars[i].getUB() * c[i]; E += nub - ub; I[i] = nub - lb; anychange = true; } } if (I[i] - E > 0) { ub = vars[i].getUB() * c[i]; lb = ub - I[i]; if (vars[i].updateLowerBound(divCeil(ub - E, c[i]), this)) { long nlb = vars[i].getLB() * c[i]; F -= nlb - lb; I[i] = ub - nlb; anychange = true; } } if(maxI < I[i])maxI = I[i]; i++; } // then negative ones while (i < l) { if (I[i] - F > 0) { lb = vars[i].getUB() * c[i]; ub = lb + I[i]; if (vars[i].updateLowerBound(divCeil(-F - lb, -c[i]), this)) { long nub = vars[i].getLB() * c[i]; E += nub - ub; I[i] = nub - lb; anychange = true; } } if (I[i] - E > 0) { ub = vars[i].getLB() * c[i]; lb = ub - I[i]; if (vars[i].updateUpperBound(divFloor(-ub + E, -c[i]), this)) { long nlb = vars[i].getUB() * c[i]; F -= nlb - lb; I[i] = ub - nlb; anychange = true; } } if(maxI < I[i])maxI = I[i]; i++; } } if (F <= 0 && E <= 0) { this.setPassive(); return; } } while (anychange); } @Override protected void filterOnLeq() throws ContradictionException { long F = b - sumLB; long E = sumUB - b; // When explanations are on, no global failure allowed if (model.getSolver().isLearnOff() &&F < 0) { fails(); } if (maxI > F) { long lb, ub; int i = 0; maxI = 0; // positive coefficients first while (i < pos) { maxI = 0; if (I[i] - F > 0) { lb = vars[i].getLB() * c[i]; ub = lb + I[i]; if (vars[i].updateUpperBound(divFloor(F + lb, c[i]), this)) { long nub = vars[i].getUB() * c[i]; E += nub - ub; I[i] = nub - lb; } } if(maxI < I[i])maxI = I[i]; i++; } // then negative ones while (i < l) { if (I[i] - F > 0) { lb = vars[i].getUB() * c[i]; ub = lb + I[i]; if (vars[i].updateLowerBound(divCeil(-F - lb, -c[i]), this)) { long nub = vars[i].getLB() * c[i]; E += nub - ub; I[i] = nub - lb; } } if(maxI < I[i])maxI = I[i]; i++; } } if (E <= 0) { this.setPassive(); } } @Override protected void filterOnGeq() throws ContradictionException { long F = b - sumLB; long E = sumUB - b; // When explanations are on, no global failure allowed if (model.getSolver().isLearnOff() && E < 0) { fails(); } if (maxI > E) { maxI = 0; long lb, ub; int i = 0; // positive coefficients first while (i < pos) { if (I[i] - E > 0) { ub = vars[i].getUB() * c[i]; lb = ub - I[i]; if (vars[i].updateLowerBound(divCeil(ub - E, c[i]), this)) { long nlb = vars[i].getLB() * c[i]; F -= nlb - lb; I[i] = ub - nlb; } } if(maxI < I[i])maxI = I[i]; i++; } // then negative ones while (i < l) { if (I[i] - E > 0) { ub = vars[i].getLB() * c[i]; lb = ub - I[i]; if (vars[i].updateUpperBound(divFloor(-ub + E, -c[i]), this)) { long nlb = vars[i].getUB() * c[i]; F -= nlb - lb; I[i] = ub - nlb; } } if(maxI < I[i])maxI = I[i]; i++; } } if (F <= 0) { this.setPassive(); } } @Override protected void filterOnNeq() throws ContradictionException { long F = b - sumLB; long E = sumUB - b; if (F < 0 || E < 0) { setPassive(); return; } int w = -1; long sum = 0; for (int i = 0; i < l; i++) { if (vars[i].isInstantiated()) { sum += vars[i].getValue() * c[i]; } else if (w == -1) { w = i; } else return; } if (w == -1) { if (sum == b) { this.fails(); } } else if(c[w]!=0 && (b - sum)%c[w]==0){ vars[w].removeValue((b - sum)/c[w], this); } } @Override public ESat isEntailed() { long sumUB = 0, sumLB = 0; int i = 0; for (; i < pos; i++) { // first the positive coefficients sumLB += vars[i].getLB() * c[i]; sumUB += vars[i].getUB() * c[i]; } for (; i < l; i++) { // then the negative ones sumLB += vars[i].getUB() * c[i]; sumUB += vars[i].getLB() * c[i]; } return check(sumLB, sumUB); } @Override public String toString() { StringBuilder linComb = new StringBuilder(20); linComb.append(c[0]).append('.').append(vars[0].getName()); int i = 1; for (; i < pos; i++) { linComb.append(" + ").append(c[i]).append('.').append(vars[i].getName()); } for (; i < l; i++) { linComb.append(" - ").append(-c[i]).append('.').append(vars[i].getName()); } linComb.append(" ").append(o).append(" "); linComb.append(b); return linComb.toString(); } private long divFloor(long a, long b) { // we assume b > 0 if (a >= 0) { return (a / b); } else { return (a - b + 1) / b; } } private long divCeil(long a, long b) { // we assume b > 0 if (a >= 0) { return ((a + b - 1) / b); } else { return a / b; } } @Override protected PropScalarWithLong opposite(){ return new PropScalarWithLong(vars, c, pos, nop(o), b + nb(o)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy