this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2/* 3 * Main authors: 4 * Christian Schulte <schulte@gecode.org> 5 * 6 * Copyright: 7 * Christian Schulte, 2015 8 * 9 * This file is part of Gecode, the generic constraint 10 * development environment: 11 * http://www.gecode.org 12 * 13 * Permission is hereby granted, free of charge, to any person obtaining 14 * a copy of this software and associated documentation files (the 15 * "Software"), to deal in the Software without restriction, including 16 * without limitation the rights to use, copy, modify, merge, publish, 17 * distribute, sublicense, and/or sell copies of the Software, and to 18 * permit persons to whom the Software is furnished to do so, subject to 19 * the following conditions: 20 * 21 * The above copyright notice and this permission notice shall be 22 * included in all copies or substantial portions of the Software. 23 * 24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 28 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 29 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 31 * 32 */ 33 34#include <gecode/int/rel.hh> 35 36namespace Gecode { namespace Int { namespace Arithmetic { 37 38 template<class VA, class VB, bool tiebreak> 39 forceinline 40 ArgMax<VA,VB,tiebreak>::ArgMax(Home home, IdxViewArray<VA>& x0, VB y0) 41 : Propagator(home), x(x0), y(y0) { 42 x.subscribe(home,*this,PC_INT_BND); 43 y.subscribe(home,*this,PC_INT_DOM); 44 } 45 46 template<class VA, class VB, bool tiebreak> 47 ExecStatus 48 ArgMax<VA,VB,tiebreak>::post(Home home, IdxViewArray<VA>& x, VB y) { 49 assert(x.size() > 0); 50 if (x.size() == 1) { 51 GECODE_ME_CHECK(y.eq(home,x[0].idx)); 52 } else if (y.assigned()) { 53 int max=0; 54 while (x[max].idx < y.val()) 55 max++; 56 assert(x[max].idx == y.val()); 57 if (tiebreak) 58 for (int i=0; i<max; i++) 59 GECODE_ES_CHECK((Rel::Le<VA,VA>::post(home, 60 x[i].view,x[max].view))); 61 else 62 for (int i=0; i<max; i++) 63 GECODE_ES_CHECK((Rel::Lq<VA,VA>::post(home, 64 x[i].view,x[max].view))); 65 for (int i=max+1; i<x.size(); i++) 66 GECODE_ES_CHECK((Rel::Lq<VA,VA>::post(home, 67 x[i].view,x[max].view))); 68 } else { 69 (void) new (home) ArgMax<VA,VB,tiebreak>(home,x,y); 70 } 71 return ES_OK; 72 } 73 74 template<class VA, class VB, bool tiebreak> 75 forceinline 76 ArgMax<VA,VB,tiebreak>::ArgMax(Space& home, ArgMax<VA,VB,tiebreak>& p) 77 : Propagator(home,p) { 78 x.update(home,p.x); 79 y.update(home,p.y); 80 } 81 82 template<class VA, class VB, bool tiebreak> 83 Actor* 84 ArgMax<VA,VB,tiebreak>::copy(Space& home) { 85 return new (home) ArgMax<VA,VB,tiebreak>(home,*this); 86 } 87 88 template<class VA, class VB, bool tiebreak> 89 PropCost 90 ArgMax<VA,VB,tiebreak>::cost(const Space&, const ModEventDelta&) const { 91 return PropCost::linear(PropCost::LO,x.size()+1); 92 } 93 94 template<class VA, class VB, bool tiebreak> 95 void 96 ArgMax<VA,VB,tiebreak>::reschedule(Space& home) { 97 x.reschedule(home,*this,PC_INT_BND); 98 y.reschedule(home,*this,PC_INT_DOM); 99 } 100 101 template<class VA, class VB, bool tiebreak> 102 ExecStatus 103 ArgMax<VA,VB,tiebreak>::propagate(Space& home, const ModEventDelta&) { 104 /* 105 * A key invariant is as follows: for each value i in the domain 106 * of y there is an index-value pair with index i in x. 107 */ 108 109 // Compute lower and upper bounds for the maximum and its first position. 110 int p = x[0].idx; 111 int l = x[0].view.min(); 112 int u = x[0].view.max(); 113 for (int i=1; i<x.size(); i++) { 114 if (l < x[i].view.min()) { 115 p = x[i].idx; l = x[i].view.min(); 116 } 117 if (u < x[i].view.max()) 118 u = x[i].view.max(); 119 } 120 121 // Eliminate elements from x and y that are too small 122 { 123 Region r; 124 125 // Values to delete from y 126 int* d=r.alloc<int>(y.size()); 127 // Number of values to delete 128 int n = 0; 129 130 int i=0, j=0; 131 ViewValues<VB> iy(y); 132 133 while ((i < x.size()) && iy()) { 134 if (x[i].idx == iy.val()) { 135 if (x[i].view.max() < l) { 136 x[i].view.cancel(home,*this,PC_INT_BND); 137 d[n++]=x[i].idx; 138 } else { 139 x[j++]=x[i]; 140 } 141 ++iy; 142 } else { 143 assert(x[i].idx < iy.val()); 144 if (x[i].view.max() < l) { 145 x[i].view.cancel(home,*this,PC_INT_BND); 146 } else { 147 x[j++]=x[i]; 148 } 149 } 150 i++; 151 } 152 while (i < x.size()) 153 if (x[i].view.max() < l) { 154 x[i].view.cancel(home,*this,PC_INT_BND); i++; 155 } else { 156 x[j++]=x[i++]; 157 } 158 x.size(j); 159 160 if (static_cast<unsigned int>(n) == y.size()) 161 return ES_FAILED; 162 Iter::Values::Array id(d,n); 163 GECODE_ME_CHECK(y.minus_v(home,id,false)); 164 } 165 166 /* 167 * Now the following invariant holds: 168 * - for all q in y: u >= x(q).max() >= l 169 * - if l==u, then exists q in y: x(q).max = u 170 */ 171 172 if (tiebreak && (l == u)) 173 GECODE_ME_CHECK(y.lq(home,p)); 174 175 if (y.assigned()) { 176 int max=0; 177 while (x[max].idx < y.val()) 178 max++; 179 assert(x[max].idx == y.val()); 180 if (tiebreak) 181 for (int i=0; i<max; i++) 182 GECODE_ES_CHECK((Rel::Le<VA,VA>::post(home(*this), 183 x[i].view,x[max].view))); 184 else 185 for (int i=0; i<max; i++) 186 GECODE_ES_CHECK((Rel::Lq<VA,VA>::post(home(*this), 187 x[i].view,x[max].view))); 188 for (int i=max+1; i<x.size(); i++) 189 GECODE_ES_CHECK((Rel::Lq<VA,VA>::post(home(*this), 190 x[i].view,x[max].view))); 191 return home.ES_SUBSUMED(*this); 192 } 193 194 // Recompute the upper bound for elements in y 195 { 196 ViewValues<VB> iy(y); 197 int i=0; 198 // Skip smaller elements 199 while (x[i].idx < y.min()) 200 i++; 201 u=x[i].view.max(); 202 // Skip the minimal element 203 i++; ++iy; 204 while (iy()) { 205 if (x[i].idx == iy.val()) { 206 u = std::max(u,x[i].view.max()); 207 ++iy; 208 } else { 209 assert(x[i].idx < iy.val()); 210 } 211 i++; 212 } 213 } 214 215 // Constrain elements in x but not in y 216 { 217 int i = 0; 218 // Elements which must be smaller (for tiebreaking) 219 if (tiebreak) 220 while ((i < x.size()) && (x[i].idx < y.min())) { 221 GECODE_ME_CHECK(x[i].view.le(home,u)); 222 i++; 223 } 224 else 225 while ((i < x.size()) && (x[i].idx < y.min())) { 226 GECODE_ME_CHECK(x[i].view.lq(home,u)); 227 i++; 228 } 229 assert(x[i].idx == y.min()); 230 231 // Elements which cannot be larger 232 ViewValues<VB> iy(y); 233 // Skip the minimal element 234 i++; ++iy; 235 while ((i < x.size()) && iy()) { 236 if (x[i].idx == iy.val()) { 237 ++iy; 238 } else { 239 assert(x[i].idx < iy.val()); 240 GECODE_ME_CHECK(x[i].view.lq(home,u)); 241 } 242 i++; 243 } 244 while (i < x.size()) { 245 assert(x[i].idx > y.max()); 246 GECODE_ME_CHECK(x[i].view.lq(home,u)); 247 i++; 248 } 249 } 250 return tiebreak ? ES_NOFIX : ES_FIX; 251 } 252 253 template<class VA, class VB, bool tiebreak> 254 forceinline size_t 255 ArgMax<VA,VB,tiebreak>::dispose(Space& home) { 256 x.cancel(home,*this,PC_INT_BND); 257 y.cancel(home,*this,PC_INT_DOM); 258 (void) Propagator::dispose(home); 259 return sizeof(*this); 260 } 261 262}}} 263 264// STATISTICS: int-prop 265