135 using Node =
typename P::node_type;
147 : f_p( problem ) , f_options( options ) {
162 return( run( std::nullopt ) );
170 return( run( std::move( seeds ) ) );
184 using Mq = ADS::MultiQueue< Value , Held >;
185 using Item =
typename BBQueue< Node , Value >::Item;
189 SolutionT run( std::optional< std::vector< Leaf > > seeds )
const
192 const unsigned p = f_options.
threads;
195 detail::bb_signed< P >( *f_options.
incumbent ) : inf;
196 Shared sh( p , start , f_options.
seed );
198 auto hd = sh.q.handle();
200 for(
auto & l : detail::bb_starts( f_p , std::move( seeds ) ) ) {
201 const Value key = detail::bb_key( f_p , l.node , l.bound , l.depth ,
203 hd.push( key , Held{ std::move( l.node ) , l.bound , l.depth } );
209 std::vector< std::unique_ptr< Worker > > w( p );
210 for(
unsigned i = 0 ; i < p ; ++i )
211 w[ i ] = std::make_unique< Worker >( *
this , sh , clock );
212 run_workers( f_ex , p , [ & ](
unsigned i ) { w[ i ]->run( i ); } );
216 detail::BBFrontier< Node , Value > fr( f_options.keep_frontier );
217 for(
auto & x : w ) {
218 sol.stats.add( x->f_st );
219 fr.merge( std::move( x->f_fr ) );
221 auto hd = sh.q.handle();
222 for(
auto e = hd.tryPop() ; e ; e = hd.tryPop() )
223 fr.add( std::move( e->item.node ) , e->item.bound , e->item.depth ,
225 detail::bb_finish< P >( sol , sh.inc , fr , sh.limit.load() ,
227 sol.stats.seconds = clock.seconds();
236 Shared(
unsigned np ,
Value z , std::uint64_t seed )
237 : q( 2 * std::size_t( np ) , 1 , seed ) , inc( z ) {}
240 BBIncumbent< Node , Value > inc;
242 alignas(
cache_line ) std::atomic< std::size_t > held{ 0 };
243 alignas(
cache_line ) std::atomic< std::uint64_t > evaluated{ 0 };
244 alignas(
cache_line ) std::atomic< bool > done{
false };
245 std::atomic< bool > limit{
false };
246 std::atomic< bool > time{
false };
252 struct alignas( cache_line ) Worker {
255 const Stopwatch & c )
256 : f_a( a ) , f_sh( s ) , f_clock( c ) ,
257 f_fr( a.f_options.keep_frontier ) {}
260 void run(
unsigned i ) {
261 auto w = detail::bb_worker( f_a.f_p , i );
262 const auto & o = f_a.f_options;
264 auto hd = f_sh.q.handle();
265 ADS::Backoff backoff;
266 std::optional< Item > dive;
267 std::vector< Item > kids;
268 std::vector< typename Mq::Entry > out;
269 const auto inc = [ & ] {
return( f_sh.inc.value() ); };
270 const auto improve = [ & ](
Value v ,
const Node & n ) {
271 return( f_sh.inc.template improve< P >( v , n , o ) );
274 while( ! f_sh.done.load( std::memory_order_acquire ) ) {
275 std::optional< Item > it;
277 it.emplace( std::move( *dive ) );
281 auto e = hd.tryPop();
283 if( f_sh.held.load( std::memory_order_acquire ) == 0 ) {
284 f_sh.done.store(
true , std::memory_order_release );
291 if( detail::bb_prunable( e->item.bound , inc() , o ) ) {
292 f_fr.add( std::move( e->item.node ) , e->item.bound , e->item.depth ,
294 ++f_st.pruned_extracted;
295 f_sh.held.fetch_sub( 1 , std::memory_order_acq_rel );
298 it.emplace( Item{ std::move( e->item.node ) , e->item.bound ,
303 f_fr.add( std::move( it->node ) , it->bound , it->depth ,
309 detail::bb_process< P >( it->node , it->bound , it->depth , w , inc ,
312 kids.push_back( Item{ std::move( c ) , b , d } );
313 } , o , f_st , f_fr );
315 f_sh.evaluated.fetch_add( 1 );
317 const std::size_t k = detail::bb_dive( kids , it->bound , inc() , o );
319 for( std::size_t j = 0 ; j < kids.size() ; ++j )
321 dive.emplace( std::move( kids[ j ] ) );
323 out.push_back(
typename Mq::Entry{
324 detail::bb_key( f_a.f_p , kids[ j ].node , kids[ j ].bound ,
325 kids[ j ].depth , sel ) ,
326 Held{ std::move( kids[ j ].node ) , kids[ j ].bound ,
327 kids[ j ].depth } } );
330 if( kids.size() != 1 ) {
331 const std::size_t m = f_sh.held.fetch_add( kids.size() - 1 ,
332 std::memory_order_acq_rel );
333 f_st.max_open = std::max( f_st.max_open , m + kids.size() - 1 );
335 hd.pushAll( std::make_move_iterator( out.begin() ) ,
336 std::make_move_iterator( out.end() ) );
339 f_fr.add( std::move( dive->node ) , dive->bound , dive->depth ,
345 if( ! detail::bb_limit( f_a.f_options , f_sh.evaluated.load() , f_clock ,
346 f_sh.limit , f_sh.time ) )
348 f_sh.done.store(
true , std::memory_order_release );
354 const Stopwatch & f_clock;
356 detail::BBFrontier< Node , Value > f_fr;
363 Executor * f_ex =
nullptr;