Generated on Tue Apr 18 10:22:09 2017 for Gecode by doxygen 1.6.3

dfs.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, 2009
00008  *
00009  *  Last modified:
00010  *     $Date: 2016-04-19 17:19:45 +0200 (Tue, 19 Apr 2016) $ by $Author: schulte $
00011  *     $Revision: 14967 $
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/support.hh>
00039 
00040 #ifdef GECODE_HAS_THREADS
00041 
00042 #include <gecode/search/parallel/dfs.hh>
00043 
00044 namespace Gecode { namespace Search { namespace Parallel {
00045 
00046   /*
00047    * Statistics
00048    */
00049   Statistics
00050   DFS::statistics(void) const {
00051     Statistics s;
00052     for (unsigned int i=0; i<workers(); i++)
00053       s += worker(i)->statistics();
00054     return s;
00055   }
00056 
00057 
00058   /*
00059    * Engine: search control
00060    */
00061   void
00062   DFS::Worker::run(void) {
00063     /*
00064      * The engine maintains the following invariant:
00065      *  - If the current space (cur) is not NULL, the path always points
00066      *    to exactly that space.
00067      *  - If the current space (cur) is NULL, the path always points
00068      *    to the next space (if there is any).
00069      *
00070      * This invariant is needed so that no-goods can be extracted properly
00071      * when the engine is stopped or has found a solution.
00072      *
00073      */
00074     // Peform initial delay, if not first worker
00075     if (this != engine().worker(0))
00076       Support::Thread::sleep(Config::initial_delay);
00077     // Okay, we are in business, start working
00078     while (true) {
00079       switch (engine().cmd()) {
00080       case C_WAIT:
00081         // Wait
00082         engine().wait();
00083         break;
00084       case C_TERMINATE:
00085         // Acknowledge termination request
00086         engine().ack_terminate();
00087         // Wait until termination can proceed
00088         engine().wait_terminate();
00089         // Terminate thread
00090         engine().terminated();
00091         return;
00092       case C_RESET:
00093         // Acknowledge reset request
00094         engine().ack_reset_start();
00095         // Wait until reset has been performed
00096         engine().wait_reset();
00097         // Acknowledge that reset cycle is over
00098         engine().ack_reset_stop();
00099         break;
00100       case C_WORK:
00101         // Perform exploration work
00102         {
00103           m.acquire();
00104           if (idle) {
00105             m.release();
00106             // Try to find new work
00107             find();
00108           } else if (cur != NULL) {
00109             start();
00110             if (stop(engine().opt())) {
00111               // Report stop
00112               m.release();
00113               engine().stop();
00114             } else {
00115               node++;
00116               switch (cur->status(*this)) {
00117               case SS_FAILED:
00118                 fail++;
00119                 delete cur;
00120                 cur = NULL;
00121                 path.next();
00122                 m.release();
00123                 break;
00124               case SS_SOLVED:
00125                 {
00126                   // Deletes all pending branchers
00127                   (void) cur->choice();
00128                   Space* s = cur->clone(false);
00129                   delete cur;
00130                   cur = NULL;
00131                   path.next();
00132                   m.release();
00133                   engine().solution(s);
00134                 }
00135                 break;
00136               case SS_BRANCH:
00137                 {
00138                   Space* c;
00139                   if ((d == 0) || (d >= engine().opt().c_d)) {
00140                     c = cur->clone();
00141                     d = 1;
00142                   } else {
00143                     c = NULL;
00144                     d++;
00145                   }
00146                   const Choice* ch = path.push(*this,cur,c);
00147                   cur->commit(*ch,0);
00148                   m.release();
00149                 }
00150                 break;
00151               default:
00152                 GECODE_NEVER;
00153               }
00154             }
00155           } else if (!path.empty()) {
00156             cur = path.recompute(d,engine().opt().a_d,*this);
00157             if (cur == NULL)
00158               path.next();
00159             m.release();
00160           } else {
00161             idle = true;
00162             path.ngdl(0);
00163             m.release();
00164             // Report that worker is idle
00165             engine().idle();
00166           }
00167         }
00168         break;
00169       default:
00170         GECODE_NEVER;
00171       }
00172     }
00173   }
00174 
00175 
00176   /*
00177    * Perform reset
00178    *
00179    */
00180   void
00181   DFS::reset(Space* s) {
00182     // Grab wait lock for reset
00183     m_wait_reset.acquire();
00184     // Release workers for reset
00185     release(C_RESET);
00186     // Wait for reset cycle started
00187     e_reset_ack_start.wait();
00188     // All workers are marked as busy again
00189     n_busy = workers();
00190     for (unsigned int i=1U; i<workers(); i++)
00191       worker(i)->reset(NULL,0);
00192     worker(0U)->reset(s,opt().nogoods_limit);
00193     // Block workers again to ensure invariant
00194     block();
00195     // Release reset lock
00196     m_wait_reset.release();
00197     // Wait for reset cycle stopped
00198     e_reset_ack_stop.wait();
00199   }
00200 
00201 
00202 
00203   /*
00204    * Create no-goods
00205    *
00206    */
00207   NoGoods&
00208   DFS::nogoods(void) {
00209     NoGoods* ng;
00210     // Grab wait lock for reset
00211     m_wait_reset.acquire();
00212     // Release workers for reset
00213     release(C_RESET);
00214     // Wait for reset cycle started
00215     e_reset_ack_start.wait();
00216     ng = &worker(0)->nogoods();
00217     // Block workers again to ensure invariant
00218     block();
00219     // Release reset lock
00220     m_wait_reset.release();
00221     // Wait for reset cycle stopped
00222     e_reset_ack_stop.wait();
00223     return *ng;
00224   }
00225 
00226 
00227   /*
00228    * Termination and deletion
00229    */
00230   DFS::~DFS(void) {
00231     terminate();
00232     heap.rfree(_worker);
00233   }
00234 
00235 }}}
00236 
00237 #endif
00238 
00239 // STATISTICS: search-parallel