127 using Node =
typename P::node_type;
139 : f_p( problem ) , f_options( options ) {
154 return( run( std::nullopt ) );
162 return( run( std::move( seeds ) ) );
176 std::vector< Item > kids;
177 std::optional< std::pair< Value , Node > > best;
179 detail::BBFrontier< Node , Value > fr;
184 SolutionT run( std::optional< std::vector< Leaf > > seeds )
const
189 const std::size_t round = o.round ? o.round : p;
192 BBQueue< Node , Value > q( o.selection );
194 BBStats & st = sol.
stats;
196 const auto push = [ & ]( Item && it ) {
197 const Value key = detail::bb_key( f_p , it.node , it.bound , it.depth ,
199 q.push( std::move( it.node ) , it.bound , it.depth , key );
200 st.max_open = std::max( st.max_open , q.size() );
202 for(
auto & l : detail::bb_starts( f_p , std::move( seeds ) ) )
203 push( Item{ std::move( l.node ) , l.bound , l.depth } );
205 BBIncumbent< Node , Value > inc( o.incumbent ?
206 detail::bb_signed< P >( *o.incumbent ) :
208 detail::BBFrontier< Node , Value > fr( o.keep_frontier );
209 std::vector< Slot > slots( round );
210 std::size_t nslots = 0;
211 Value snapshot = inc.value();
212 bool done = false , limit = false , late =
false;
213 std::exception_ptr error;
219 const auto next_round = [ & ]( void )
noexcept {
221 for( std::size_t j = 0 ; j < nslots ; ++j ) {
222 Slot & s = slots[ j ];
224 add_counters( st , s.st );
225 st.evaluated_by[ j % p ] += s.st.evaluated;
226 if( s.best && inc.template improve< P >( s.best->first ,
227 s.best->second , o ) )
229 fr.merge( std::move( s.fr ) );
230 for( Item & k : s.kids )
231 if( detail::bb_prunable( k.bound , inc.value() , o ) ) {
232 ++st.pruned_generated;
233 fr.add( std::move( k.node ) , k.bound , k.depth ,
237 push( std::move( k ) );
245 if( o.node_limit && ( st.evaluated >= o.node_limit ) ) {
249 if( ( o.time_limit > 0 ) && ( clock.seconds() >= o.time_limit ) ) {
250 limit = late = done =
true;
257 if( detail::bb_prunable( q.best_bound() , inc.value() , o ) ) {
263 std::size_t r = round;
265 r = std::min( r , std::size_t( o.node_limit - st.evaluated ) );
266 while( ( nslots < r ) && ! q.empty() ) {
267 Slot & s = slots[ nslots++ ];
272 s.fr = detail::BBFrontier< Node , Value >( o.keep_frontier );
274 snapshot = inc.value();
277 std::lock_guard< std::mutex > guard( error_m );
279 error = std::current_exception();
284 std::barrier sync( std::ptrdiff_t( p ) , next_round );
286 auto w = detail::bb_worker( f_p , i );
288 sync.arrive_and_wait();
291 for( std::size_t j = i ; j < nslots ; j += p ) {
292 Slot & s = slots[ j ];
294 detail::bb_process< P >( s.it.node , s.it.bound , s.it.depth , w ,
295 [ & ] { return( snapshot ); } ,
297 if( ( v >= snapshot ) ||
298 ( s.best && ( v >= s.best->first ) ) )
300 s.best.emplace( v , n );
303 [ & ](
Node && c ,
Value b ,
unsigned d ) {
304 s.kids.push_back( Item{ std::move( c ) , b ,
306 } , o , s.st , s.fr );
309 std::lock_guard< std::mutex > guard( error_m );
311 error = std::current_exception();
317 std::rethrow_exception( error );
320 detail::bb_finish< P >( sol , inc , fr , limit , late );
321 st.seconds = clock.seconds();
329 a.evaluated += b.evaluated;
330 a.branched += b.branched;
331 a.generated += b.generated;
332 a.infeasible += b.infeasible;
333 a.pruned_generated += b.pruned_generated;
334 a.pruned_extracted += b.pruned_extracted;
335 a.pruned_evaluated += b.pruned_evaluated;
336 a.incumbents += b.incumbents;
343 Executor * f_ex =
nullptr;