1 /* 2 * ArgMin.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.constraints; 32 33 import org.jacop.api.SatisfiedPresent; 34 import org.jacop.core.*; 35 36 import java.util.Arrays; 37 import java.util.List; 38 import java.util.concurrent.atomic.AtomicInteger; 39 import java.util.stream.Stream; 40 41 /** 42 * ArgMin constraint provides the index of the maximum 43 * variable from all variables on the list. 44 * 45 * @author Krzysztof Kuchcinski and Radoslaw Szymanek 46 * @version 4.8 47 */ 48 49 public class ArgMin extends Constraint implements SatisfiedPresent { 50 51 final static AtomicInteger idNumber = new AtomicInteger(0); 52 53 boolean firstConsistencyCheck = true; 54 55 /** 56 * It specifies a list of variables among which a maximum value is being searched for. 57 */ 58 final public IntVar list[]; 59 60 /** 61 * It specifies variable max which stores the maximum value present in the list. 62 */ 63 final public IntVar minIndex; 64 65 66 /** 67 * It specifies indexOffset within an element constraint list[index-indexOffset] = value. 68 */ 69 public int indexOffset; 70 71 /** 72 * It constructs max constraint. 73 * 74 * @param minIndex variable denoting the index of the maximum value 75 * @param list the array of variables for which the index of the maximum value is imposed. 76 * @param indexOffset the offset for the index that is computed from 1 by default (if needed from 0, use -1 for this parameter) 77 */ ArgMin(IntVar[] list, IntVar minIndex, int indexOffset)78 public ArgMin(IntVar[] list, IntVar minIndex, int indexOffset) { 79 80 this(list, minIndex); 81 this.indexOffset = indexOffset; 82 } 83 ArgMin(IntVar[] list, IntVar minIndex)84 public ArgMin(IntVar[] list, IntVar minIndex) { 85 86 checkInputForNullness(new String[] {"list", "minIndex"}, new Object[][] {list, {minIndex}}); 87 88 this.queueIndex = 1; 89 this.numberId = idNumber.incrementAndGet(); 90 this.indexOffset = 0; 91 this.minIndex = minIndex; 92 this.list = Arrays.copyOf(list, list.length); 93 94 setScope(Stream.concat(Stream.of(minIndex), Stream.of(list))); 95 } 96 97 /** 98 * It constructs max constraint. 99 * 100 * @param minIndex variable denoting the index of minimum value 101 * @param variables the array of variables for which the minimum value is imposed. 102 * @param indexOffset the offset for the index that is computed from 1 by default (if needed from 0, use -1 for this parameter) 103 */ ArgMin(List<? extends IntVar> variables, IntVar minIndex, int indexOffset)104 public ArgMin(List<? extends IntVar> variables, IntVar minIndex, int indexOffset) { 105 this(variables, minIndex); 106 this.indexOffset = indexOffset; 107 } 108 ArgMin(List<? extends IntVar> variables, IntVar minIndex)109 public ArgMin(List<? extends IntVar> variables, IntVar minIndex) { 110 111 this(variables.toArray(new IntVar[variables.size()]), minIndex); 112 113 } 114 consistency(Store store)115 @Override public void consistency(Store store) { 116 117 if (firstConsistencyCheck) { 118 minIndex.domain.in(store.level, minIndex, 1 + indexOffset, list.length + indexOffset); 119 firstConsistencyCheck = false; 120 } 121 122 int lb = IntDomain.MaxInt; 123 int ub = IntDomain.MaxInt; 124 int pos = -1; 125 126 // find lower/upper bounds for elements on list 127 for (int i = 0; i < list.length; i++) { 128 129 int vDomMin = list[i].dom().min(); 130 if (lb > vDomMin) { 131 lb = vDomMin; 132 } 133 134 int vDomMax = list[i].dom().max(); 135 if (ub > vDomMax) { 136 ub = vDomMax; 137 pos = i; 138 } 139 } 140 141 if (lb == ub) 142 minIndex.domain.inMax(store.level, minIndex, pos + 1 + indexOffset); 143 144 // find min/max values for index 145 IntervalDomain idxDomain = new IntervalDomain(); 146 for (int i = 0; i < list.length; i++) { 147 int cp = i + 1 + indexOffset; 148 149 if (list[i].min() <= ub) { 150 if (idxDomain.getSize() == 0) 151 idxDomain.unionAdapt(cp, cp); 152 else 153 idxDomain.addLastElement(cp); 154 } 155 } 156 if (idxDomain.isEmpty()) 157 throw Store.failException; 158 else 159 minIndex.domain.in(store.level, minIndex, idxDomain); 160 161 // find min value for variables indexed by index variable 162 lb = IntDomain.MaxInt; 163 pos = -1; 164 for (ValueEnumeration e = minIndex.dom().valueEnumeration(); e.hasMoreElements(); ) { 165 int i = e.nextElement() - 1 - indexOffset; 166 167 int vDomMin = list[i].dom().min(); 168 if (lb > vDomMin) { 169 lb = vDomMin; 170 pos = i; 171 } 172 } 173 if (list[pos].singleton()) 174 minIndex.domain.in(store.level, minIndex, pos + 1 + indexOffset, pos + 1 + indexOffset); 175 176 if (minIndex.singleton()) { 177 178 int idx = minIndex.value() - 1 - indexOffset; 179 IntVar y = list[idx]; 180 181 for (int i = 0; i < list.length; i++) { 182 183 // prune variables before and after index of max value 184 IntVar x = list[i]; 185 if (i < idx) { 186 // x > y 187 x.domain.inMin(store.level, x, y.min() + 1); 188 y.domain.inMax(store.level, y, x.max() - 1); 189 } 190 else { 191 // x >= y 192 x.domain.inMin(store.level, x, y.min()); 193 y.domain.inMax(store.level, y, x.max()); 194 } 195 } 196 } else { 197 // prune values on the list 198 int im = minIndex.min(); 199 for (int i = 0; i < list.length; i++) { 200 int cp = i + 1 + indexOffset; 201 202 if (cp < im) 203 list[i].domain.inMin(store.level, list[i], lb + 1); 204 else if (cp > im) 205 list[i].domain.inMin(store.level, list[i], lb); 206 } 207 } 208 209 // if (maxIndex.singleton() && list[maxIndex.value() - 1 - indexOffset].singleton()) 210 // removeConstraint(); 211 } 212 getDefaultConsistencyPruningEvent()213 @Override public int getDefaultConsistencyPruningEvent() { 214 return IntDomain.BOUND; 215 } 216 getConsistencyPruningEvent(Var var)217 @Override public int getConsistencyPruningEvent(Var var) { 218 219 // If consistency function mode 220 if (consistencyPruningEvents != null) { 221 Integer possibleEvent = consistencyPruningEvents.get(var); 222 if (possibleEvent != null) 223 return possibleEvent; 224 } 225 226 if (var == minIndex) 227 return IntDomain.ANY; 228 else { 229 return IntDomain.BOUND; 230 } 231 } 232 satisfied()233 @Override public boolean satisfied() { 234 235 boolean sat = minIndex.singleton(); 236 237 if (!sat) 238 return false; 239 240 int MIN = list[minIndex.value() - 1 - indexOffset].value(); 241 int i = 0, eq = 0; 242 while (sat && i < list.length) { 243 if (list[i].singleton() && list[i].value() >= MIN) 244 eq++; 245 sat = list[i].min() >= MIN; 246 i++; 247 } 248 249 return sat && eq == list.length; 250 } 251 toString()252 @Override public String toString() { 253 254 StringBuffer result = new StringBuffer(id()); 255 256 result.append(" : ArgMin( [ "); 257 for (int i = 0; i < list.length; i++) { 258 result.append(list[i]); 259 if (i < list.length - 1) 260 result.append(", "); 261 } 262 263 result.append("], ").append(this.minIndex); 264 result.append(", "+indexOffset+")"); 265 266 return result.toString(); 267 } 268 269 } 270