Package solver.constraints.binary

Source Code of solver.constraints.binary.PropDistanceXYC$RemProc

/*
* Copyright (c) 1999-2014, 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:
*
*     * Redistributions of source code must retain the above copyright
*       notice, this list of conditions and the following disclaimer.
*     * 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.
*     * Neither the name of the Ecole des Mines de Nantes 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS AND CONTRIBUTORS 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 solver.constraints.binary;

import gnu.trove.map.hash.THashMap;
import solver.Solver;
import solver.constraints.Operator;
import solver.constraints.Propagator;
import solver.constraints.PropagatorPriority;
import solver.exception.ContradictionException;
import solver.exception.SolverException;
import solver.explanations.Deduction;
import solver.explanations.Explanation;
import solver.explanations.VariableState;
import solver.variables.IntVar;
import solver.variables.Variable;
import solver.variables.delta.IIntDeltaMonitor;
import solver.variables.events.IntEventType;
import util.ESat;
import util.iterators.DisposableRangeIterator;
import util.procedure.UnaryIntProcedure;

/**
* | X - Y | op C <br/> op = {"==", "<", ">", "=/="} <br/>
*
* @author Charles Prud'homme
* @since 21/03/12
*/
public class PropDistanceXYC extends Propagator<IntVar> {

    protected final Operator operator;

    protected final int cste;

    protected final RemProc remproc;

    protected final IIntDeltaMonitor[] idms;

    public PropDistanceXYC(IntVar[] vars, Operator operator, int cste) {
        super(vars, PropagatorPriority.BINARY, true);
        if (operator == Operator.EQ) {
            this.idms = new IIntDeltaMonitor[this.vars.length];
            for (int i = 0; i < this.vars.length; i++) {
                idms[i] = vars[i].hasEnumeratedDomain() ? this.vars[i].monitorDelta(this) : IIntDeltaMonitor.Default.NONE;
            }
        } else {
            this.idms = new IIntDeltaMonitor[0];
        }
        this.operator = operator;
        this.cste = cste;
        this.remproc = new RemProc(this);
    }

    @Override
    public int getPropagationConditions(int idx) {
        if (vars[idx].hasEnumeratedDomain()) {
            return IntEventType.all();
        } else {
            return IntEventType.boundAndInst();
        }
    }

    @Override
    public void propagate(int evtmask) throws ContradictionException {
        //cste < 0, and |vars[0]-vars[1]| always >= 0
        if (cste < 0) {
            switch (operator) {
                case EQ:
                case LT:
                    this.contradiction(null, "< or = to 0");
                    break;
                case NQ:
                case GT:
                    this.setPassive();
                    break;
            }
        }
        if (operator == Operator.EQ) {
            if (vars[0].hasEnumeratedDomain()) {
                filterFromVarToVar(vars[0], vars[1]);
            } else {
                vars[0].updateLowerBound(vars[1].getLB() - cste, aCause);
                vars[0].updateUpperBound(vars[1].getUB() + cste, aCause);
            }
            if (vars[1].hasEnumeratedDomain()) {
                filterFromVarToVar(vars[1], vars[0]);
            } else {
                vars[1].updateLowerBound(vars[0].getLB() - cste, aCause);
                vars[1].updateUpperBound(vars[0].getUB() + cste, aCause);
            }
        } else if (operator == Operator.GT) {
            filterGT();
        } else if (operator == Operator.LT) {
            filterLT();
        } else {
            filterNeq();
        }
        for (int i = 0; i < idms.length; i++) {
            idms[i].unfreeze();
        }
    }

    @Override
    public void propagate(int varIdx, int mask) throws ContradictionException {
        int idx2 = varIdx == 0 ? 1 : 0;
        switch (operator) {
            case EQ:
                if (IntEventType.isInstantiate(mask)) {
                    filterOnInst(vars[idx2], vars[varIdx].getValue());
                } else {
                    if (IntEventType.isRemove(mask) && vars[varIdx].hasEnumeratedDomain()) {
                        idms[varIdx].freeze();
                        idms[varIdx].forEachRemVal(remproc.set(varIdx));
                        idms[varIdx].unfreeze();
                    }
                    if (IntEventType.isInclow(mask)) {
                        filterOnInf(vars[varIdx], vars[idx2]);
                    }
                    if (IntEventType.isDecupp(mask)) {
                        filterOnSup(vars[varIdx], vars[idx2]);
                    }
                }
                break;
            case NQ:
                filterNeq();
                break;
            case GT:
                if (IntEventType.isInstantiate(mask)) {
                    filterGTonVar(vars[varIdx], vars[idx2]);
                } else if (IntEventType.isBound(mask)) {
                    filterGTonVar(vars[varIdx], vars[idx2]);
                }
                break;
            case LT:
                if (IntEventType.isInstantiate(mask)) {
                    filterLTonVar(vars[varIdx], vars[idx2]);
                } else if (IntEventType.isBound(mask)) {
                    filterLTonVar(vars[varIdx], vars[idx2]);
                }
                break;
        }
    }

    @Override
    public ESat isEntailed() {
        if (isCompletelyInstantiated()) {
            if (operator == Operator.EQ) {
                return ESat.eval(Math.abs(vars[0].getValue() - vars[1].getValue()) == cste);
            } else if (operator == Operator.LT) {
                return ESat.eval(Math.abs(vars[0].getValue() - vars[1].getValue()) < cste);
            } else if (operator == Operator.GT) {
                return ESat.eval(Math.abs(vars[0].getValue() - vars[1].getValue()) > cste);
            } else if (operator == Operator.NQ) {
                return ESat.eval(Math.abs(vars[0].getValue() - vars[1].getValue()) != cste);
            } else {
                throw new SolverException("operator not known");
            }
        }
        return ESat.UNDEFINED;
    }

    @Override
    public String toString() {
        StringBuilder st = new StringBuilder();
        st.append("|").append(vars[0].getName()).append(" - ").append(vars[1].getName()).append("|");
        switch (operator) {
            case EQ:
                st.append("=");
                break;
            case GT:
                st.append(">");
                break;
            case LT:
                st.append("<");
                break;
            case NQ:
                st.append("=/=");
                break;
        }
        st.append(cste);
        return st.toString();
    }

    @Override
    public void explain(Deduction d, Explanation e) {
        e.add(solver.getExplainer().getPropagatorActivation(this));
        Variable reason = (d.getVar() == vars[0]) ? vars[1] : vars[0];
        reason.explain(VariableState.DOM, e);
        e.add(aCause);
    }


    //*************************************************************//
//        Methods for filtering                                //
//*************************************************************//


    /**
     * Initial propagation in case of EQ and enumerated domains
     *
     * @throws ContradictionException
     */
    public void filterFromVarToVar(IntVar var1, IntVar var2) throws ContradictionException {
        DisposableRangeIterator it = var1.getRangeIterator(true);
        try {
            while (it.hasNext()) {
                int from = it.min();
                int to = it.max();
                for (int value = from; value <= to; value++)
                    if (!var2.contains(value - cste) && !var2.contains(value + cste)) {
                        var1.removeValue(value, aCause);
                    }
                it.next();
            }
        } finally {
            it.dispose();
        }
    }

    /**
     * In case of a GT
     */
    public void filterGT() throws ContradictionException {
        if (cste >= 0) {
            int lbv0 = vars[1].getUB() - cste;
            int ubv0 = vars[1].getLB() + cste;
            // remove interval [lbv0, ubv0] from domain of vars[0]
            vars[0].removeInterval(lbv0, ubv0, aCause);
            int lbv1 = vars[0].getUB() - cste;
            int ubv1 = vars[0].getLB() + cste;
            // remove interval [lbv1, ubv1] from domain of vars[1]
            vars[1].removeInterval(lbv1, ubv1, aCause);
        } else {
            this.setPassive();
        }
    }

    /**
     * In case of a GT, due to a modification on v0 domain
     */
    public void filterGTonVar(IntVar v0, IntVar v1) throws ContradictionException {
        if (cste >= 0) {
            int lbv0 = v0.getUB() - cste;
            int ubv0 = v0.getLB() + cste;
            // remove interval [lbv0, ubv0] from domain of vars[0]
            v1.removeInterval(lbv0, ubv0, aCause);
        } else {
            this.setPassive();
        }
    }

    /**
     * In case of a LT
     */
    public void filterLT() throws ContradictionException {
        vars[0].updateLowerBound(vars[1].getLB() - cste + 1, aCause);
        vars[0].updateUpperBound(vars[1].getUB() + cste - 1, aCause);
        vars[1].updateLowerBound(vars[0].getLB() - cste + 1, aCause);
        vars[1].updateUpperBound(vars[0].getUB() + cste - 1, aCause);
    }

    /**
     * In case of a LT, due to a modification on v0 domain
     */
    public void filterLTonVar(IntVar v0, IntVar v1) throws ContradictionException {
        v1.updateLowerBound(v0.getLB() - cste + 1, aCause);
        v1.updateUpperBound(v0.getUB() + cste - 1, aCause);
    }

    /**
     * In case of a EQ, due to a modification of the lower bound of v0
     */
    public void filterOnInf(IntVar v0, IntVar v1) throws ContradictionException {
        if (v1.hasEnumeratedDomain()) {
            int end = v0.getLB() + cste;
            for (int val = v0.getLB(); val <= end; val = v1.nextValue(val)) {
                if (!v0.contains(val - cste) && !v0.contains(val + cste)) {
                    v1.removeValue(val, aCause);
                }
            }
        } else {
            v1.updateLowerBound(v0.getLB() - cste, aCause);
        }
    }

    /**
     * In case of a EQ, due to a modification of the upper bound of v0
     */
    public void filterOnSup(IntVar v0, IntVar v1) throws ContradictionException {
        if (v1.hasEnumeratedDomain()) {
            int initval;
            if (v0.getUB() - cste > v1.getLB()) {
                initval = v1.nextValue(v0.getUB() - cste - 1);
            } else {
                initval = v1.getLB();
            }
            int val = initval;
            do {
                if (!v0.contains(val - cste) && !v0.contains(val + cste)) {
                    v1.removeValue(val, aCause);
                }
                val = v1.nextValue(val);
            } while (val <= v1.getUB() && val > initval); //todo : pourquoi besoin du deuxieme currentElement ?
        } else {
            v1.updateUpperBound(v0.getUB() + cste, aCause);
        }
    }

    /**
     * In case of a EQ, due to the instantion to one variable to val
     */
    public void filterOnInst(IntVar v, int val) throws ContradictionException {
        if (!v.contains(val + cste)) {
            v.instantiateTo(val - cste, aCause);
        } else if (!v.contains(val - cste)) {
            v.instantiateTo(val + cste, aCause);
        } else {
            if (v.hasEnumeratedDomain()) {
                DisposableRangeIterator rit = v.getRangeIterator(true);
                try {
                    while (rit.hasNext()) {
                        int from = rit.min();
                        int to = rit.max();
                        for (int value = from; value <= to; value++) {
                            if (value != (val - cste) && value != (val + cste)) {
                                v.removeValue(value, aCause);
                            }
                        }
                        rit.next();
                    }
                } finally {
                    rit.dispose();
                }
            } else {
                v.updateLowerBound(val - cste, aCause);
                v.updateUpperBound(val + cste, aCause);
            }
        }
    }

    public void filterNeq() throws ContradictionException {
        if (cste >= 0) {
            if (vars[0].isInstantiated()) {
                vars[1].removeValue(vars[0].getValue() + cste, aCause);
                vars[1].removeValue(vars[0].getValue() - cste, aCause);
            }
            if (vars[1].isInstantiated()) {
                vars[0].removeValue(vars[1].getValue() + cste, aCause);
                vars[0].removeValue(vars[1].getValue() - cste, aCause);
            }
        } else {
            this.setPassive();
        }
    }

    private static class RemProc implements UnaryIntProcedure<Integer> {

        int idx;
        final PropDistanceXYC p;

        public RemProc(PropDistanceXYC p) {
            this.p = p;
        }

        @Override
        public UnaryIntProcedure set(Integer integer) {
            this.idx = integer;
            return this;
        }

        @Override
        public void execute(int i) throws ContradictionException {
            if (idx == 0) {
                if (!p.vars[0].contains(i + 2 * p.cste)) {
                    p.vars[1].removeValue(i + p.cste, this.p);
                }
                if (!p.vars[0].contains(i - 2 * p.cste)) {
                    p.vars[1].removeValue(i - p.cste, this.p);
                }
            } else {
                if (!p.vars[1].contains(i + 2 * p.cste)) {
                    p.vars[0].removeValue(i + p.cste, this.p);
                }
                if (!p.vars[1].contains(i - 2 * p.cste)) {
                    p.vars[0].removeValue(i - p.cste, this.p);
                }
            }
        }
    }

    @Override
    public void duplicate(Solver solver, THashMap<Object, Object> identitymap) {
        if (!identitymap.containsKey(this)) {
            int size = this.vars.length;
            IntVar[] aVars = new IntVar[size];
            for (int i = 0; i < size; i++) {
                this.vars[i].duplicate(solver, identitymap);
                aVars[i] = (IntVar) identitymap.get(this.vars[i]);
            }
            identitymap.put(this, new PropDistanceXYC(aVars, operator, cste));
        }
    }
}
TOP

Related Classes of solver.constraints.binary.PropDistanceXYC$RemProc

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.