1 /* 2 * Match.java 3 * This file is part of JaCoP. 4 * <p> 5 * JaCoP is a Java Constraint Programming solver. 6 * <p> 7 * Copyright (C) 2000-2008 Krzysztof Kuchcinski and Radoslaw Szymanek 8 * <p> 9 * This program is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU Affero General Public License as published by 11 * the Free Software Foundation, either version 3 of the License, or 12 * (at your option) any later version. 13 * <p> 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Affero General Public License for more details. 18 * <p> 19 * Notwithstanding any other provision of this License, the copyright 20 * owners of this work supplement the terms of this License with terms 21 * prohibiting misrepresentation of the origin of this work and requiring 22 * that modified versions of this work be marked in reasonable ways as 23 * different from the original version. This supplement of the license 24 * terms is in accordance with Section 7 of GNU Affero General Public 25 * License version 3. 26 * <p> 27 * You should have received a copy of the GNU Affero General Public License 28 * along with this program. If not, see <http://www.gnu.org/licenses/>. 29 */ 30 31 package org.jacop.set.constraints; 32 33 import org.jacop.api.SatisfiedPresent; 34 import org.jacop.constraints.Constraint; 35 import org.jacop.core.*; 36 import org.jacop.set.core.SetDomain; 37 import org.jacop.set.core.SetVar; 38 39 import java.util.Arrays; 40 import java.util.concurrent.atomic.AtomicInteger; 41 import java.util.stream.Stream; 42 43 /** 44 * This constraint matches the elements of the given set variable 45 * onto a list of integer variables. 46 * 47 * @author Radoslaw Szymanek, Krzysztof Kuchcinski, and Robert Åkemalm 48 * @version 4.8 49 */ 50 51 public class Match extends Constraint implements SatisfiedPresent { 52 53 static AtomicInteger idNumber = new AtomicInteger(0); 54 55 /** 56 * It specifies a set variable whose values are being matched against integer variables 57 * from the list. 58 */ 59 public SetVar a; 60 61 /** 62 * It specifies the list of integer variables which value is being matched against 63 * elements from a set variable a. 64 */ 65 public IntVar[] list; 66 67 /** 68 * It constructs a match constraint to connect the value of set variable a 69 * to the values of integer variables provided in the list. 70 * 71 * @param a set variable that is restricted to be equal to a set created from values specified by integer variables form the list. 72 * @param list of integer variables that is restricted to have the same elements as set variable a. 73 */ 74 Match(SetVar a, IntVar[] list)75 public Match(SetVar a, IntVar[] list) { 76 77 checkInputForNullness(new String[] {"a", "list"}, new Object[][] {{a}, list}); 78 79 this.numberId = idNumber.incrementAndGet(); 80 this.a = a; 81 this.list = Arrays.copyOf(list, list.length); 82 83 setScope(Stream.concat(Stream.of(a), Arrays.stream(list))); 84 85 } 86 consistency(Store store)87 @Override public void consistency(Store store) { 88 89 /** 90 * It specifies the consistency rules for constraint 91 * match(list, a) where list is a list of intVar and a is a setVar. 92 * 93 * list is lexicographically ordered elements of a. 94 * 95 * [a, b, c, e, f] = {a, b, c, e, f} 96 * 97 * #A = list.length 98 * 99 * each element el in A.glb must occurr in one of the intvar in list. 100 * elPos is lexicographical position of el in A.glb 101 * 102 * element el can only occur within an interval of intvars list[elPos]..list[list.length - (#A.glb-elPos)] 103 * 104 * every element elU in A.lub that is not in A.glb can if added to glb will end up at position posElU 105 * and for this element we can also say that it can only occur in list[posElU]..list[list.length - (1+#A.glb-posElU)] 106 * 107 * for all l[i], D(l[i]) must be in A.lub 108 * 109 * A.lub = A.lub /\ ( \/ D(i) ). 110 * 111 */ 112 113 a.domain.inCardinality(store.level, a, list.length, list.length); 114 115 if (a.domain.glb().getSize() == list.length) { 116 117 ValueEnumeration ve = a.domain.glb().valueEnumeration(); 118 int el; 119 for (int i = 0; i < list.length; i++) { 120 el = ve.nextElement(); 121 list[i].domain.in(store.level, list[i], el, el); 122 } 123 a.domain.inLUB(store.level, a, a.domain.glb()); 124 125 } else if (a.domain.lub().getSize() == list.length) { 126 127 ValueEnumeration ve = a.domain.lub().valueEnumeration(); 128 int el; 129 for (int i = 0; i < list.length; i++) { 130 el = ve.nextElement(); 131 list[i].domain.in(store.level, list[i], el, el); 132 } 133 a.domain.inGLB(store.level, a, a.domain.lub()); 134 135 } else { 136 137 IntDomain glbA = a.domain.glb(); 138 IntDomain lubA = a.domain.lub(); 139 140 int sizeOfaGLB = glbA.getSize(); 141 int sizeOfaLUB = lubA.getSize(); 142 143 // glbA, lubA => list[i] 144 for (int i = 0; i < list.length; i++) { 145 146 list[i].domain.in(store.level, list[i], lubA); 147 148 int minValue = lubA.getElementAt(i); 149 150 if (i >= list.length - sizeOfaGLB) { 151 // -1 since indexing of arrays starts from 0. 152 int minValueFromGLB = glbA.getElementAt(sizeOfaGLB - list.length + i); 153 if (minValueFromGLB > minValue) 154 minValue = minValueFromGLB; 155 } 156 157 list[i].domain.inMin(store.level, list[i], minValue); 158 159 int maxValue = lubA.getElementAt(sizeOfaLUB - list.length + i); 160 161 if (i < sizeOfaGLB) { 162 int maxValueFromGLB = glbA.getElementAt(i); 163 if (maxValueFromGLB < maxValue) 164 maxValue = maxValueFromGLB; 165 } 166 167 list[i].domain.inMax(store.level, list[i], maxValue); 168 169 } 170 171 IntDomain lubFromList = list[0].domain.cloneLight(); 172 for (int i = 0; i < list.length; i++) { 173 if (list[i].singleton()) 174 a.domain.inGLB(store.level, a, list[i].value()); 175 if (i > 0) 176 lubFromList.unionAdapt(list[i].domain); 177 } 178 a.domain.inLUB(store.level, a, lubFromList); 179 180 } 181 182 } 183 getConsistencyPruningEvent(Var var)184 @Override public int getConsistencyPruningEvent(Var var) { 185 186 // If consistency function mode 187 if (consistencyPruningEvents != null) { 188 Integer possibleEvent = consistencyPruningEvents.get(var); 189 if (possibleEvent != null) 190 return possibleEvent; 191 } 192 193 if (var == a) 194 return SetDomain.ANY; 195 else 196 return IntDomain.ANY; 197 } 198 getDefaultConsistencyPruningEvent()199 @Override public int getDefaultConsistencyPruningEvent() { 200 throw new IllegalStateException("Not implemented as more precise version exist."); 201 } 202 satisfied()203 @Override public boolean satisfied() { 204 205 if (!grounded()) 206 return false; 207 208 if (a.domain.glb().getSize() == list.length) { 209 210 ValueEnumeration ve = a.domain.glb().valueEnumeration(); 211 212 for (int i = 0; i < list.length; i++) { 213 if (ve.nextElement() != list[i].value()) 214 return false; 215 } 216 217 return true; 218 219 } else { 220 return false; 221 } 222 223 } 224 toString()225 @Override public String toString() { 226 227 StringBuffer ret = new StringBuffer(id()); 228 ret.append(" : Match(" + a + ", [ "); 229 for (Var fdv : list) 230 ret.append(fdv + " "); 231 ret.append("] )"); 232 return ret.toString(); 233 234 } 235 236 } 237