185 : f_domain( domain ) , f_options( options ) , f_ddd( std::move( ddd ) )
188 throw( std::invalid_argument(
"DDDAStar: no partition" ) );
197 Run r( f_domain , f_options , f_ddd );
199 sol.
stats = std::move( r.st );
214 std::uint64_t parent;
220 std::uint64_t parent;
221 [[no_unique_address]] OperatorOf< D > o;
227 std::uint64_t operator()(
const State & s )
const {
228 return( d->hash( s ) );
232 using Table = ADS::FlatHashTable< State , Val , Hash >;
238 bool operator<(
const Key & o )
const {
239 return( ( f < o.f ) || ( ( f == o.f ) && ( g < o.g ) ) );
247 const SearchOptions & opt;
248 const DDDOptions & ddd;
249 ADS::TempDirectory dir;
251 std::set< Key > open;
252 std::map< Cost , std::vector< Cost > > closed;
256 Run(
const D & domain ,
const SearchOptions & o ,
const DDDOptions & x )
257 : d( domain ) , opt( o ) , ddd( x ) , dir( x.directory ,
"pbefs-ddd-" ) ,
258 buffer( std::max< std::size_t >( 1 , x.buffer_bytes / sizeof( Rec ) ) )
262 [[nodiscard]] ADS::RecordFile< Rec > file(
char kind ,
Cost g ,
Cost h ,
263 std::size_t p )
const {
264 return( ADS::RecordFile< Rec >( dir / ( std::string( 1 , kind ) +
"_" +
265 std::to_string( g ) +
"_" +
266 std::to_string( h ) +
"_" +
267 std::to_string( p ) ) ) );
270 [[nodiscard]] std::size_t part(
const State & s )
const {
271 return( std::size_t( d.hash( s ) % ddd.partitions ) );
276 const State s0 = d.initial_state();
277 const Cost h0 = d.heuristic( s0 );
279 const Rec root{ s0 , d.hash( s0 ) , {} };
280 file(
'o' ,
Cost( 0 ) , h0 , part( s0 ) ).append( &root , 1 );
281 open.insert( Key{ h0 ,
Cost( 0 ) } );
284 while( ! open.empty() ) {
285 const Key k = *open.begin();
286 open.erase( open.begin() );
287 const Cost g = k.g , h = k.f - k.g;
290 std::map< std::tuple< Cost , Cost , std::size_t > ,
291 std::pair< std::unique_ptr< ADS::RecordFile< Rec > > ,
292 std::unique_ptr< ADS::RecordWriter< Rec > > > > out;
293 const auto writer = [ & ](
Cost gv ,
Cost hv , std::size_t p )
294 -> ADS::RecordWriter< Rec > & {
295 auto & slot = out[ { gv , hv , p } ];
296 if( ! slot.second ) {
297 slot.first = std::make_unique< ADS::RecordFile< Rec > >(
298 file(
'o' , gv , hv , p ) );
299 slot.second = std::make_unique< ADS::RecordWriter< Rec > >(
300 *slot.first , buffer );
302 return( *slot.second );
304 for( std::size_t p = 0 ; p < ddd.partitions ; ++p ) {
305 auto in = file(
'o' , g , h , p );
310 Table t( in.size() , Hash{ &d } );
311 in.forEach( [ & ](
const Rec & x ) {
312 if( ! t.insert( x.s , Val{ x.parent , x.o } ) )
316 const auto cl = closed.find( h );
317 if( cl != closed.end() )
318 for(
Cost gc : cl->second )
319 file(
'c' , gc , h , p ).forEach( [ & ](
const Rec & x ) {
320 if( t.remove( x.s ) )
326 std::vector< Rec > fresh;
327 fresh.reserve( t.size() );
328 t.forEach( [ & ](
const State & s ,
const Val & v ) {
329 fresh.push_back( Rec{ s , v.parent , v.o } );
331 file(
'c' , g , h , p ).append( fresh.data() , fresh.size() );
332 st.stored += fresh.size();
335 for(
const Rec & x : fresh )
336 if( d.is_goal( x.s ) ) {
337 mark_closed( g , h );
340 sol.path = trace( x , g );
344 for(
const Rec & x : fresh ) {
346 const std::uint64_t hu = d.hash( x.s );
352 throw( std::logic_error(
"DDDAStar: an edge of a cost that is not"
354 if( g + c + hv < k.f )
355 throw( std::logic_error(
"DDDAStar: the heuristic is not"
357 writer( g + c , hv , part( v ) ).push( Rec{ v , hu , ov } );
361 if( opt.node_limit && ( st.stored >= opt.node_limit ) ) {
362 mark_closed( g , h );
368 for(
auto & [ key , fw ] : out ) {
370 const auto [ gv , hv , p ] = key;
371 open.insert( Key{ gv + hv , gv } );
373 mark_closed( g , h );
380 void mark_closed(
Cost g ,
Cost h ) {
381 auto it = closed.find( h );
382 if( ( it != closed.end() ) &&
383 ( std::find( it->second.begin() , it->second.end() , g ) ==
385 it->second.push_back( g );
392 std::vector< State > trace( Rec x ,
Cost g ) {
393 std::vector< State > path{ x.s };
394 const State s0 = d.initial_state();
395 while( ! ( ( g ==
Cost( 0 ) ) && ( x.s == s0 ) ) ) {
396 const std::size_t p = std::size_t( x.parent % ddd.partitions );
398 for(
const auto & e : closed ) {
399 const Cost hc = e.first;
400 for(
Cost gc : e.second ) {
403 file(
'c' , gc , hc , p ).forEach( [ & ](
const Rec & y ) {
404 if( found || ( d.hash( y.s ) != x.parent ) )
406 d.for_each_successor( y.s , hc , [ & ](
const State & v ,
Cost c ,
408 if( ! found && ( v == x.s ) && ( gc + c == g ) ) {
422 throw( std::logic_error(
"DDDAStar: the parent of a state is not in"
423 " the closed files" ) );
424 path.push_back( x.s );
426 std::reverse( path.begin() , path.end() );
435 SearchOptions f_options;
Header file for the concepts a search problem has to satisfy in order to be searched by the algorithm...
a Domain that DDDAStar can search: integer costs, since a bucket is a pair of values,...
Definition DDDAStar.h:135