001package org.clafer.choco.constraint.propagator;
002
003import solver.constraints.Propagator;
004import solver.constraints.PropagatorPriority;
005import solver.exception.ContradictionException;
006import solver.variables.EventType;
007import solver.variables.IntVar;
008import solver.variables.SetVar;
009import solver.variables.Variable;
010import solver.variables.delta.monitor.SetDeltaMonitor;
011import util.ESat;
012import util.procedure.IntProcedure;
013
014/**
015 * Missing from the library.
016 * 
017 * @author jimmy
018 */
019public class PropIntNotMemberSet extends Propagator<Variable> {
020
021    private IntVar element;
022    private SetVar set;
023    private SetDeltaMonitor setD;
024
025    public PropIntNotMemberSet(IntVar element, SetVar set) {
026        super(new Variable[]{element, set}, PropagatorPriority.BINARY, true);
027        this.element = element;
028        this.set = set;
029        this.setD = set.monitorDelta(aCause);
030    }
031
032    private boolean isElementVar(int idx) {
033        return idx == 0;
034    }
035
036    private boolean isSetVar(int idx) {
037        return idx == 1;
038    }
039
040    @Override
041    public int getPropagationConditions(int vIdx) {
042        if (isElementVar(vIdx)) {
043            return EventType.INSTANTIATE.mask;
044        }
045        assert isSetVar(vIdx);
046        return EventType.ADD_TO_KER.mask;
047    }
048
049    @Override
050    public void propagate(int evtmask) throws ContradictionException {
051        for (int i = set.getKernelFirst(); i != SetVar.END; i = set.getKernelNext()) {
052            element.removeValue(i, aCause);
053        }
054        if (element.instantiated()) {
055            set.removeFromEnvelope(element.getValue(), aCause);
056            setPassive();
057        } else if (set.instantiated()) {
058            setPassive();
059        }
060    }
061
062    @Override
063    public void propagate(int idxVarInProp, int mask) throws ContradictionException {
064        if (isElementVar(idxVarInProp)) {
065            assert element.instantiated();
066            set.removeFromEnvelope(element.getValue(), aCause);
067            setPassive();
068        } else {
069            assert isSetVar(idxVarInProp);
070            setD.freeze();
071            setD.forEach(pruneElementOnSetKer, EventType.ADD_TO_KER);
072            setD.unfreeze();
073            if (element.instantiated()) {
074                set.removeFromEnvelope(element.getValue(), aCause);
075                setPassive();
076            } else if (set.instantiated()) {
077                setPassive();
078            }
079        }
080    }
081    private final IntProcedure pruneElementOnSetKer = new IntProcedure() {
082
083        @Override
084        public void execute(int setKer) throws ContradictionException {
085            element.removeValue(setKer, aCause);
086        }
087    };
088
089    @Override
090    public ESat isEntailed() {
091        if (element.instantiated()) {
092            if (!set.envelopeContains(element.getValue())) {
093                return ESat.TRUE;
094            }
095            return set.instantiated() ? ESat.FALSE : ESat.UNDEFINED;
096        }
097        if (PropUtil.isDomSubsetKer(element, set)) {
098            return ESat.FALSE;
099        }
100        return PropUtil.isDomIntersectEnv(element, set) ? ESat.UNDEFINED : ESat.TRUE;
101    }
102
103    @Override
104    public String toString() {
105        return element + " not in " + set;
106    }
107}