172 : f_domain( domain ) , f_options( options ) {
174 if( f_options.
eps < 1 )
190 const unsigned p = f_options.threads;
193 std::vector< std::unique_ptr< Worker > > w( p );
194 for(
unsigned i = 0 ; i < p ; ++i )
195 w[ i ] = std::make_unique< Worker >( *
this , sh );
198 const State s0 = f_domain.initial_state();
199 NodeT * root = w[ 0 ]->f_pool.allocate();
200 *root =
NodeT{ s0 ,
Cost( 0 ) ,
Cost( f_domain.heuristic( s0 ) ) ,
201 nullptr , false ,
false };
202 sh.table.find_or_insert( s0 , f_domain.hash( s0 ) ,
203 [ & ] { return( root ); } );
204 sh.open.insert( Key( root ) ,
true );
207 run_workers( f_ex , p , [ & ](
unsigned i ) { w[ i ]->run(); } );
211 for(
auto & x : w ) {
215 st.
stored += x->f_pool.size();
217 st.
stored_by.push_back( x->f_pool.size() );
224 sol.cost = sh.goal->
g;
235 using Lock =
typename Executor::lock_type;
240 std::conditional_t< std::is_integral_v< Cost > , std::uint64_t ,
241 std::pair< Cost , Cost > > fg{};
242 std::uintptr_t node = 0;
244 Key(
void ) =
default;
246 explicit Key(
const NodeT * x )
247 : node( reinterpret_cast< std::uintptr_t >( x ) ) {
248 if constexpr( std::is_integral_v< Cost > )
251 fg = { x->f() , - x->g };
254 NodeT * get(
void )
const {
return(
reinterpret_cast< NodeT *
>( node ) ); }
256 friend auto operator<=>(
const Key & ,
const Key & ) =
default;
264 std::condition_variable_any changed;
265 ADS::BTreeMap< Key , bool > open;
266 std::vector< NodeT * > be;
267 NodeTable< NodeT > table;
269 bool limit_hit =
false;
270 NodeT * goal =
nullptr;
276 struct alignas( cache_line ) Worker {
278 Worker(
const PASE & a , Shared & s ) : f_a( a ) , f_sh( s ) {}
281 static constexpr std::size_t c_candidates = 64;
286 bool independent(
const NodeT * s ,
const NodeT * t )
const {
287 const double lhs = double( s->g - t->g );
288 const double rhs = f_a.f_options.eps *
289 double( f_a.f_domain.pairwise_heuristic( t->state , s->state ) );
290 if constexpr( std::is_floating_point_v< Cost > )
291 return( lhs <= rhs + 1e-9 * std::max( 1.0 ,
292 std::abs(
double( s->g ) ) ) );
294 return( lhs <= rhs );
302 bool safe(
const NodeT * s )
const {
303 for(
const NodeT * t : f_sh.be )
304 if( ! independent( s , t ) )
306 const Cost fs = s->f();
307 for(
const auto & k : f_sh.open ) {
308 const NodeT * t = k.first.get();
309 if( ! ( t->f() < fs ) )
311 if( ! independent( s , t ) )
319 std::vector< std::tuple<
State ,
Cost ,
Cost , std::uint64_t ,
320 std::uint8_t > > succ;
321 std::unique_lock< Lock > guard( f_sh.lock );
322 while( ! f_sh.done ) {
329 for(
const auto & k : f_sh.open ) {
330 if( n++ == c_candidates )
332 if( safe( k.first.get() ) ) {
338 if( f_sh.open.empty() && f_sh.be.empty() ) {
340 f_sh.changed.notify_all();
343 f_sh.changed.wait( guard );
346 f_sh.open.remove( Key( s ) );
347 if( f_a.f_domain.is_goal( s->state ) ) {
350 f_sh.changed.notify_all();
353 f_sh.be.push_back( s );
354 s->closed = s->expanded =
true;
355 const State st = s->state;
356 const Cost g = s->g , h = s->h;
357 const std::uint8_t op = s->op;
365 succ.emplace_back( t , g + c , ht , f_a.f_domain.hash( t ) , ot );
372 for(
const auto & sc : succ )
373 f_sh.table.prefetch( std::get< 3 >( sc ) );
374 for(
const auto & sc : succ ) {
375 const State & t = std::get< 0 >( sc );
376 const Cost gt = std::get< 1 >( sc ) , ht = std::get< 2 >( sc );
378 auto [ x , fresh ] = f_sh.table.find_or_insert( t ,
379 std::get< 3 >( sc ) ,
381 NodeT * y = f_pool.allocate();
382 *y =
NodeT{ t , gt , ht , s , false , false , std::get< 4 >( sc ) };
386 f_sh.open.insert( Key( x ) ,
true );
388 if( ! x->closed && ( gt < x->g ) ) {
389 f_sh.open.remove( Key( x ) );
392 x->op = std::get< 4 >( sc );
393 f_sh.open.insert( Key( x ) ,
true );
398 f_sh.be.erase( std::find( f_sh.be.begin() , f_sh.be.end() , s ) );
399 if( f_a.f_options.node_limit &&
400 ( f_pool.size() >= f_a.f_options.node_limit ) ) {
401 f_sh.limit_hit =
true;
404 f_sh.changed.notify_all();
410 NodePool< NodeT > f_pool;
417 PASEOptions f_options;
418 Executor * f_ex =
nullptr;
void run_workers(Executor *ex, unsigned p, F &&f)
runs the workers f( 0 ) , ... , f( p - 1 ) at once on an Executor
Definition SearchUtils.h:121