112 using Node =
typename P::node_type;
125 : f_p( problem ) , f_options( options ) {
140 return( run( std::nullopt ) );
148 return( run( std::move( seeds ) ) );
157 SolutionT run( std::optional< std::vector< Leaf > > seeds )
const
162 detail::bb_signed< P >( *f_options.
incumbent ) : inf;
163 Shared sh( start , clock );
164 Master master( *
this , sh , detail::bb_starts( f_p , std::move( seeds ) ) );
165 const unsigned n = f_options.
threads;
166 std::vector< std::unique_ptr< Worker > > w( n );
167 for(
unsigned i = 0 ; i < n ; ++i )
168 w[ i ] = std::make_unique< Worker >( *
this , sh , i );
169 const auto begin = [ & ](
auto && emit , std::size_t ) {
170 if( ! ADS::isRunCaller() )
172 master.start( emit );
174 const auto back = [ & ]( Task * t ,
auto && emit ) {
175 return( master.back( t , emit ) );
177 const auto work = [ & ]( Task * t , std::size_t i ) {
178 return( w[ i ]->process( t ) );
181 ADS::feedbackFarm< Task * , Task * >( *f_ex , n , begin , back , work );
183 Executor ex( n + 1 );
184 ADS::feedbackFarm< Task * , Task * >( ex , n , begin , back , work );
189 detail::BBFrontier< Node , Value > & fr = master.f_fr;
191 for(
auto & x : w ) {
192 sol.stats.add( x->f_st );
193 fr.merge( std::move( x->f_fr ) );
195 sol.stats.pruned_extracted += master.f_st.pruned_extracted;
196 sol.stats.max_open = master.f_st.max_open;
197 sol.stats.messages = master.f_st.messages;
198 detail::bb_finish< P >( sol , sh.inc , fr , sh.limit.load() ,
200 sol.stats.seconds = clock.
seconds();
206 std::vector< Item > nodes;
207 std::vector< Item > kids;
216 Shared(
Value z ,
const Stopwatch & c ) : inc( z ) , clock( c ) {}
218 BBIncumbent< Node , Value > inc;
219 const Stopwatch & clock;
220 alignas(
cache_line ) std::atomic< std::uint64_t > evaluated{ 0 };
221 std::atomic< bool > limit{
false };
222 std::atomic< bool > time{
false };
231 std::vector< Leaf > && starts )
232 : f_a( a ) , f_sh( s ) , f_q( a.f_options.selection ) ,
233 f_fr( a.f_options.keep_frontier ) , v_starts( std::move( starts ) ) {}
235 Master(
const Master & ) =
delete;
236 Master & operator=(
const Master & ) =
delete;
239 for( Task * t : v_free )
245 void start( E && emit ) {
246 for(
auto & l : v_starts )
247 enqueue( Item{ std::move( l.node ) , l.bound , l.depth } );
256 bool back( Task * t , E && emit ) {
258 for( Item & it : t->kids )
259 enqueue( std::move( it ) );
261 v_free.push_back( t );
264 return( ( f_out > 0 ) || ( ! f_sh.limit.load() && ! f_q.empty() ) );
268 void enqueue( Item && it ) {
269 const Value key = detail::bb_key( f_a.f_p , it.node , it.bound ,
270 it.depth , f_a.f_options.selection );
271 f_q.push( std::move( it.node ) , it.bound , it.depth , key );
272 f_st.max_open = std::max( f_st.max_open , f_q.size() );
276 void check_limits(
void ) {
277 ( void ) detail::bb_limit( f_a.f_options , f_sh.evaluated.load() ,
278 f_sh.clock , f_sh.limit , f_sh.time );
283 void dispatch( E && emit ) {
284 while( ! f_sh.limit.load() && ( f_out < f_a.f_options.threads ) &&
286 const Value best = f_q.best_bound();
287 if( detail::bb_prunable( best , f_sh.inc.value() , f_a.f_options ) ) {
299 while( ! f_q.empty() && ( t->nodes.size() < f_a.f_options.batch ) )
300 t->nodes.push_back( f_q.pop() );
301 t->best = std::min( best , f_q.best_bound() );
310 BBQueue< Node , Value > f_q;
311 std::vector< Task * > v_free;
314 detail::BBFrontier< Node , Value > f_fr;
315 std::vector< Leaf > v_starts;
324 : f_a( a ) , f_sh( s ) , f_id( i ) ,
325 f_fr( a.f_options.keep_frontier ) {}
328 Task * process( Task * t ) {
330 if( ! ADS::isRunCaller() )
332 f_w.emplace( detail::bb_worker( f_a.f_p , f_id ) );
334 const auto & o = f_a.f_options;
335 const auto inc = [ & ] {
return( f_sh.inc.value() ); };
336 const auto improve = [ & ](
Value v ,
const Node & n ) {
337 return( f_sh.inc.template improve< P >( v , n , o ) );
339 for( Item & first : t->nodes ) {
340 std::optional< Item > it( std::move( first ) );
343 detail::bb_process< P >( it->node , it->bound , it->depth , *f_w , inc ,
346 v_kids.push_back( Item{ std::move( c ) , b ,
348 } , o , f_st , f_fr );
349 f_sh.evaluated.fetch_add( 1 );
351 const std::size_t k = detail::bb_dive( v_kids , t->best , inc() , o );
352 for( std::size_t j = 0 ; j < v_kids.size() ; ++j )
354 it.emplace( std::move( v_kids[ j ] ) );
356 t->kids.push_back( std::move( v_kids[ j ] ) );
357 if( it && o.node_limit &&
358 ( f_sh.evaluated.load() >= o.node_limit ) ) {
359 t->kids.push_back( std::move( *it ) );
368 using Evaluator =
decltype( detail::bb_worker( std::declval< const P & >() ,
374 std::optional< Evaluator > f_w;
375 std::vector< Item > v_kids;
377 detail::BBFrontier< Node , Value > f_fr;
384 Executor * f_ex =
nullptr;