001package org.clafer.choco.constraint.propagator; 002 003import java.util.Arrays; 004import solver.constraints.Propagator; 005import solver.constraints.PropagatorPriority; 006import solver.exception.ContradictionException; 007import solver.variables.EventType; 008import solver.variables.IntVar; 009import solver.variables.SetVar; 010import solver.variables.Variable; 011import solver.variables.delta.IIntDeltaMonitor; 012import solver.variables.delta.monitor.SetDeltaMonitor; 013import util.ESat; 014import util.procedure.IntProcedure; 015 016/** 017 * An idempotent and more efficient propagator than the default one. Does not 018 * require an supplementary disjoint propagator like the default one. 019 * 020 * @author jimmy 021 */ 022public class PropIntChannel extends Propagator<Variable> { 023 024 private final SetVar[] sets; 025 private SetDeltaMonitor[] setsD; 026 private final IntVar[] ints; 027 private IIntDeltaMonitor[] intsD; 028 029 public PropIntChannel(SetVar[] sets, IntVar[] ints) { 030 super(buildArray(sets, ints), PropagatorPriority.LINEAR, true); 031 this.sets = sets; 032 this.setsD = PropUtil.monitorDeltas(sets, aCause); 033 this.ints = ints; 034 this.intsD = PropUtil.monitorDeltas(ints, aCause); 035 } 036 037 private static Variable[] buildArray(SetVar[] sets, IntVar[] ints) { 038 Variable[] vars = new Variable[sets.length + ints.length]; 039 System.arraycopy(sets, 0, vars, 0, sets.length); 040 System.arraycopy(ints, 0, vars, sets.length, ints.length); 041 return vars; 042 } 043 044 private boolean isSetVar(int idx) { 045 return idx < sets.length; 046 } 047 048 private int getSetVarIndex(int idx) { 049 assert isSetVar(idx); 050 return idx; 051 } 052 053 private boolean isIntVar(int idx) { 054 return idx >= sets.length; 055 } 056 057 private int getIntVarIndex(int idx) { 058 assert isIntVar(idx); 059 return idx - sets.length; 060 } 061 062 @Override 063 public int getPropagationConditions(int vIdx) { 064 if (isSetVar(vIdx)) { 065 return EventType.ADD_TO_KER.mask + EventType.REMOVE_FROM_ENVELOPE.mask; 066 } 067 assert isIntVar(vIdx); 068 return EventType.INT_ALL_MASK(); 069 } 070 071 @Override 072 public void propagate(int evtmask) throws ContradictionException { 073 for (int i = 0; i < ints.length; i++) { 074 int ub = ints[i].getUB(); 075 for (int j = ints[i].getLB(); j <= ub; j = ints[i].nextValue(j)) { 076 if (j < 0 || j >= sets.length || !sets[j].envelopeContains(i)) { 077 ints[i].removeValue(j, aCause); 078 } 079 } 080 if (ints[i].instantiated()) { 081 sets[ints[i].getValue()].addToKernel(i, aCause); 082 } 083 } 084 for (int i = 0; i < sets.length; i++) { 085 for (int j = sets[i].getEnvelopeFirst(); j != SetVar.END; j = sets[i].getEnvelopeNext()) { 086 if (j < 0 || j >= ints.length || !ints[j].contains(i)) { 087 sets[i].removeFromEnvelope(j, aCause); 088 } 089 } 090 } 091 for (int i = 0; i < sets.length; i++) { 092 for (int j = sets[i].getKernelFirst(); j != SetVar.END; j = sets[i].getKernelNext()) { 093 ints[j].instantiateTo(i, aCause); 094 } 095 } 096 } 097 098 @Override 099 public void propagate(final int idxVarInProp, final int mask) throws ContradictionException { 100 if (isSetVar(idxVarInProp)) { 101 final int id = getSetVarIndex(idxVarInProp); 102 103 setsD[id].freeze(); 104 setsD[id].forEach(new IntProcedure() { 105 @Override 106 public void execute(int setKer) throws ContradictionException { 107 ints[setKer].instantiateTo(id, aCause); 108 for (int i = 0; i < sets.length; i++) { 109 if (i != id) { 110 sets[i].removeFromEnvelope(setKer, aCause); 111 } 112 } 113 } 114 }, EventType.ADD_TO_KER); 115 setsD[id].forEach(new IntProcedure() { 116 @Override 117 public void execute(int setEnv) throws ContradictionException { 118 if (ints[setEnv].removeValue(id, aCause) && ints[setEnv].instantiated()) { 119 int val = ints[setEnv].getValue(); 120 sets[val].addToKernel(setEnv, aCause); 121 for (int i = 0; i < sets.length; i++) { 122 if (i != val) { 123 sets[i].removeFromEnvelope(setEnv, aCause); 124 } 125 } 126 } 127 } 128 }, EventType.REMOVE_FROM_ENVELOPE); 129 setsD[id].unfreeze(); 130 } else { 131 assert isIntVar(idxVarInProp); 132 final int id = getIntVarIndex(idxVarInProp); 133 134 intsD[id].freeze(); 135 intsD[id].forEach(new IntProcedure() { 136 @Override 137 public void execute(int intRem) throws ContradictionException { 138 sets[intRem].removeFromEnvelope(id, aCause); 139 } 140 }, EventType.REMOVE); 141 if (ints[id].instantiated()) { 142 sets[ints[id].getValue()].addToKernel(id, aCause); 143 } 144 intsD[id].unfreeze(); 145 } 146 } 147 148 @Override 149 public ESat isEntailed() { 150 for (int i = 0; i < ints.length; i++) { 151 if (ints[i].instantiated()) { 152 int value = ints[i].getValue(); 153 if (value < 0 || value >= sets.length || !sets[value].envelopeContains(i)) { 154 return ESat.FALSE; 155 } 156 } 157 } 158 for (int i = 0; i < sets.length; i++) { 159 for (int j = sets[i].getKernelFirst(); j != SetVar.END; j = sets[i].getKernelNext()) { 160 if (j < 0 || j >= ints.length || !ints[j].contains(i)) { 161 return ESat.FALSE; 162 } 163 } 164 } 165 return isCompletelyInstantiated() ? ESat.TRUE : ESat.UNDEFINED; 166 } 167 168 @Override 169 public String toString() { 170 return "intChannel(" + Arrays.toString(sets) + ", " + Arrays.toString(ints) + ")"; 171 } 172}