001package org.clafer.choco.constraint.propagator; 002 003import org.clafer.common.Util; 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 * 018 * @author jimmy 019 */ 020public class PropArrayToSet extends Propagator<Variable> { 021 022 private final IntVar[] as; 023 private final IIntDeltaMonitor[] asD; 024 private final SetVar s; 025 private final SetDeltaMonitor sD; 026 027 public PropArrayToSet(IntVar[] as, SetVar s) { 028 super(buildArray(as, s), PropagatorPriority.TERNARY, true); 029 if (as.length == 0) { 030 throw new IllegalArgumentException(); 031 } 032 this.as = as; 033 this.asD = PropUtil.monitorDeltas(as, aCause); 034 this.s = s; 035 this.sD = s.monitorDelta(aCause); 036 } 037 038 private static Variable[] buildArray(IntVar[] as, SetVar s) { 039 Variable[] array = new Variable[as.length + 1]; 040 array[0] = s; 041 System.arraycopy(as, 0, array, 1, as.length); 042 return array; 043 } 044 045 private boolean isAVar(int idx) { 046 return idx >= 1; 047 } 048 049 private int getAVarIndex(int idx) { 050 assert isAVar(idx); 051 return idx - 1; 052 } 053 054 private boolean isSVar(int idx) { 055 return idx == 0; 056 } 057 058 @Override 059 public int getPropagationConditions(int vIdx) { 060 if (isAVar(vIdx)) { 061 return EventType.INT_ALL_MASK(); 062 } 063 assert isSVar(vIdx); 064 return EventType.REMOVE_FROM_ENVELOPE.mask + EventType.ADD_TO_KER.mask; 065 } 066 067 private boolean findMate(int sEnv) throws ContradictionException { 068 assert s.envelopeContains(sEnv); 069 boolean inKer = s.kernelContains(sEnv); 070 int mate = -1; 071 for (int i = 0; i < as.length; i++) { 072 if (as[i].contains(sEnv)) { 073 // Found a second mate. 074 if (mate != -1 || !inKer) { 075 mate = -2; 076 break; 077 } 078 mate = i; 079 } 080 } 081 if (mate == -1) { 082 // No mates. 083 s.removeFromEnvelope(sEnv, aCause); 084 } else if (mate != -2 && inKer) { 085 // One mate. 086 return as[mate].instantiateTo(sEnv, aCause); 087 } 088 return false; 089 } 090 091 private void findMates() throws ContradictionException { 092 for (int i = s.getEnvelopeFirst(); i != SetVar.END; i = s.getEnvelopeNext()) { 093 if (findMate(i)) { 094 findMates(); 095 return; 096 } 097 } 098 } 099 100 @Override 101 public void propagate(int evtmask) throws ContradictionException { 102 // Prune as 103 for (IntVar a : as) { 104 PropUtil.domSubsetEnv(a, s, aCause); 105 } 106 // Prune s 107 findMates(); 108 // Pick s 109 for (IntVar a : as) { 110 if (a.instantiated()) { 111 s.addToKernel(a.getValue(), aCause); 112 } 113 } 114 } 115 116 @Override 117 public void propagate(int idxVarInProp, int mask) throws ContradictionException { 118 if (isSVar(idxVarInProp)) { 119 sD.freeze(); 120 sD.forEach(pruneAOnSEnv, EventType.REMOVE_FROM_ENVELOPE); 121 sD.forEach(pickAOnSEnv, EventType.ADD_TO_KER); 122 sD.unfreeze(); 123 } else { 124 assert isAVar(idxVarInProp); 125 126 int id = getAVarIndex(idxVarInProp); 127 if (EventType.isRemove(mask) 128 || (EventType.isInclow(mask) && as[id].getLB() > s.getEnvelopeFirst()) 129 || EventType.isDecupp(mask)) { 130 asD[id].freeze(); 131 asD[id].forEach(pruneSOnARem, EventType.REMOVE); 132 asD[id].unfreeze(); 133 } 134 if (as[id].instantiated()) { 135 s.addToKernel(as[id].getValue(), aCause); 136 } 137 } 138 } 139 private final IntProcedure pruneAOnSEnv = new IntProcedure() { 140 @Override 141 public void execute(int sEnv) throws ContradictionException { 142 for (IntVar a : as) { 143 if (a.removeValue(sEnv, aCause) && a.instantiated()) { 144 s.addToKernel(a.getValue(), aCause); 145 } 146 } 147 } 148 }; 149 private final IntProcedure pickAOnSEnv = new IntProcedure() { 150 @Override 151 public void execute(int sKer) throws ContradictionException { 152 if (findMate(sKer)) { 153 findMates(); 154 } 155 } 156 }; 157 private final IntProcedure pruneSOnARem = new IntProcedure() { 158 @Override 159 public void execute(int aRem) throws ContradictionException { 160 if (s.envelopeContains(aRem)) { 161 if (findMate(aRem)) { 162 findMates(); 163 } 164 } 165 } 166 }; 167 168 @Override 169 public ESat isEntailed() { 170 if (s.getKernelSize() > as.length) { 171 return ESat.FALSE; 172 } 173 for (IntVar a : as) { 174 if (!PropUtil.isDomIntersectEnv(a, s)) { 175 return ESat.FALSE; 176 } 177 } 178 for (int i = s.getKernelFirst(); i != SetVar.END; i = s.getKernelNext()) { 179 if (!PropUtil.domsContain(as, i)) { 180 return ESat.FALSE; 181 } 182 } 183 return isCompletelyInstantiated() ? ESat.TRUE : ESat.UNDEFINED; 184 } 185 186 @Override 187 public String toString() { 188 return "arrayToSet({" + Util.commaSeparate(as) + "} = " + s + ")"; 189 } 190}