Generated on Sun Feb 17 15:24:15 2019 for Gecode by doxygen 1.6.3

cbs.hpp

Go to the documentation of this file.
00001 /* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */
00002 /*
00003  *  Main authors:
00004  *     Samuel Gagnon <samuel.gagnon92@gmail.com>
00005  *
00006  *  Copyright:
00007  *     Samuel Gagnon, 2018
00008  *
00009  *  This file is part of Gecode, the generic constraint
00010  *  development environment:
00011  *     http://www.gecode.org
00012  *
00013  *  Permission is hereby granted, free of charge, to any person obtaining
00014  *  a copy of this software and associated documentation files (the
00015  *  "Software"), to deal in the Software without restriction, including
00016  *  without limitation the rights to use, copy, modify, merge, publish,
00017  *  distribute, sublicense, and/or sell copies of the Software, and to
00018  *  permit persons to whom the Software is furnished to do so, subject to
00019  *  the following conditions:
00020  *
00021  *  The above copyright notice and this permission notice shall be
00022  *  included in all copies or substantial portions of the Software.
00023  *
00024  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
00025  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00026  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
00027  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
00028  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
00029  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
00030  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00031  *
00032  */
00033 
00034 #ifdef GECODE_HAS_CBS
00035 
00036 namespace Gecode { namespace Int { namespace Branch {
00037 
00038   template<class View>
00039   forceinline void
00040   CBSBrancher<View>::VarIdToPos::init() {
00041     assert(object() == nullptr);
00042     object(new VarIdToPosO());
00043   }
00044 
00045   template<class View>
00046   forceinline bool
00047   CBSBrancher<View>::VarIdToPos::isIn(unsigned int var_id) const {
00048     auto *hm = &static_cast<VarIdToPosO*>(object())->_varIdToPos;
00049     return hm->find(var_id) != hm->end();
00050   }
00051 
00052   template<class View>
00053   forceinline int
00054   CBSBrancher<View>::VarIdToPos::operator[](unsigned int i) const {
00055     return static_cast<VarIdToPosO*>(object())->_varIdToPos.at(i);
00056   }
00057 
00058   template<class View>
00059   forceinline void
00060   CBSBrancher<View>::VarIdToPos::insert(unsigned int var_id,
00061                                              unsigned int pos) {
00062     static_cast<VarIdToPosO*>(object())
00063       ->_varIdToPos.insert(std::make_pair(var_id, pos));
00064   }
00065 
00066   template<class View>
00067   CBSBrancher<View>::CBSBrancher(Home home, ViewArray<View>& x0)
00068     : Brancher(home), x(x0),
00069       logProp(typename decltype(logProp)::size_type(),
00070               typename decltype(logProp)::hasher(),
00071               typename decltype(logProp)::key_equal(),
00072               typename decltype(logProp)::allocator_type(home)) {
00073     home.notice(*this, AP_DISPOSE);
00074     varIdToPos.init();
00075     for (int i=0; i<x.size(); i++)
00076       varIdToPos.insert(x[i].id(), i);
00077   }
00078 
00079   template<class View>
00080   forceinline void
00081   CBSBrancher<View>::post(Home home, ViewArray<View>& x) {
00082     (void) new (home) CBSBrancher(home,x);
00083   }
00084 
00085   template<class View>
00086   Actor* CBSBrancher<View>::copy(Space& home) {
00087     return new (home) CBSBrancher(home,*this);
00088   }
00089 
00090   template<class View>
00091   forceinline size_t
00092   CBSBrancher<View>::dispose(Space& home) {
00093     home.ignore(*this, AP_DISPOSE);
00094     varIdToPos.~VarIdToPos();
00095     (void) Brancher::dispose(home);
00096     return sizeof(*this);
00097   }
00098 
00099   template<class View>
00100   CBSBrancher<View>::CBSBrancher(Space& home, CBSBrancher& b)
00101     : Brancher(home,b),
00102       varIdToPos(b.varIdToPos),
00103       logProp(b.logProp.begin(), b.logProp.end(),
00104               typename decltype(logProp)::size_type(),
00105               typename decltype(logProp)::hasher(),
00106               typename decltype(logProp)::key_equal(),
00107               typename decltype(logProp)::allocator_type(home)) {
00108     x.update(home,b.x);
00109   }
00110 
00111   template<class View>
00112   bool CBSBrancher<View>::status(const Space& home) const {
00113     for (Propagators p(home, PropagatorGroup::all); p(); ++p) {
00114       // Sum of domains of all variable in propagator
00115       unsigned int domsum;
00116       // Same, but for variables that are also in this brancher.
00117       unsigned int domsum_b;
00118 
00119       // If the propagator doesn't support counting-based search, domsum and
00120       // domsum_b are going to be equal to 0.
00121       p.propagator().domainsizesum([this](unsigned int var_id)
00122                          { return inbrancher(var_id); },
00123                          domsum, domsum_b);
00124 
00125       if (domsum_b > 0)
00126         return true;
00127     }
00128 
00129     return false;
00130   }
00131 
00132   template<class View>
00133   forceinline bool
00134   CBSBrancher<View>::inbrancher(unsigned int varId) const {
00135     return varIdToPos.isIn(varId);
00136   }
00137 
00138   template<class View>
00139   const Choice* CBSBrancher<View>::choice(Space& home) {
00140     // Structure for keeping the maximum solution density assignment
00141     struct {
00142       unsigned int var_id;
00143       int val;
00144       double dens;
00145     } maxSD{0, 0, -1};
00146 
00147     // Lambda we pass to propagators via solndistrib to query solution densities
00148     auto SendMarginal = [this](unsigned int prop_id, unsigned int var_id,
00149                                int val, double dens) {
00150         if (logProp[prop_id].dens < dens) {
00151           logProp[prop_id].var_id = var_id;
00152           logProp[prop_id].val = val;
00153           logProp[prop_id].dens = dens;
00154         }
00155     };
00156 
00157     for (auto& kv : logProp)
00158       kv.second.visited = false;
00159 
00160     for (Propagators p(home, PropagatorGroup::all); p(); ++p) {
00161       unsigned int prop_id = p.propagator().id();
00162       unsigned int domsum;
00163       unsigned int domsum_b;
00164 
00165       p.propagator().domainsizesum([this](unsigned int var_id)
00166                                    { return inbrancher(var_id); },
00167                                    domsum, domsum_b);
00168 
00169       // If the propagator doesn't share any unasigned variables with this
00170       // brancher, we continue and it will be deleted from the log afterwards.
00171       if (domsum_b == 0)
00172         continue;
00173 
00174       // New propagators can be created as we solve the problem. If this is the
00175       // case we create a new entry in the log.
00176       if (logProp.find(prop_id) == logProp.end())
00177         logProp.insert(std::make_pair(prop_id, PropInfo{0, 0, 0, -1, true}));
00178       else
00179         logProp[prop_id].visited = true;
00180 
00181       // If the domain size sum of all variables in the propagator has changed
00182       // since the last time we called this function, we need to recompute
00183       // solution densities. Otherwise, we can reuse them.
00184       if (logProp[prop_id].domsum != domsum) {
00185         logProp[prop_id].dens = -1;
00186         // Solution density computation
00187         p.propagator().solndistrib(home, SendMarginal);
00188         logProp[prop_id].domsum = domsum;
00189       }
00190     }
00191 
00192     // We delete unvisited propagators from the log and look for the highest
00193     // solution density across all propagators.
00194     for (const auto& kv : logProp) {
00195       unsigned int prop_id = kv.first;
00196       const PropInfo& info = kv.second;
00197       if (!info.visited)
00198         logProp.erase(prop_id);
00199       else if (info.dens > maxSD.dens)
00200         maxSD = {info.var_id, info.val, info.dens};
00201     }
00202 
00203     assert(maxSD.dens != -1);
00204     assert(!x[varIdToPos[maxSD.var_id]].assigned());
00205     return new PosValChoice<int>(*this, 2, varIdToPos[maxSD.var_id], maxSD.val);
00206   }
00207 
00208   template<class View>
00209   forceinline const Choice*
00210   CBSBrancher<View>::choice(const Space&, Archive& e) {
00211     int pos, val;
00212     e >> pos >> val;
00213     return new PosValChoice<int>(*this, 2, pos, val);
00214   }
00215 
00216   template<class View>
00217   forceinline ExecStatus
00218   CBSBrancher<View>::commit(Space& home, const Choice& c, unsigned int a) {
00219     const auto& pvc = static_cast<const PosValChoice<int>&>(c);
00220     int pos = pvc.pos().pos;
00221     int val = pvc.val();
00222     if (a == 0)
00223       return me_failed(x[pos].eq(home, val)) ? ES_FAILED : ES_OK;
00224     else
00225       return me_failed(x[pos].nq(home, val)) ? ES_FAILED : ES_OK;
00226   }
00227 
00228   template<class View>
00229   forceinline void
00230   CBSBrancher<View>::print(const Space&, const Choice& c, unsigned int a,
00231                            std::ostream& o) const {
00232     const auto& pvc = static_cast<const PosValChoice<int>&>(c);
00233     int pos=pvc.pos().pos, val=pvc.val();
00234     if (a == 0)
00235       o << "x[" << pos << "] = " << val;
00236     else
00237       o << "x[" << pos << "] != " << val;
00238   }
00239 
00240 }}}
00241 
00242 #endif
00243 
00244 // STATISTICS: int-branch