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.SetVar;
008import solver.variables.delta.monitor.SetDeltaMonitor;
009import util.ESat;
010import util.procedure.IntProcedure;
011
012/**
013 *
014 * @author jimmy
015 */
016public class PropMask extends Propagator<SetVar> {
017
018    private final SetVar set;
019    private final SetVar masked;
020    private final SetDeltaMonitor setD;
021    private final SetDeltaMonitor maskedD;
022    // Inclusive
023    private final int from;
024    // Exclusive
025    private final int to;
026
027    public PropMask(SetVar set, SetVar masked, int from, int to) {
028        super(new SetVar[]{set, masked}, PropagatorPriority.UNARY, true);
029
030        if (from > to) {
031            throw new IllegalArgumentException();
032        }
033
034        this.set = set;
035        this.masked = masked;
036        this.setD = set.monitorDelta(aCause);
037        this.maskedD = masked.monitorDelta(aCause);
038        this.from = from;
039        this.to = to;
040    }
041
042    private boolean isSetVar(int idx) {
043        return idx == 0;
044    }
045
046    private boolean isMaskedVar(int idx) {
047        return idx == 1;
048    }
049
050    @Override
051    protected int getPropagationConditions(int vIdx) {
052        return EventType.ADD_TO_KER.mask + EventType.REMOVE_FROM_ENVELOPE.mask;
053    }
054
055    @Override
056    public void propagate(int evtmask) throws ContradictionException {
057        for (int i = set.getKernelFirst(); i != SetVar.END; i = set.getKernelNext()) {
058            if (i >= from && i < to) {
059                masked.addToKernel(i - from, aCause);
060            }
061        }
062        for (int i = set.getEnvelopeFirst(); i != SetVar.END; i = set.getEnvelopeNext()) {
063            if (i >= from && i < to && !masked.envelopeContains(i - from)) {
064                set.removeFromEnvelope(i, aCause);
065            }
066        }
067        for (int i = masked.getKernelFirst(); i != SetVar.END; i = masked.getKernelNext()) {
068            set.addToKernel(i + from, aCause);
069        }
070        for (int i = masked.getEnvelopeFirst(); i != SetVar.END; i = masked.getEnvelopeNext()) {
071            if (i >= to - from || !set.envelopeContains(i + from)) {
072                masked.removeFromEnvelope(i, aCause);
073            }
074        }
075    }
076
077    @Override
078    public void propagate(int idxVarInProp, int mask) throws ContradictionException {
079        if (isSetVar(idxVarInProp)) {
080            setD.freeze();
081            setD.forEach(pickMaskedOnSetKer, EventType.ADD_TO_KER);
082            setD.forEach(pruneMaskedOnSetEnv, EventType.REMOVE_FROM_ENVELOPE);
083            setD.unfreeze();
084        } else {
085            assert isMaskedVar(idxVarInProp);
086            maskedD.freeze();
087            maskedD.forEach(pickSetOnMaskedKer, EventType.ADD_TO_KER);
088            maskedD.forEach(pruneSetOnMaskedEnv, EventType.REMOVE_FROM_ENVELOPE);
089            maskedD.unfreeze();
090        }
091    }
092    private final IntProcedure pickMaskedOnSetKer = new IntProcedure() {
093        @Override
094        public void execute(int ker) throws ContradictionException {
095            if (ker >= from && ker < to) {
096                masked.addToKernel(ker - from, aCause);
097            }
098        }
099    };
100    private final IntProcedure pruneMaskedOnSetEnv = new IntProcedure() {
101        @Override
102        public void execute(int env) throws ContradictionException {
103            if (env >= from && env < to) {
104                masked.removeFromEnvelope(env - from, aCause);
105            }
106        }
107    };
108    private final IntProcedure pickSetOnMaskedKer = new IntProcedure() {
109        @Override
110        public void execute(int ker) throws ContradictionException {
111            assert ker < to - from;
112            set.addToKernel(ker + from, aCause);
113        }
114    };
115    private final IntProcedure pruneSetOnMaskedEnv = new IntProcedure() {
116        @Override
117        public void execute(int env) throws ContradictionException {
118            assert env < to - from;
119            set.removeFromEnvelope(env + from, aCause);
120        }
121    };
122
123    @Override
124    public ESat isEntailed() {
125        for (int i = set.getKernelFirst(); i != SetVar.END; i = set.getKernelNext()) {
126            if (i >= from && i < to && !masked.envelopeContains(i - from)) {
127                return ESat.FALSE;
128            }
129        }
130        for (int i = masked.getKernelFirst(); i != SetVar.END; i = masked.getKernelNext()) {
131            if (i < 0 || i >= to - from || !set.envelopeContains(i + from)) {
132                return ESat.FALSE;
133            }
134        }
135        return set.instantiated() && masked.instantiated() ? ESat.TRUE : ESat.UNDEFINED;
136    }
137
138    @Override
139    public String toString() {
140        return "mask(" + set + ", " + masked + ", " + from + ", " + to + ")";
141    }
142}