this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
2/*
3 * Main authors:
4 * Guido Tack <tack@gecode.org>
5 *
6 * Copyright:
7 * Guido Tack, 2006
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/gist/spacenode.hh>
35#include <gecode/gist/visualnode.hh>
36#include <gecode/gist/stopbrancher.hh>
37#include <gecode/search.hh>
38#include <stack>
39
40#include <QString>
41#include <QVector>
42
43namespace Gecode { namespace Gist {
44
45 /// \brief Representation of a branch in the search tree
46 class Branch {
47 public:
48 /// Alternative number
49 int alternative;
50 /// The best space known when the branch was created
51 SpaceNode* ownBest;
52 const Choice* choice;
53
54 /// Constructor
55 Branch(int a, const Choice* c, SpaceNode* best = nullptr)
56 : alternative(a), ownBest(best) {
57 choice = c;
58 }
59 };
60
61 BestNode::BestNode(SpaceNode* s0) : s(s0) {}
62
63 int
64 SpaceNode::recompute(NodeAllocator& na,
65 BestNode* curBest, int c_d, int a_d) {
66 int rdist = 0;
67
68 if (copy == nullptr) {
69 SpaceNode* curNode = this;
70 SpaceNode* lastFixpoint = nullptr;
71
72 lastFixpoint = curNode;
73
74 std::stack<Branch> stck;
75
76 int idx = getIndex(na);
77 while (curNode->copy == nullptr) {
78 SpaceNode* parent = curNode->getParent(na);
79 int parentIdx = curNode->getParent();
80 int alternative = curNode->getAlternative(na);
81
82 SpaceNode* ownBest = na.best(idx);
83 Branch b(alternative, parent->choice,
84 curBest == nullptr ? nullptr : ownBest);
85 stck.push(b);
86
87 curNode = parent;
88 idx = parentIdx;
89 rdist++;
90 }
91
92 Space* curSpace;
93 if (Support::marked(curNode->copy)) {
94 curSpace = static_cast<Space*>(Support::unmark(curNode->copy));
95 curNode->copy = nullptr;
96 a_d = -1;
97 } else {
98 curSpace = curNode->copy->clone();
99 curNode->setDistance(0);
100 }
101
102 SpaceNode* lastBest = nullptr;
103 SpaceNode* middleNode = curNode;
104 int curDist = 0;
105
106 while (!stck.empty()) {
107 if (a_d >= 0 &&
108 curDist > a_d &&
109 curDist == rdist / 2) {
110 if (curSpace->status() == SS_FAILED) {
111 copy = static_cast<Space*>(Support::mark(curSpace));
112 return rdist;
113 } else {
114 middleNode->copy = curSpace->clone();
115 }
116 }
117 Branch b = stck.top(); stck.pop();
118
119 if(middleNode == lastFixpoint) {
120 curSpace->status();
121 }
122
123 curSpace->commit(*b.choice, b.alternative);
124
125 if (b.ownBest != nullptr && b.ownBest != lastBest) {
126 b.ownBest->acquireSpace(na,curBest, c_d, a_d);
127 Space* ownBestSpace =
128 static_cast<Space*>(Support::funmark(b.ownBest->copy));
129 if (ownBestSpace->status() != SS_SOLVED) {
130 // in the presence of weakly monotonic propagators, we may have to
131 // use search to find the solution here
132 ownBestSpace = Gecode::dfs(ownBestSpace);
133 if (Support::marked(b.ownBest->copy)) {
134 delete static_cast<Space*>(Support::unmark(b.ownBest->copy));
135 b.ownBest->copy =
136 static_cast<Space*>(Support::mark(ownBestSpace));
137 } else {
138 delete b.ownBest->copy;
139 b.ownBest->copy = ownBestSpace;
140 }
141 }
142 curSpace->constrain(*ownBestSpace);
143 lastBest = b.ownBest;
144 }
145 curDist++;
146 middleNode = middleNode->getChild(na,b.alternative);
147 middleNode->setDistance(curDist);
148 }
149 copy = static_cast<Space*>(Support::mark(curSpace));
150
151 }
152 return rdist;
153 }
154
155 void
156 SpaceNode::acquireSpace(NodeAllocator& na,
157 BestNode* curBest, int c_d, int a_d) {
158 SpaceNode* p = getParent(na);
159 int parentIdx = getParent();
160 int idx = getIndex(na);
161
162 if (getStatus() == UNDETERMINED && curBest != nullptr &&
163 na.best(idx) == nullptr &&
164 p != nullptr && curBest->s != na.best(parentIdx)) {
165 na.setBest(idx, curBest->s->getIndex(na));
166 }
167 SpaceNode* ownBest = na.best(idx);
168
169 if (copy == nullptr && p != nullptr && p->copy != nullptr &&
170 Support::marked(p->copy)) {
171 // If parent has a working space, steal it
172 copy = p->copy;
173 p->copy = nullptr;
174 if (p->choice != nullptr)
175 static_cast<Space*>(Support::unmark(copy))->
176 commit(*p->choice, getAlternative(na));
177
178 if (ownBest != nullptr) {
179 ownBest->acquireSpace(na,curBest, c_d, a_d);
180 Space* ownBestSpace =
181 static_cast<Space*>(Support::funmark(ownBest->copy));
182 if (ownBestSpace->status() != SS_SOLVED) {
183 // in the presence of weakly monotonic propagators, we may have to
184 // use search to find the solution here
185
186 ownBestSpace = Gecode::dfs(ownBestSpace);
187 if (Support::marked(ownBest->copy)) {
188 delete static_cast<Space*>(Support::unmark(ownBest->copy));
189 ownBest->copy =
190 static_cast<Space*>(Support::mark(ownBestSpace));
191 } else {
192 delete ownBest->copy;
193 ownBest->copy = ownBestSpace;
194 }
195 }
196 static_cast<Space*>(Support::unmark(copy))->constrain(*ownBestSpace);
197 }
198 int d = p->getDistance()+1;
199 if (d > c_d && c_d >= 0 &&
200 static_cast<Space*>(Support::unmark(copy))->status() == SS_BRANCH) {
201 copy = static_cast<Space*>(Support::unmark(copy));
202 d = 0;
203 }
204 setDistance(d);
205 }
206
207 if (copy == nullptr) {
208 if (recompute(na, curBest, c_d, a_d) > c_d && c_d >= 0 &&
209 static_cast<Space*>(Support::unmark(copy))->status() == SS_BRANCH) {
210 copy = static_cast<Space*>(Support::unmark(copy));
211 setDistance(0);
212 }
213 }
214
215 // always return a fixpoint
216 static_cast<Space*>(Support::funmark(copy))->status();
217 if (Support::marked(copy) && p != nullptr && isOpen() &&
218 p->copy != nullptr && p->getNoOfOpenChildren(na) == 1 &&
219 !p->isRoot()) {
220 // last alternative optimization
221
222 copy = static_cast<Space*>(Support::unmark(copy));
223 delete static_cast<Space*>(Support::funmark(p->copy));
224 p->copy = nullptr;
225 setDistance(0);
226 p->setDistance(p->getParent(na)->getDistance()+1);
227 }
228 }
229
230 void
231 SpaceNode::closeChild(const NodeAllocator& na,
232 bool hadFailures, bool hadSolutions) {
233 setHasFailedChildren(hasFailedChildren() || hadFailures);
234 setHasSolvedChildren(hasSolvedChildren() || hadSolutions);
235
236 bool allClosed = true;
237 for (int i=getNumberOfChildren(); i--;) {
238 if (getChild(na,i)->isOpen()) {
239 allClosed = false;
240 break;
241 }
242 }
243
244 if (allClosed) {
245 setHasOpenChildren(false);
246 for (unsigned int i=0; i<getNumberOfChildren(); i++)
247 setHasSolvedChildren(hasSolvedChildren() ||
248 getChild(na,i)->hasSolvedChildren());
249 SpaceNode* p = getParent(na);
250 if (p != nullptr) {
251 delete static_cast<Space*>(Support::funmark(copy));
252 copy = nullptr;
253 p->closeChild(na, hasFailedChildren(), hasSolvedChildren());
254 }
255 } else {
256
257 if (hadSolutions) {
258 setHasSolvedChildren(true);
259 SpaceNode* p = getParent(na);
260 while (p != nullptr && !p->hasSolvedChildren()) {
261 p->setHasSolvedChildren(true);
262 p = p->getParent(na);
263 }
264 }
265 if (hadFailures) {
266 SpaceNode* p = getParent(na);
267 while (p != nullptr && !p->hasFailedChildren()) {
268 p->setHasFailedChildren(true);
269 p = p->getParent(na);
270 }
271 }
272 }
273
274 }
275
276 SpaceNode::SpaceNode(Space* root)
277 : Node(-1, root==nullptr),
278 copy(root), choice(nullptr), nstatus(0) {
279 if (root == nullptr) {
280 setStatus(FAILED);
281 setHasSolvedChildren(false);
282 setHasFailedChildren(true);
283 } else {
284 setStatus(UNDETERMINED);
285 setHasSolvedChildren(false);
286 setHasFailedChildren(false);
287 }
288 }
289
290 void
291 SpaceNode::dispose(void) {
292 delete choice;
293 delete static_cast<Space*>(Support::funmark(copy));
294 }
295
296
297 int
298 SpaceNode::getNumberOfChildNodes(NodeAllocator& na,
299 BestNode* curBest, Statistics& stats,
300 int c_d, int a_d) {
301 int kids = 0;
302 if (isUndetermined()) {
303 stats.undetermined--;
304 acquireSpace(na, curBest, c_d, a_d);
305 QVector<QString> labels;
306 switch (static_cast<Space*>(Support::funmark(copy))->status(stats)) {
307 case SS_FAILED:
308 {
309 purge(na);
310 kids = 0;
311 setHasOpenChildren(false);
312 setHasSolvedChildren(false);
313 setHasFailedChildren(true);
314 setStatus(FAILED);
315 stats.failures++;
316 SpaceNode* p = getParent(na);
317 if (p != nullptr)
318 p->closeChild(na, true, false);
319 }
320 break;
321 case SS_SOLVED:
322 {
323 // Deletes all pending branchers
324 (void) static_cast<Space*>(Support::funmark(copy))->choice();
325 kids = 0;
326 setStatus(SOLVED);
327 setHasOpenChildren(false);
328 setHasSolvedChildren(true);
329 setHasFailedChildren(false);
330 stats.solutions++;
331 if (curBest != nullptr) {
332 curBest->s = this;
333 }
334 SpaceNode* p = getParent(na);
335 if (p != nullptr)
336 p->closeChild(na, false, true);
337 }
338 break;
339 case SS_BRANCH:
340 {
341 Space* s = static_cast<Space*>(Support::funmark(copy));
342 choice = s->choice();
343 kids = choice->alternatives();
344 setHasOpenChildren(true);
345 if (dynamic_cast<const StopChoice*>(choice)) {
346 setStatus(STOP);
347 } else {
348 setStatus(BRANCH);
349 stats.choices++;
350 }
351 stats.undetermined += kids;
352 for (int i=0; i<kids; i++) {
353 std::ostringstream oss;
354 s->print(*choice,i,oss);
355 labels.push_back(QString(oss.str().c_str()));
356 }
357 }
358 break;
359 }
360 static_cast<VisualNode*>(this)->changedStatus(na);
361 setNumberOfChildren(kids, na);
362 } else {
363 kids = getNumberOfChildren();
364 }
365 return kids;
366 }
367
368 int
369 SpaceNode::getNoOfOpenChildren(const NodeAllocator& na) {
370 if (!hasOpenChildren())
371 return 0;
372 int noOfOpenChildren = 0;
373 for (int i=getNumberOfChildren(); i--;)
374 noOfOpenChildren += (getChild(na,i)->isOpen());
375 return noOfOpenChildren;
376 }
377
378}}
379
380// STATISTICS: gist-any