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

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

There is a newer version: 4.10.16
Show newest version
/**
 * Copyright (c) 2016, Ecole des Mines de Nantes
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by the .
 * 4. Neither the name of the  nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY  ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package org.chocosolver.solver.constraints.ternary;

import org.chocosolver.solver.constraints.Operator;
import org.chocosolver.solver.constraints.Propagator;
import org.chocosolver.solver.constraints.PropagatorPriority;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.exception.SolverException;
import org.chocosolver.solver.variables.IntVar;
import org.chocosolver.solver.variables.events.IntEventType;
import org.chocosolver.util.ESat;

/**
 * A constraint to state |x0 - x1| operator x2
 * where operator can be =, <=, >= and x1, x2, x3 are variables
 * Warning: only achieves BoundConsistency for the moment !
 *
 * @author Hadrien Cambazard, Charles Prud'homme
 * @since 06/04/12
 */
public final class PropDistanceXYZ extends Propagator {

    private Operator operator;

    /**
     * Enforces |x0 - x1| op x2
     * where op can be =, <, >
     *
     * @param vars variable
     * @param op   the operator to be chosen among {0,1,2} standing for (eq,lt,gt)
     */
    public PropDistanceXYZ(IntVar[] vars, Operator op) {
        super(vars, PropagatorPriority.TERNARY, true);
        this.operator = op;
    }


    @Override
    public int getPropagationConditions(int vIdx) {
        return IntEventType.boundAndInst();
    }

    @Override
    public void propagate(int evtmask) throws ContradictionException {
        filterFixPoint();
    }

    @Override
    public void propagate(int idxVarInProp, int mask) throws ContradictionException {
        filterFixPoint();
    }


    //*************************************************************//
    //********************** main filter **************************//
    //*************************************************************//

    public void filterFixPoint() throws ContradictionException {
        boolean change = true;
        while (change) {
            if (operator == Operator.EQ) {
                change = filterFromXYtoLBZ();
                change |= filterFromXYtoUBZ();
                change |= filterEQFromXZToY();
                change |= filterEQFromYZToX();
            } else if (operator == Operator.LT) {
                change = filterFromXYtoLBZ();
                change |= filterLTFromXZtoY();
                change |= filterLTFromYZtoX();
            } else if (operator == Operator.GT) {
                change = filterFromXYtoUBZ();
                change |= filterGTFromXZtoY();
                change |= filterGTFromYZtoX();
            }
        }
    }


    //*************************************************************//
    //********************** Bounds on Z **************************//
    //*************************************************************//

    //update lower bound of vars[2] if we have vars[0] != vars[1]
    //
    public boolean filterFromXYtoLBZ() throws ContradictionException {
        int t = vars[1].getLB() - vars[0].getUB();
        if (t > 0) { // x < y
            return vars[2].updateLowerBound(t, this);
        }
        t = vars[0].getLB() - vars[1].getUB();
        // x > y
        return t > 0 && vars[2].updateLowerBound(t, this);
    }

    //update upper bound of vars[2] as max(|vars[1].sup - vars[0].inf|, |vars[1].inf - vars[0].sup|)
    public boolean filterFromXYtoUBZ() throws ContradictionException {
        int a = Math.abs(vars[1].getUB() - vars[0].getLB());
        int b = Math.abs(vars[0].getUB() - vars[1].getLB());
        return vars[2].updateUpperBound((a > b) ? a : b, this);
    }

    //*************************************************************//
    //********************** EQ on XY *****************************//
    //*************************************************************//

    public boolean filterEQFromYZToX() throws ContradictionException {
        int l1 = vars[1].getLB();
        int u1 = vars[1].getUB();
        int l2 = vars[2].getLB();
        int u2 = vars[2].getUB();
        int lb = l1 - u2;
        int ub = u1 + u2;
        int lbv0 = u1 - l2 + 1;
        int ubv0 = l1 + l2 - 1;
        return vars[0].updateLowerBound(lb, this) | vars[0].updateUpperBound(ub, this) | vars[0].removeInterval(lbv0, ubv0, this);
    }

    public boolean filterEQFromXZToY() throws ContradictionException {
        int l0 = vars[0].getLB();
        int u0 = vars[0].getUB();
        int l2 = vars[2].getLB();
        int u2 = vars[2].getUB();
        int lb = l0 - u2;
        int ub = u0 + u2;
        int lbv1 = u0 - l2 + 1;
        int ubv1 = l0 + l2 - 1;
        return vars[1].updateLowerBound(lb, this) |
                vars[1].updateUpperBound(ub, this) |
                vars[1].removeInterval(lbv1, ubv1, this);
    }

    //*************************************************************//
    //********************** LT on XY *****************************//
    //*************************************************************//

    // LEQ: update x from the domain of z and y
    public boolean filterLTFromYZtoX() throws ContradictionException {
        int u2 = vars[2].getUB();
        int lb = vars[1].getLB() - u2 + 1;
        int ub = vars[1].getUB() + u2 - 1;
        return vars[0].updateLowerBound(lb, this) | vars[0].updateUpperBound(ub, this);
    }

    // LEQ: update x from the domain of z and y
    public boolean filterLTFromXZtoY() throws ContradictionException {
        int u2 = vars[2].getUB();
        int lb = vars[0].getLB() - u2 + 1;
        int ub = vars[0].getUB() + u2 - 1;
        return vars[1].updateLowerBound(lb, this) | vars[1].updateUpperBound(ub, this);
    }

    //*************************************************************//
    //********************** GT on XY *****************************//
    //*************************************************************//

    // GEQ: remove interval for x from the domain of z and y
    public boolean filterGTFromYZtoX() throws ContradictionException {
//        DisposableIntIterator it = vars[0].getDomain().getIterator();
//        boolean b = false;
//        while(it.hasNext()) {
//            int val = it.next();
//            if (Math.max(Math.abs(val- vars[1].getLB()),Math.abs(val - vars[1].getUB())) <= vars[2].getLB()) {
//                b |= vars[0].removeVal(val,cIdx0);
//            }
//        }
        int l2 = vars[2].getLB();
        int lbv0 = vars[1].getUB() - l2;
        int ubv0 = vars[1].getLB() + l2;
        // remove interval [lbv0, ubv0] from domain of vars[0]
        return vars[0].removeInterval(lbv0, ubv0, this);
    }

    // GEQ: remove interval for y from the domain of x and y
    public boolean filterGTFromXZtoY() throws ContradictionException {
//         DisposableIntIterator it = vars[1].getDomain().getIterator();
//         boolean b = false;
//         while(it.hasNext()) {
//             int val = it.next();
//             if (Math.max(Math.abs(vars[0].getLB() - val),Math.abs(vars[0].getUB() - val)) <= vars[2].getLB()) {
//                 b |= vars[1].removeVal(val,cIdx1);
//             }
//         }
//         return b;
        int l2 = vars[2].getLB();
        int lbv1 = vars[0].getUB() - l2;
        int ubv1 = vars[0].getLB() + l2;
        // remove interval [lbv0, ubv0] from domain of vars[0]
        return vars[1].removeInterval(lbv1, ubv1, this);
    }

    @Override
    public ESat isEntailed() {
        if (isCompletelyInstantiated()) {
            if (operator == Operator.EQ) {
                return ESat.eval(Math.abs(vars[0].getValue() - vars[1].getValue()) == vars[2].getValue());
            } else if (operator == Operator.LT) {
                return ESat.eval(Math.abs(vars[0].getValue() - vars[1].getValue()) < vars[2].getValue());
            } else if (operator == Operator.GT) {
                return ESat.eval(Math.abs(vars[0].getValue() - vars[1].getValue()) > vars[2].getValue());
            }
        }
        return ESat.UNDEFINED;
    }

    @Override
    public String toString() {
        String op;
        if (operator == Operator.EQ) {
            op = "=";
        } else if (operator == Operator.GT) {
            op = ">";
        } else if (operator == Operator.LT) {
            op = "<";
        } else {
            throw new SolverException("unknown operator");
        }
        return "|" + vars[0] + " - " + vars[1] + "| " + op + " " + vars[2];
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy