set-expr.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 00002 /* 00003 * Main authors: 00004 * Guido Tack <tack@gecode.org> 00005 * Christian Schulte <schulte@gecode.org> 00006 * 00007 * Copyright: 00008 * Guido Tack, 2010 00009 * Christian Schulte, 2004 00010 * 00011 * Last modified: 00012 * $Date: 2011-01-21 16:01:14 +0100 (Fri, 21 Jan 2011) $ by $Author: schulte $ 00013 * $Revision: 11553 $ 00014 * 00015 * This file is part of Gecode, the generic constraint 00016 * development environment: 00017 * http://www.gecode.org 00018 * 00019 * Permission is hereby granted, free of charge, to any person obtaining 00020 * a copy of this software and associated documentation files (the 00021 * "Software"), to deal in the Software without restriction, including 00022 * without limitation the rights to use, copy, modify, merge, publish, 00023 * distribute, sublicense, and/or sell copies of the Software, and to 00024 * permit persons to whom the Software is furnished to do so, subject to 00025 * the following conditions: 00026 * 00027 * The above copyright notice and this permission notice shall be 00028 * included in all copies or substantial portions of the Software. 00029 * 00030 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 00031 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00032 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 00033 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 00034 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 00035 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00036 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00037 * 00038 */ 00039 00040 #include <gecode/minimodel.hh> 00041 00042 #ifdef GECODE_HAS_SET_VARS 00043 00044 namespace Gecode { 00045 00046 /* 00047 * Operations for nodes 00048 * 00049 */ 00050 bool 00051 SetExpr::Node::decrement(void) { 00052 if (--use == 0) { 00053 if ((l != NULL) && l->decrement()) 00054 delete l; 00055 if ((r != NULL) && r->decrement()) 00056 delete r; 00057 return true; 00058 } 00059 return false; 00060 } 00061 00062 00063 SetExpr::SetExpr(const SetVar& x) : n(new Node) { 00064 n->same = 1; 00065 n->t = NT_VAR; 00066 n->l = NULL; 00067 n->r = NULL; 00068 n->x = x; 00069 } 00070 00071 SetExpr::SetExpr(const IntSet& s) : n(new Node) { 00072 n->same = 1; 00073 n->t = NT_CONST; 00074 n->l = NULL; 00075 n->r = NULL; 00076 n->s = s; 00077 } 00078 00079 SetExpr::SetExpr(const LinExpr& e) : n(new Node) { 00080 n->same = 1; 00081 n->t = NT_LEXP; 00082 n->l = NULL; 00083 n->r = NULL; 00084 n->e = e; 00085 } 00086 00087 SetExpr::SetExpr(const SetExpr& l, NodeType t, const SetExpr& r) 00088 : n(new Node) { 00089 int ls = same(t,l.n->t) ? l.n->same : 1; 00090 int rs = same(t,r.n->t) ? r.n->same : 1; 00091 n->same = ls+rs; 00092 n->t = t; 00093 n->l = l.n; 00094 n->l->use++; 00095 n->r = r.n; 00096 n->r->use++; 00097 } 00098 00099 SetExpr::SetExpr(const SetExpr& l, NodeType t) { 00100 (void) t; 00101 assert(t == NT_CMPL); 00102 if (l.n->t == NT_CMPL) { 00103 n = l.n->l; 00104 n->use++; 00105 } else { 00106 n = new Node; 00107 n->same = 1; 00108 n->t = NT_CMPL; 00109 n->l = l.n; 00110 n->l->use++; 00111 n->r = NULL; 00112 } 00113 } 00114 00115 const SetExpr& 00116 SetExpr::operator =(const SetExpr& e) { 00117 if (this != &e) { 00118 if (n != NULL && n->decrement()) 00119 delete n; 00120 n = e.n; 00121 n->use++; 00122 } 00123 return *this; 00124 } 00125 00126 SetExpr::~SetExpr(void) { 00127 if (n != NULL && n->decrement()) 00128 delete n; 00129 } 00130 00131 /* 00132 * Operations for negation normalform 00133 * 00134 */ 00135 forceinline void 00136 SetExpr::NNF::operator delete(void*) {} 00137 00138 forceinline void 00139 SetExpr::NNF::operator delete(void*, Region&) {} 00140 00141 forceinline void* 00142 SetExpr::NNF::operator new(size_t s, Region& r) { 00143 return r.ralloc(s); 00144 } 00145 00146 void 00147 SetExpr::NNF::post(Home home, SetRelType srt, SetVar s) const { 00148 switch (t) { 00149 case NT_VAR: 00150 if (neg) { 00151 switch (srt) { 00152 case SRT_EQ: 00153 rel(home, u.a.x->x, SRT_CMPL, s); 00154 break; 00155 case SRT_CMPL: 00156 rel(home, u.a.x->x, SRT_EQ, s); 00157 break; 00158 default: 00159 SetVar bc(home,IntSet::empty, 00160 IntSet(Set::Limits::min,Set::Limits::max)); 00161 rel(home, s, SRT_CMPL, bc); 00162 rel(home, u.a.x->x, srt, bc); 00163 break; 00164 } 00165 } else 00166 rel(home, u.a.x->x, srt, s); 00167 break; 00168 case NT_CONST: 00169 { 00170 IntSet ss; 00171 if (neg) { 00172 IntSetRanges sr(u.a.x->s); 00173 Set::RangesCompl<IntSetRanges> src(sr); 00174 ss = IntSet(src); 00175 } else { 00176 ss = u.a.x->s; 00177 } 00178 switch (srt) { 00179 case SRT_SUB: srt = SRT_SUP; break; 00180 case SRT_SUP: srt = SRT_SUB; break; 00181 default: break; 00182 } 00183 dom(home, s, srt, ss); 00184 } 00185 break; 00186 case NT_LEXP: 00187 { 00188 IntVar iv = u.a.x->e.post(home,ICL_DEF); 00189 if (neg) { 00190 SetVar ic(home,IntSet::empty, 00191 IntSet(Set::Limits::min,Set::Limits::max)); 00192 rel(home, iv, SRT_CMPL, ic); 00193 rel(home,ic,srt,s); 00194 } else { 00195 rel(home,iv,srt,s); 00196 } 00197 } 00198 break; 00199 case NT_INTER: 00200 { 00201 SetVarArgs bs(p+n); 00202 int i=0; 00203 post(home, NT_INTER, bs, i); 00204 if (i == 2) { 00205 rel(home, bs[0], SOT_INTER, bs[1], srt, s); 00206 } else { 00207 if (srt == SRT_EQ) 00208 rel(home, SOT_INTER, bs, s); 00209 else { 00210 SetVar bc(home,IntSet::empty, 00211 IntSet(Set::Limits::min,Set::Limits::max)); 00212 rel(home, SOT_INTER, bs, bc); 00213 rel(home, bc, srt, s); 00214 } 00215 } 00216 } 00217 break; 00218 case NT_UNION: 00219 { 00220 SetVarArgs bs(p+n); 00221 int i=0; 00222 post(home, NT_UNION, bs, i); 00223 if (i == 2) { 00224 rel(home, bs[0], SOT_UNION, bs[1], srt, s); 00225 } else { 00226 if (srt == SRT_EQ) 00227 rel(home, SOT_UNION, bs, s); 00228 else { 00229 SetVar bc(home,IntSet::empty, 00230 IntSet(Set::Limits::min,Set::Limits::max)); 00231 rel(home, SOT_UNION, bs, bc); 00232 rel(home, bc, srt, s); 00233 } 00234 } 00235 } 00236 break; 00237 case NT_DUNION: 00238 { 00239 SetVarArgs bs(p+n); 00240 int i=0; 00241 post(home, NT_DUNION, bs, i); 00242 00243 if (i == 2) { 00244 if (neg) { 00245 if (srt == SRT_CMPL) { 00246 rel(home, bs[0], SOT_DUNION, bs[1], srt, s); 00247 } else { 00248 SetVar bc(home,IntSet::empty, 00249 IntSet(Set::Limits::min,Set::Limits::max)); 00250 rel(home,s,SRT_CMPL,bc); 00251 rel(home, bs[0], SOT_DUNION, bs[1], srt, bc); 00252 } 00253 } else { 00254 rel(home, bs[0], SOT_DUNION, bs[1], srt, s); 00255 } 00256 } else { 00257 if (neg) { 00258 if (srt == SRT_CMPL) { 00259 rel(home, SOT_DUNION, bs, s); 00260 } else { 00261 SetVar br(home,IntSet::empty, 00262 IntSet(Set::Limits::min,Set::Limits::max)); 00263 rel(home, SOT_DUNION, bs, br); 00264 if (srt == SRT_EQ) 00265 rel(home, br, SRT_CMPL, s); 00266 else { 00267 SetVar bc(home,IntSet::empty, 00268 IntSet(Set::Limits::min,Set::Limits::max)); 00269 rel(home, br, srt, bc); 00270 rel(home, bc, SRT_CMPL, s); 00271 } 00272 } 00273 } else { 00274 if (srt == SRT_EQ) 00275 rel(home, SOT_DUNION, bs, s); 00276 else { 00277 SetVar br(home,IntSet::empty, 00278 IntSet(Set::Limits::min,Set::Limits::max)); 00279 rel(home, SOT_DUNION, bs, br); 00280 rel(home, br, srt, s); 00281 } 00282 } 00283 } 00284 } 00285 break; 00286 default: 00287 GECODE_NEVER; 00288 } 00289 } 00290 00291 void 00292 SetExpr::NNF::post(Home home, SetRelType srt, SetVar s, BoolVar b) const { 00293 switch (t) { 00294 case NT_VAR: 00295 if (neg) { 00296 switch (srt) { 00297 case SRT_EQ: 00298 rel(home, u.a.x->x, SRT_CMPL, s, b); 00299 break; 00300 case SRT_CMPL: 00301 rel(home, u.a.x->x, SRT_EQ, s, b); 00302 break; 00303 default: 00304 SetVar bc(home,IntSet::empty, 00305 IntSet(Set::Limits::min,Set::Limits::max)); 00306 rel(home, s, SRT_CMPL, bc); 00307 rel(home, u.a.x->x, srt, bc, b); 00308 break; 00309 } 00310 } else 00311 rel(home, u.a.x->x, srt, s, b); 00312 break; 00313 case NT_CONST: 00314 { 00315 IntSet ss; 00316 if (neg) { 00317 IntSetRanges sr(u.a.x->s); 00318 Set::RangesCompl<IntSetRanges> src(sr); 00319 ss = IntSet(src); 00320 } else { 00321 ss = u.a.x->s; 00322 } 00323 dom(home, s, srt, ss, b); 00324 } 00325 break; 00326 case NT_LEXP: 00327 { 00328 IntVar iv = u.a.x->e.post(home,ICL_DEF); 00329 if (neg) { 00330 SetVar ic(home,IntSet::empty, 00331 IntSet(Set::Limits::min,Set::Limits::max)); 00332 rel(home, iv, SRT_CMPL, ic); 00333 rel(home,ic,srt,s,b); 00334 } else { 00335 rel(home,iv,srt,s,b); 00336 } 00337 } 00338 case NT_INTER: 00339 { 00340 SetVarArgs bs(p+n); 00341 int i=0; 00342 post(home, NT_INTER, bs, i); 00343 SetVar br(home,IntSet::empty, 00344 IntSet(Set::Limits::min,Set::Limits::max)); 00345 rel(home, SOT_INTER, bs, br); 00346 rel(home, br, srt, s, b); 00347 } 00348 break; 00349 case NT_UNION: 00350 { 00351 SetVarArgs bs(p+n); 00352 int i=0; 00353 post(home, NT_UNION, bs, i); 00354 SetVar br(home,IntSet::empty, 00355 IntSet(Set::Limits::min,Set::Limits::max)); 00356 rel(home, SOT_UNION, bs, br); 00357 rel(home, br, srt, s, b); 00358 } 00359 break; 00360 case NT_DUNION: 00361 { 00362 SetVarArgs bs(p+n); 00363 int i=0; 00364 post(home, NT_DUNION, bs, i); 00365 00366 if (neg) { 00367 SetVar br(home,IntSet::empty, 00368 IntSet(Set::Limits::min,Set::Limits::max)); 00369 rel(home, SOT_DUNION, bs, br); 00370 if (srt == SRT_CMPL) 00371 rel(home, br, SRT_EQ, s, b); 00372 else if (srt == SRT_EQ) 00373 rel(home, br, SRT_CMPL, s, b); 00374 else { 00375 SetVar bc(home,IntSet::empty, 00376 IntSet(Set::Limits::min,Set::Limits::max)); 00377 rel(home, br, srt, bc); 00378 rel(home, bc, SRT_CMPL, s, b); 00379 } 00380 } else { 00381 SetVar br(home,IntSet::empty, 00382 IntSet(Set::Limits::min,Set::Limits::max)); 00383 rel(home, SOT_DUNION, bs, br); 00384 rel(home, br, srt, s, b); 00385 } 00386 } 00387 break; 00388 default: 00389 GECODE_NEVER; 00390 } 00391 } 00392 00393 void 00394 SetExpr::NNF::post(Home home, NodeType t, 00395 SetVarArgs& b, int& i) const { 00396 if (this->t != t) { 00397 switch (this->t) { 00398 case NT_VAR: 00399 if (neg) { 00400 SetVar xc(home,IntSet::empty, 00401 IntSet(Set::Limits::min,Set::Limits::max)); 00402 rel(home, xc, SRT_CMPL, u.a.x->x); 00403 b[i++]=xc; 00404 } else { 00405 b[i++]=u.a.x->x; 00406 } 00407 break; 00408 default: 00409 { 00410 SetVar s(home,IntSet::empty, 00411 IntSet(Set::Limits::min,Set::Limits::max)); 00412 post(home,SRT_EQ,s); 00413 b[i++] = s; 00414 } 00415 break; 00416 } 00417 } else { 00418 u.b.l->post(home, t, b, i); 00419 u.b.r->post(home, t, b, i); 00420 } 00421 } 00422 00423 void 00424 SetExpr::NNF::post(Home home, SetRelType srt, const NNF* n) const { 00425 if (n->t == NT_VAR && !n->neg) { 00426 post(home,srt,n->u.a.x->x); 00427 } else if (t == NT_VAR && !neg) { 00428 SetRelType n_srt; 00429 switch (srt) { 00430 case SRT_SUB: n_srt = SRT_SUP; break; 00431 case SRT_SUP: n_srt = SRT_SUB; break; 00432 default: n_srt = srt; 00433 } 00434 n->post(home,n_srt,this); 00435 } else { 00436 SetVar nx(home,IntSet::empty, 00437 IntSet(Set::Limits::min,Set::Limits::max)); 00438 n->post(home,SRT_EQ,nx); 00439 post(home,srt,nx); 00440 } 00441 } 00442 00443 void 00444 SetExpr::NNF::post(Home home, BoolVar b, bool t, 00445 SetRelType srt, const NNF* n) const { 00446 if (t) { 00447 if (n->t == NT_VAR && !n->neg) { 00448 post(home,srt,n->u.a.x->x,b); 00449 } else if (t == NT_VAR && !neg) { 00450 SetRelType n_srt; 00451 switch (srt) { 00452 case SRT_SUB: n_srt = SRT_SUP; break; 00453 case SRT_SUP: n_srt = SRT_SUB; break; 00454 default: n_srt = srt; 00455 } 00456 n->post(home,b,true,n_srt,this); 00457 } else { 00458 SetVar nx(home,IntSet::empty, 00459 IntSet(Set::Limits::min,Set::Limits::max)); 00460 n->post(home,SRT_EQ,nx); 00461 post(home,srt,nx,b); 00462 } 00463 } else if (srt == SRT_EQ) { 00464 post(home,b,true,SRT_NQ,n); 00465 } else if (srt == SRT_NQ) { 00466 post(home,b,true,SRT_EQ,n); 00467 } else { 00468 BoolVar nb(home,0,1); 00469 rel(home,b,IRT_NQ,nb); 00470 post(home,nb,true,srt,n); 00471 } 00472 } 00473 00474 SetExpr::NNF* 00475 SetExpr::NNF::nnf(Region& r, Node* n, bool neg) { 00476 switch (n->t) { 00477 case NT_VAR: case NT_CONST: case NT_LEXP: 00478 { 00479 NNF* x = new (r) NNF; 00480 x->t = n->t; x->neg = neg; x->u.a.x = n; 00481 if (neg) { 00482 x->p = 0; x->n = 1; 00483 } else { 00484 x->p = 1; x->n = 0; 00485 } 00486 return x; 00487 } 00488 case NT_CMPL: 00489 return nnf(r,n->l,!neg); 00490 case NT_INTER: case NT_UNION: case NT_DUNION: 00491 { 00492 NodeType t; bool xneg; 00493 if (n->t == NT_DUNION) { 00494 t = n->t; xneg = neg; neg = false; 00495 } else { 00496 t = ((n->t == NT_INTER) == neg) ? NT_UNION : NT_INTER; 00497 xneg = false; 00498 } 00499 NNF* x = new (r) NNF; 00500 x->neg = xneg; 00501 x->t = t; 00502 x->u.b.l = nnf(r,n->l,neg); 00503 x->u.b.r = nnf(r,n->r,neg); 00504 int p_l, n_l; 00505 if ((x->u.b.l->t == t) || (x->u.b.l->t == NT_VAR)) { 00506 p_l=x->u.b.l->p; n_l=x->u.b.l->n; 00507 } else { 00508 p_l=1; n_l=0; 00509 } 00510 int p_r, n_r; 00511 if ((x->u.b.r->t == t) || (x->u.b.r->t == NT_VAR)) { 00512 p_r=x->u.b.r->p; n_r=x->u.b.r->n; 00513 } else { 00514 p_r=1; n_r=0; 00515 } 00516 x->p = p_l+p_r; 00517 x->n = n_l+n_r; 00518 return x; 00519 } 00520 default: 00521 GECODE_NEVER; 00522 } 00523 GECODE_NEVER; 00524 return NULL; 00525 } 00526 00527 00528 SetExpr 00529 operator &(const SetExpr& l, const SetExpr& r) { 00530 return SetExpr(l,SetExpr::NT_INTER,r); 00531 } 00532 SetExpr 00533 operator |(const SetExpr& l, const SetExpr& r) { 00534 return SetExpr(l,SetExpr::NT_UNION,r); 00535 } 00536 SetExpr 00537 operator +(const SetExpr& l, const SetExpr& r) { 00538 return SetExpr(l,SetExpr::NT_DUNION,r); 00539 } 00540 SetExpr 00541 operator -(const SetExpr& e) { 00542 return SetExpr(e,SetExpr::NT_CMPL); 00543 } 00544 SetExpr 00545 operator -(const SetExpr& l, const SetExpr& r) { 00546 return SetExpr(l,SetExpr::NT_INTER,-r); 00547 } 00548 SetExpr 00549 singleton(const LinExpr& e) { 00550 return SetExpr(e); 00551 } 00552 00553 SetExpr 00554 inter(const SetVarArgs& x) { 00555 if (x.size() == 0) 00556 return SetExpr(IntSet(Set::Limits::min,Set::Limits::max)); 00557 SetExpr r(x[0]); 00558 for (int i=1; i<x.size(); i++) 00559 r = (r & x[i]); 00560 return r; 00561 } 00562 SetExpr 00563 setunion(const SetVarArgs& x) { 00564 if (x.size() == 0) 00565 return SetExpr(IntSet::empty); 00566 SetExpr r(x[0]); 00567 for (int i=1; i<x.size(); i++) 00568 r = (r | x[i]); 00569 return r; 00570 } 00571 SetExpr 00572 setdunion(const SetVarArgs& x) { 00573 if (x.size() == 0) 00574 return SetExpr(IntSet::empty); 00575 SetExpr r(x[0]); 00576 for (int i=1; i<x.size(); i++) 00577 r = (r + x[i]); 00578 return r; 00579 } 00580 00581 namespace MiniModel { 00583 class GECODE_MINIMODEL_EXPORT SetNonLinExpr : public NonLinExpr { 00584 public: 00586 enum SetNonLinExprType { 00587 SNLE_CARD, 00588 SNLE_MIN, 00589 SNLE_MAX 00590 } t; 00592 SetExpr e; 00594 SetNonLinExpr(const SetExpr& e0, SetNonLinExprType t0) 00595 : t(t0), e(e0) {} 00597 virtual IntVar post(Home home, IntVar* ret, IntConLevel) const { 00598 IntVar m = result(home,ret); 00599 switch (t) { 00600 case SNLE_CARD: 00601 cardinality(home, e.post(home), m); 00602 break; 00603 case SNLE_MIN: 00604 min(home, e.post(home), m); 00605 break; 00606 case SNLE_MAX: 00607 max(home, e.post(home), m); 00608 break; 00609 default: 00610 GECODE_NEVER; 00611 break; 00612 } 00613 return m; 00614 } 00615 virtual void post(Home home, IntRelType irt, int c, 00616 IntConLevel icl) const { 00617 if (t==SNLE_CARD && irt!=IRT_NQ) { 00618 switch (irt) { 00619 case IRT_LQ: 00620 cardinality(home, e.post(home), 00621 0U, 00622 static_cast<unsigned int>(c)); 00623 break; 00624 case IRT_LE: 00625 cardinality(home, e.post(home), 00626 0U, 00627 static_cast<unsigned int>(c-1)); 00628 break; 00629 case IRT_GQ: 00630 cardinality(home, e.post(home), 00631 static_cast<unsigned int>(c), 00632 Set::Limits::card); 00633 break; 00634 case IRT_GR: 00635 cardinality(home, e.post(home), 00636 static_cast<unsigned int>(c+1), 00637 Set::Limits::card); 00638 break; 00639 case IRT_EQ: 00640 cardinality(home, e.post(home), 00641 static_cast<unsigned int>(c), 00642 static_cast<unsigned int>(c)); 00643 break; 00644 default: 00645 GECODE_NEVER; 00646 } 00647 } else if (t==SNLE_MIN && (irt==IRT_GR || irt==IRT_GQ)) { 00648 c = (irt==IRT_GQ ? c : c+1); 00649 dom(home, e.post(home), SRT_SUB, c, Set::Limits::max); 00650 } else if (t==SNLE_MAX && (irt==IRT_LE || irt==IRT_LQ)) { 00651 c = (irt==IRT_LQ ? c : c-1); 00652 dom(home, e.post(home), SRT_SUB, Set::Limits::min, c); 00653 } else { 00654 rel(home, post(home,NULL,icl), irt, c); 00655 } 00656 } 00657 virtual void post(Home home, IntRelType irt, int c, 00658 BoolVar b, IntConLevel icl) const { 00659 if (t==SNLE_MIN && (irt==IRT_GR || irt==IRT_GQ)) { 00660 c = (irt==IRT_GQ ? c : c+1); 00661 dom(home, e.post(home), SRT_SUB, c, Set::Limits::max, b); 00662 } else if (t==SNLE_MAX && (irt==IRT_LE || irt==IRT_LQ)) { 00663 c = (irt==IRT_LQ ? c : c-1); 00664 dom(home, e.post(home), SRT_SUB, Set::Limits::min, c, b); 00665 } else { 00666 rel(home, post(home,NULL,icl), irt, c, b); 00667 } 00668 } 00669 }; 00670 } 00671 00672 LinExpr 00673 cardinality(const SetExpr& e) { 00674 return LinExpr(new MiniModel::SetNonLinExpr(e, 00675 MiniModel::SetNonLinExpr::SNLE_CARD)); 00676 } 00677 LinExpr 00678 min(const SetExpr& e) { 00679 return LinExpr(new MiniModel::SetNonLinExpr(e, 00680 MiniModel::SetNonLinExpr::SNLE_MIN)); 00681 } 00682 LinExpr 00683 max(const SetExpr& e) { 00684 return LinExpr(new MiniModel::SetNonLinExpr(e, 00685 MiniModel::SetNonLinExpr::SNLE_MAX)); 00686 } 00687 00688 /* 00689 * Posting set expressions 00690 * 00691 */ 00692 SetVar 00693 expr(Home home, const SetExpr& e) { 00694 if (!home.failed()) 00695 return e.post(home); 00696 SetVar x(home,IntSet::empty,IntSet::empty); 00697 return x; 00698 } 00699 00700 } 00701 00702 #endif 00703 00704 // STATISTICS: minimodel-any