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}