Generated on Mon Jul 6 18:09:15 2009 for Gecode by doxygen 1.5.9

core.cpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Christian Schulte <schulte@gecode.org>
00005  *
00006  *  Copyright:
00007  *     Christian Schulte, 2002
00008  *
00009  *  Last modified:
00010  *     $Date: 2009-04-20 13:31:07 +0200 (Mon, 20 Apr 2009) $ by $Author: schulte $
00011  *     $Revision: 8735 $
00012  *
00013  *  This file is part of Gecode, the generic constraint
00014  *  development environment:
00015  *     http://www.gecode.org
00016  *
00017  *  Permission is hereby granted, free of charge, to any person obtaining
00018  *  a copy of this software and associated documentation files (the
00019  *  "Software"), to deal in the Software without restriction, including
00020  *  without limitation the rights to use, copy, modify, merge, publish,
00021  *  distribute, sublicense, and/or sell copies of the Software, and to
00022  *  permit persons to whom the Software is furnished to do so, subject to
00023  *  the following conditions:
00024  *
00025  *  The above copyright notice and this permission notice shall be
00026  *  included in all copies or substantial portions of the Software.
00027  *
00028  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00029  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00030  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00031  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00032  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00033  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00034  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00035  *
00036  */
00037 
00038 #include <gecode/kernel.hh>
00039 
00040 namespace Gecode {
00041 
00042   /*
00043    * Variable type disposer
00044    *
00045    */
00046   void
00047   VarDisposerBase::dispose(Space&,VarImpBase*) {}
00048 
00049   VarDisposerBase::~VarDisposerBase(void) {}
00050 
00051 
00052 
00053   /*
00054    * Actor
00055    *
00056    */
00057   size_t
00058   Actor::allocated(void) const {
00059     return 0;
00060   }
00061 
00062 #ifdef __GNUC__
00064   Actor::~Actor(void) {}
00065 #endif
00066 
00067 
00068 
00069   /*
00070    * Propagator
00071    *
00072    */
00073   ExecStatus
00074   Propagator::advise(Space&, Advisor&, const Delta&) {
00075     assert(false);
00076     return ES_FAILED;
00077   }
00078 
00079 
00080 
00081   /*
00082    * Space: Misc
00083    *
00084    */
00085   unsigned long int Space::unused_uli;
00086   bool Space::unused_b;
00087   StatusStatistics Space::unused_status;
00088   CloneStatistics Space::unused_clone;
00089   CommitStatistics Space::unused_commit;
00090 
00091 #ifdef GECODE_HAS_VAR_DISPOSE
00092   VarDisposerBase* Space::vd[AllVarConf::idx_d];
00093 #endif
00094 
00095   Space::Space(void)
00096     : sm(new SharedMemory), mm(sm), n_wmp(0) {
00097 #ifdef GECODE_HAS_VAR_DISPOSE
00098     for (int i=0; i<AllVarConf::idx_d; i++)
00099       _vars_d[i] = NULL;
00100 #endif
00101     // Initialize propagator and branching links
00102     pl.init();
00103     bl.init();
00104     b_status = b_commit = Branching::cast(&bl);
00105     // Initialize array for forced deletion to be empty
00106     d_fst = d_cur = d_lst = NULL;
00107     // Initialize propagator queues
00108     pc.p.active = &pc.p.queue[0]-1;
00109     for (int i=0; i<=PropCost::AC_MAX; i++)
00110       pc.p.queue[i].init();
00111     pc.p.branch_id = 0;
00112     pc.p.n_sub = 0;
00113   }
00114 
00115   void
00116   Space::d_resize(void) {
00117     if (d_fst == NULL) {
00118       // Create new array
00119       d_fst = alloc<Actor*>(4);
00120       d_cur = d_fst;
00121       d_lst = d_fst+4;
00122     } else {
00123       // Resize existing array
00124       unsigned int n = static_cast<unsigned int>(d_lst - d_fst);
00125       assert(n != 0);
00126       d_fst = realloc<Actor*>(d_fst,n,2*n);
00127       d_cur = d_fst+n;
00128       d_lst = d_fst+2*n;
00129     }
00130   }
00131 
00132   unsigned int
00133   Space::propagators(void) const {
00134     unsigned int n = 0;
00135     for (Propagators p(*this); p(); ++p)
00136       n++;
00137     return n;
00138   }
00139 
00140   unsigned int
00141   Space::branchings(void) const {
00142     unsigned int n = 0;
00143     for (Branchings b(*this); b(); ++b)
00144       n++;
00145     return n;
00146   }
00147 
00148   void
00149   Space::flush(void) {
00150     sm->flush();
00151   }
00152 
00153   Space::~Space(void) {
00154     // Mark space as failed
00155     fail();
00156     // Delete actors that must be deleted
00157     {
00158       Actor** a = d_fst;
00159       Actor** e = d_cur;
00160       // So that d_unforce knows that deletion is in progress
00161       d_fst = NULL;
00162       while (a < e) {
00163         (void) (*a)->dispose(*this);
00164         a++;
00165       }
00166     }
00167 #ifdef GECODE_HAS_VAR_DISPOSE
00168     // Delete variables that were registered for disposal
00169     for (int i=AllVarConf::idx_d; i--;)
00170       if (_vars_d[i] != NULL)
00171         vd[i]->dispose(*this, _vars_d[i]);
00172 #endif
00173     // Release memory from memory manager
00174     mm.release(sm);
00175     // Release shared memory
00176     if (sm->release())
00177       delete sm;
00178   }
00179 
00180 
00181 
00182   /*
00183    * Space: propagation
00184    *
00185    */
00186 
00187   SpaceStatus
00188   Space::status(StatusStatistics& stat) {
00189     SpaceStatus s = SS_FAILED;
00190     if (failed()) {
00191       s = SS_FAILED; goto exit;
00192     }
00193     if (!stable()) {
00194       assert(pc.p.active >= &pc.p.queue[0]);
00195       Propagator* p;
00196       ModEventDelta med_o;
00197       goto unstable;
00198     execute:
00199       stat.propagate++;
00200       // Keep old modification event delta
00201       med_o = p->u.med;
00202       // Clear med but leave propagator in queue
00203       p->u.med = 0;
00204       switch (p->propagate(*this,med_o)) {
00205       case ES_FAILED:
00206         fail(); s = SS_FAILED; goto exit;
00207       case ES_NOFIX:
00208         // Find next, if possible
00209         if (p->u.med != 0) {
00210         unstable:
00211           // There is at least one propagator in a queue
00212           do {
00213             assert(pc.p.active >= &pc.p.queue[0]);
00214             // First propagator or link back to queue
00215             ActorLink* fst = pc.p.active->next();
00216             if (pc.p.active != fst) {
00217               p = Propagator::cast(fst);
00218               goto execute;
00219             }
00220             pc.p.active--;
00221           } while (true);
00222           GECODE_NEVER;
00223         }
00224         // Fall through
00225       case ES_FIX:
00226         // Clear med and put into idle queue
00227         p->u.med = 0; p->unlink(); pl.head(p);
00228       stable_or_unstable:
00229         // There might be a propagator in the queue
00230         do {
00231           assert(pc.p.active >= &pc.p.queue[0]);
00232           // First propagator or link back to queue
00233           ActorLink* fst = pc.p.active->next();
00234           if (pc.p.active != fst) {
00235             p = Propagator::cast(fst);
00236             goto execute;
00237           }
00238         } while (--pc.p.active >= &pc.p.queue[0]);
00239         assert(pc.p.active < &pc.p.queue[0]);
00240         goto stable;
00241       case __ES_SUBSUMED:
00242         p->unlink(); rfree(p,p->u.size);
00243         goto stable_or_unstable;
00244       case __ES_PARTIAL:
00245         // Schedule propagator with specified propagator events
00246         assert(p->u.med != 0);
00247         enqueue(p);
00248         goto unstable;
00249       default:
00250         GECODE_NEVER;
00251       }
00252     }
00253   stable:
00254     /*
00255      * Find the next branching that has still alternatives left
00256      *
00257      * It is important to note that branchings reporting to have no more
00258      * alternatives left cannot be deleted. They cannot be deleted
00259      * as there might be branching descriptions to be used in commit
00260      * that refer to one of these branchings. This e.g. happens when
00261      * we combine branch-and-bound search with adaptive recomputation: during
00262      * recomputation, a copy is constrained to be better than the currently
00263      * best solution, then the first half of the BranchingDescs is posted,
00264      * and a fixpoint computed (for storing in the middle of the path). Then
00265      * the remaining BranchingDescs are posted, and because of the additional
00266      * constraints that the space must be better than the previous solution,
00267      * the corresponding Branchings may already have no alternatives left.
00268      *
00269      * The same situation may arise due to weakly monotonic propagators.
00270      *
00271      * A branching reporting that no more alternatives exist is exhausted.
00272      * All exhausted branchings will be left of the current pointer b_status.
00273      * Only when it is known that no more branching descriptions
00274      * can be used for commit an exhausted branching can actually be deleted.
00275      * This becomes known when description is called.
00276      */
00277     while (b_status != Branching::cast(&bl))
00278       if (b_status->status(*this)) {
00279         // Branching still has choices to generate
00280         s = SS_BRANCH; goto exit;
00281       } else {
00282         // Branching is exhausted
00283         b_status = Branching::cast(b_status->next());
00284       }
00285     // No branching with alternatives left, space is solved
00286     s = SS_SOLVED;
00287   exit:
00288     stat.wmp = (n_wmp > 0);
00289     if (n_wmp == 1) n_wmp = 0;
00290     return s;
00291   }
00292 
00293 
00294   const BranchingDesc*
00295   Space::description(void) {
00296     if (!stable())
00297       throw SpaceNotStable("Space::description");
00298     if (failed() || (b_status == Branching::cast(&bl))) {
00299       // There are no more descriptions to be generated
00300       // Delete all branchings
00301       Branching* b = Branching::cast(bl.next()); 
00302       while (b != Branching::cast(&bl)) {
00303         Branching* d = b;
00304         b = Branching::cast(b->next());
00305         rfree(d,d->dispose(*this));
00306       }
00307       bl.init();
00308       b_status = b_commit = Branching::cast(&bl);
00309       return NULL;
00310     }
00311     /*
00312      * The call to description() says that no older branching descriptions 
00313      * can be used. Hence, all branchings that are exhausted can be deleted.
00314      */
00315     Branching* b = Branching::cast(bl.next());
00316     while (b != b_status) {
00317       Branching* d = b;
00318       b = Branching::cast(b->next());
00319       d->unlink();
00320       rfree(d,d->dispose(*this));
00321     }
00322     // Make sure that b_commit does not point to a deleted branching!
00323     b_commit = b_status;
00324     return b_status->description(*this);
00325   }
00326 
00327   void
00328   Space::_commit(const BranchingDesc& d, unsigned int a) {
00329     if (a >= d.alternatives())
00330       throw SpaceIllegalAlternative();
00331     if (failed())
00332       return;
00333     /*
00334      * Due to weakly monotonic propagators the following scenario might
00335      * occur: a branching has been committed with all its available
00336      * branching descriptions. Then, propagation determines less information
00337      * than before and the branching now will create new branching 
00338      * descriptions. Later, during recomputation, all of these branching 
00339      * descriptions can be used together, possibly interleaved with 
00340      * descriptions for other branchings. That means all branchings
00341      * must be scanned to find the matching branching for the description.
00342      *
00343      * b_commit tries to optimize scanning as it is most likely that
00344      * recomputation does not generate new descriptions during recomputation
00345      * and hence b_commit is moved from newer to older branchings.
00346      */
00347     Branching* b_old = b_commit;
00348     // Try whether we are lucky
00349     while (b_commit != Branching::cast(&bl))
00350       if (d._id != b_commit->id())
00351         b_commit = Branching::cast(b_commit->next());
00352       else
00353         goto found;
00354     if (b_commit == Branching::cast(&bl)) {
00355       // We did not find the branching, start at the beginning
00356       b_commit = Branching::cast(bl.next());
00357       while (b_commit != b_old)
00358         if (d._id != b_commit->id())
00359           b_commit = Branching::cast(b_commit->next());
00360         else
00361           goto found;
00362     }
00363     // There is no matching branching!
00364     throw SpaceNoBranching();
00365   found:
00366     // There is a matching branching
00367     if (b_commit->commit(*this,d,a) == ES_FAILED)
00368       fail();
00369   }
00370 
00371 
00372 
00373   /*
00374    * Space cloning
00375    *
00376    * Cloning is performed in two steps:
00377    *  - The space itself is copied by the copy constructor. This
00378    *    also copies all propagators, branchings, and variables.
00379    *    The copied variables are recorded.
00380    *  - In the second step the dependency information of the recorded
00381    *    variables is updated and their forwarding information is reset.
00382    *
00383    */
00384   Space::Space(bool share, Space& s)
00385     : sm(s.sm->copy(share)), 
00386       mm(sm,s.mm,s.pc.p.n_sub*sizeof(Propagator**)),
00387       n_wmp(s.n_wmp) {
00388 #ifdef GECODE_HAS_VAR_DISPOSE
00389     for (int i=0; i<AllVarConf::idx_d; i++)
00390       _vars_d[i] = NULL;
00391 #endif
00392     for (int i=0; i<AllVarConf::idx_c; i++)
00393       pc.c.vars_u[i] = NULL;
00394     pc.c.vars_noidx = NULL;
00395     pc.c.copied = NULL;
00396     // Copy all propagators
00397     {
00398       ActorLink* p = &pl;
00399       ActorLink* e = &s.pl;
00400       for (ActorLink* a = e->next(); a != e; a = a->next()) {
00401         Actor* c = Actor::cast(a)->copy(*this,share);
00402         // Link copied actor
00403         p->next(ActorLink::cast(c)); ActorLink::cast(c)->prev(p);
00404         // Note that forwarding is done in the constructors
00405         p = c;
00406       }
00407       // Link last actor
00408       p->next(&pl); pl.prev(p);
00409     }
00410     // Copy all branchings
00411     {
00412       ActorLink* p = &bl;
00413       ActorLink* e = &s.bl;
00414       for (ActorLink* a = e->next(); a != e; a = a->next()) {
00415         Actor* c = Actor::cast(a)->copy(*this,share);
00416         // Link copied actor
00417         p->next(ActorLink::cast(c)); ActorLink::cast(c)->prev(p);
00418         // Note that forwarding is done in the constructors
00419         p = c;
00420       }
00421       // Link last actor
00422       p->next(&bl); bl.prev(p);
00423     }
00424     // Setup array for actor disposal
00425     {
00426       unsigned int n = static_cast<unsigned int>(s.d_cur - s.d_fst);
00427       if (n == 0) {
00428         // No actors
00429         d_fst = d_cur = d_lst = NULL;
00430       } else {
00431         // Leave one entry free
00432         d_fst = alloc<Actor*>(n+1);
00433         d_cur = d_fst+n;
00434         d_lst = d_cur+1;
00435         do {
00436           n--;
00437           d_fst[n] = Actor::cast(s.d_fst[n]->prev());
00438         } while (n != 0);
00439       }
00440     }
00441     // Setup branching pointers
00442     if (s.b_status == &s.bl) {
00443       b_status = Branching::cast(&bl);
00444     } else {
00445       b_status = Branching::cast(s.b_status->prev());
00446     }
00447     if (s.b_commit == &s.bl) {
00448       b_commit = Branching::cast(&bl);
00449     } else {
00450       b_commit = Branching::cast(s.b_commit->prev());
00451     }
00452   }
00453 
00454   Space*
00455   Space::_clone(bool share) {
00456     if (failed())
00457       throw SpaceFailed("Space::clone");
00458     if (!stable())
00459       throw SpaceNotStable("Space::clone");
00460 
00461     // Copy all data structures (which in turn will invoke the constructor)
00462     Space* c = copy(share);
00463 
00464     // Update variables without indexing structure
00465     VarImp<NoIdxVarImpConf>* x =
00466       static_cast<VarImp<NoIdxVarImpConf>*>(c->pc.c.vars_noidx);
00467     while (x != NULL) {
00468       VarImp<NoIdxVarImpConf>* n = x->next();
00469       x->base = NULL; x->u.idx[0] = 0;
00470       x = n;
00471     }
00472     // Update variables with indexing structure
00473     c->update(static_cast<ActorLink**>(c->mm.subscriptions()));
00474 
00475     // Re-establish prev links (reset forwarding information)
00476     {
00477       ActorLink* p_a = &pl;
00478       ActorLink* c_a = p_a->next();
00479       // First update propagators and advisors
00480       while (c_a != &pl) {
00481         Propagator* p = Propagator::cast(c_a);
00482         if (p->u.advisors != NULL) {
00483           ActorLink* a = p->u.advisors;
00484           p->u.advisors = NULL;
00485           do {
00486             a->prev(p); a = a->next();
00487           } while (a != NULL);
00488         }
00489         c_a->prev(p_a); p_a = c_a; c_a = c_a->next();
00490       }
00491     }
00492     {
00493       ActorLink* p_a = &bl;
00494       ActorLink* c_a = p_a->next();
00495       // Update branchings
00496       while (c_a != &bl) {
00497         c_a->prev(p_a); p_a = c_a; c_a = c_a->next();
00498       }
00499     }
00500 
00501     // Reset links for copied objects
00502     for (CopiedHandle::Object* s = c->pc.c.copied; s != NULL; s = s->next)
00503       s->fwd = NULL;
00504 
00505     // Initialize propagator queue
00506     c->pc.p.active = &c->pc.p.queue[0]-1;
00507     for (int i=0; i<=PropCost::AC_MAX; i++)
00508       c->pc.p.queue[i].init();
00509     // Copy propagation only data
00510     c->pc.p.n_sub = pc.p.n_sub;
00511     c->pc.p.branch_id = pc.p.branch_id;
00512     return c;
00513   }
00514 
00515   void
00516   Space::constrain(const Space&) {
00517     throw SpaceConstrainUndefined();
00518   }
00519 
00520 }
00521 
00522 // STATISTICS: kernel-core