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 * More efficient than the provided PropAllEqual. 014 * 015 * @author jimmy 016 */ 017public class PropSetEqual extends Propagator<SetVar> { 018 019 private final SetVar s1, s2; 020 private SetDeltaMonitor s1D, s2D; 021 022 public PropSetEqual(SetVar s1, SetVar s2) { 023 super(new SetVar[]{s1, s2}, PropagatorPriority.LINEAR, true); 024 this.s1 = s1; 025 this.s1D = s1.monitorDelta(aCause); 026 this.s2 = s2; 027 this.s2D = s2.monitorDelta(aCause); 028 } 029 030 private boolean isS1Var(int idx) { 031 return idx == 0; 032 } 033 034 private boolean isS2Var(int idx) { 035 return idx == 1; 036 } 037 038 @Override 039 public int getPropagationConditions(int vIdx) { 040 return EventType.ADD_TO_KER.mask + EventType.REMOVE_FROM_ENVELOPE.mask; 041 } 042 043 @Override 044 public void propagate(int evtmask) throws ContradictionException { 045 PropUtil.envSubsetEnv(s1, s2, aCause); 046 PropUtil.envSubsetEnv(s2, s1, aCause); 047 PropUtil.kerSubsetKer(s1, s2, aCause); 048 PropUtil.kerSubsetKer(s2, s1, aCause); 049 } 050 051 @Override 052 public void propagate(int idxVarInProp, int mask) throws ContradictionException { 053 if (isS1Var(idxVarInProp)) { 054 s1D.freeze(); 055 s1D.forEach(pruneS2OnS1Env, EventType.REMOVE_FROM_ENVELOPE); 056 s1D.forEach(pickS2OnS1Ker, EventType.ADD_TO_KER); 057 s1D.unfreeze(); 058 } else { 059 assert isS2Var(idxVarInProp); 060 s2D.freeze(); 061 s2D.forEach(pruneS1OnS2Env, EventType.REMOVE_FROM_ENVELOPE); 062 s2D.forEach(pickS1OnS2Ker, EventType.ADD_TO_KER); 063 s2D.unfreeze(); 064 } 065 } 066 private final IntProcedure pruneS2OnS1Env = new IntProcedure() { 067 @Override 068 public void execute(int s1Env) throws ContradictionException { 069 s2.removeFromEnvelope(s1Env, aCause); 070 } 071 }; 072 private final IntProcedure pickS2OnS1Ker = new IntProcedure() { 073 @Override 074 public void execute(int s1Ker) throws ContradictionException { 075 s2.addToKernel(s1Ker, aCause); 076 } 077 }; 078 private final IntProcedure pruneS1OnS2Env = new IntProcedure() { 079 @Override 080 public void execute(int s2Env) throws ContradictionException { 081 s1.removeFromEnvelope(s2Env, aCause); 082 } 083 }; 084 private final IntProcedure pickS1OnS2Ker = new IntProcedure() { 085 @Override 086 public void execute(int s2Ker) throws ContradictionException { 087 s1.addToKernel(s2Ker, aCause); 088 } 089 }; 090 091 @Override 092 public ESat isEntailed() { 093 if (!PropUtil.isKerSubsetEnv(s1, s2) || !PropUtil.isKerSubsetEnv(s2, s1)) { 094 return ESat.FALSE; 095 } 096 return s1.instantiated() && s2.instantiated() ? ESat.TRUE : ESat.UNDEFINED; 097 } 098 099 @Override 100 public String toString() { 101 return s1 + " = " + s2; 102 } 103}