
org.btrplace.scheduler.choco.extensions.RoundedUpDivision Maven / Gradle / Ivy
/*
* Copyright 2020 The BtrPlace Authors. All rights reserved.
* Use of this source code is governed by a LGPL-style
* license that can be found in the LICENSE.txt file.
*/
package org.btrplace.scheduler.choco.extensions;
import org.chocosolver.solver.constraints.Constraint;
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;
/**
* A constraint to enforce {@code a == b / divider} where {@code divider} is a real and {@code a} and {@code b} are
* both integers.
* The division is rounded up to the smallest integer.
*
* In practice, the constraint maintains:
*
* - {@code a = Math.ceil(b / divider)}
* - {@code b = ((a - 1 )* divider) % 1 == 0 ? [(a - 1)*divider + 1; Math.floor(a * divider)] : [Math.ceil((a -1)*divider); Math.floor(a * divider)]}
*
*
* @author Fabien Hermenier
*/
public class RoundedUpDivision extends Constraint {
/**
* Make a new constraint.
*
* @param a the variable to divide
* @param b the resulting ratio
* @param d the divider
*/
public RoundedUpDivision(IntVar a, IntVar b, double d) {
super("RoundedUpDivision", new RoundedUpDivisionPropagator(a, b, d));
}
static class RoundedUpDivisionPropagator extends Propagator {
private final double divider;
/**
* New propagator
*
* @param a the variable to divide
* @param b the resulting ratio
* @param d the divider
*/
public RoundedUpDivisionPropagator(IntVar a, IntVar b, double d) {
super(new IntVar[]{a, b}, PropagatorPriority.BINARY, true);
this.divider = d;
}
@Override
public int getPropagationConditions(int vIdx) {
return IntEventType.DECUPP.getMask() + IntEventType.INCLOW.getMask() + IntEventType.INSTANTIATE.getMask();
}
@Override
public ESat isEntailed() {
if (vars[0].getDomainSize() == 1 && vars[1].getDomainSize() == 1) {
return ESat.eval(vars[0].getValue() == (int) Math.ceil(vars[1].getValue() / divider));
}
return ESat.UNDEFINED;
}
private int div(int b) {
return (int) Math.ceil(b / divider);
}
private int multLB(int a) {
if ((a - 1 * divider) % 1 == 0) {
return (int) ((a - 1) * divider + 1);
}
return (int) Math.ceil(divider * (a - 1));
}
@Override
public void propagate(int evtMask) throws ContradictionException {
filter();
if (vars[0].getLB() != div(vars[1].getLB())
|| vars[0].getUB() != div(vars[1].getUB())) {
this.fails();
}
}
private boolean filter() throws ContradictionException {
boolean fix = awakeOnInf(0);
fix |= awakeOnSup(0);
fix |= awakeOnInf(1);
fix |= awakeOnSup(1);
return fix;
}
@Override
public void propagate(int idx, int mask) throws ContradictionException {
do {
} while (filter());
}
public boolean awakeOnInf(int i) throws ContradictionException {
if (i == 1) {
return vars[0].updateLowerBound(div(vars[1].getLB()), this);
}
return vars[1].updateLowerBound(multLB(vars[0].getLB()), this);
}
public boolean awakeOnSup(int i) throws ContradictionException {
if (i == 1) {
return vars[0].updateUpperBound(div(vars[1].getUB()), this);
}
return vars[1].updateUpperBound((int) Math.floor(divider * vars[0].getUB()), this);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy