131#ifndef __PBeFS_PatternDatabase
132 #define __PBeFS_PatternDatabase
179#include "ADS/succinct/PackedArray.h"
181#include "ADS/succinct/RankSelect.h"
232template<
int W ,
int H >
243 static_assert( ( W >= 2 ) && ( H >= 2 ) && (
cells <= 32 ) ,
244 "TilePattern: at most 32 cells" );
251 int cell[ 4 ] = { 0 , 0 , 0 , 0 };
260 for(
int i = 0 ; i <
cells ; ++i )
261 b[ i ] =
static_cast< std::uint8_t
>( i );
274 std::uint64_t seen = 0;
275 for( std::uint8_t t :
goal ) {
276 if( ( t >=
cells ) || ( ( seen >> t ) & 1u ) )
277 throw( std::invalid_argument(
"TilePattern::TilePattern: the goal is "
278 "not a permutation" ) );
279 seen |= std::uint64_t( 1 ) << t;
282 throw( std::invalid_argument(
"TilePattern::TilePattern: a pattern has "
283 "1 to W H - 1 tiles" ) );
285 for(
int t :
tiles ) {
286 if( ( t <= 0 ) || ( t >= cells ) || ( ( seen >> t ) & 1u ) )
287 throw( std::invalid_argument(
"TilePattern::TilePattern: bad tile " +
288 std::to_string( t ) ) );
289 seen |= std::uint64_t( 1 ) << t;
291 f_k =
int(
tiles.size() );
293 for(
int c = 0 ; c <
cells ; ++c )
294 cell[
goal[ c ] %
cells ] = std::uint8_t( c );
295 for( std::size_t i = 0 ; i < v_goal_cell.size() ; ++i )
296 if( i <
tiles.size() )
297 v_goal_cell[ i ] = cell[ std::size_t(
tiles[ i ] ) %
cells ];
299 for(
int i = 0 ; i < f_k ; ++i )
300 f_entries *= std::uint64_t(
cells - i );
301 f_goal_rank =
rank( v_goal_cell.data() );
307 [[nodiscard]]
int size(
void )
const noexcept {
return( f_k ); }
312 [[nodiscard]]
const std::vector< int > &
tiles(
void )
const noexcept {
327 return( v_goal_cell[ i ] );
333 [[nodiscard]] std::uint64_t
entries(
void )
const noexcept {
340 [[nodiscard]] std::uint64_t
goal_rank(
void )
const noexcept {
341 return( f_goal_rank );
347 [[nodiscard]] std::uint64_t
rank(
const std::uint8_t * p )
const noexcept {
349 std::uint32_t used = 0;
350 for(
int i = 0 ; i < f_k ; ++i ) {
351 const std::uint32_t below = used & ( ( std::uint32_t( 1 ) << p[ i ] ) -
353 r = r * std::uint64_t(
cells - i ) +
354 std::uint64_t( p[ i ] - std::popcount( below ) );
355 used |= std::uint32_t( 1 ) << p[ i ];
363 void unrank( std::uint64_t r , std::uint8_t * p )
const noexcept {
365 for(
int i = f_k - 1 ; i >= 0 ; --i ) {
366 d[ i ] = int( r % std::uint64_t(
cells - i ) );
367 r /= std::uint64_t(
cells - i );
369 std::uint32_t free =
c_full;
370 for(
int i = 0 ; i < f_k ; ++i ) {
371 p[ i ] = std::uint8_t(
select( free , d[ i ] ) );
372 free &= ~( std::uint32_t( 1 ) << p[ i ] );
379 [[nodiscard]]
int manhattan(
const std::uint8_t * p )
const noexcept {
381 for(
int i = 0 ; i < f_k ; ++i )
382 m +=
distance( p[ i ] , v_goal_cell[ i ] );
390 return( c_moves[ std::size_t( c ) ] );
396 [[nodiscard]]
static int distance(
int a ,
int b )
noexcept {
397 return( std::abs( a / W - b / W ) + std::abs( a % W - b % W ) );
403 static constexpr std::uint32_t
c_full =
cells == 32 ? ~std::uint32_t( 0 )
404 : ( std::uint32_t( 1 ) <<
cells ) - 1u;
409 [[nodiscard]]
static int select( std::uint32_t x ,
int j )
noexcept {
412 return( std::countr_zero( x ) );
419 [[nodiscard]]
static std::uint32_t
region( std::uint32_t free ,
int b )
421 std::uint32_t r = std::uint32_t( 1 ) << b , last = 0;
424 std::uint32_t g = r | ( r >> W ) | ( r << W ) |
425 ( ( r & ~c_right ) << 1 ) | ( ( r & ~c_left ) >> 1 );
436 static constexpr std::uint32_t c_left = [] {
438 for(
int r = 0 ; r < H ; ++r )
439 m |= std::uint32_t( 1 ) << ( r * W );
444 static constexpr std::uint32_t c_right = c_left << ( W - 1 );
447 static constexpr std::array< Moves , cells > c_moves = [] {
448 std::array< Moves , cells > m{};
449 for(
int b = 0 ; b <
cells ; ++b ) {
450 const int r = b / W , k = b % W;
451 Moves & o = m[ std::size_t( b ) ];
453 o.cell[ o.n++ ] = b - W;
455 o.cell[ o.n++ ] = b - 1;
457 o.cell[ o.n++ ] = b + 1;
459 o.cell[ o.n++ ] = b + W;
464 std::vector< int > v_tiles;
466 std::array< std::uint8_t , cells > v_goal_cell{};
468 std::uint64_t f_entries = 0;
469 std::uint64_t f_goal_rank = 0;
481[[nodiscard]]
inline std::vector< std::uint8_t > packed_bytes(
482 const std::vector< std::uint64_t > & w , std::size_t n )
484 std::vector< std::uint8_t > b( n );
485 for( std::size_t i = 0 ; i < n ; ++i )
486 b[ i ] = std::uint8_t( w[ i >> 3 ] >> ( 8 * ( i & 7 ) ) );
492template<
unsigned B >
493[[nodiscard]]
inline unsigned packed_field(
const std::vector< std::uint8_t >
494 & d , std::uint64_t i )
noexcept
496 const std::uint64_t bit = i * B;
497 return( ( d[ bit >> 3 ] >> ( bit & 7 ) ) & ( ( 1u << B ) - 1 ) );
515 static constexpr std::uint32_t
code = 1;
516 static constexpr const char *
name =
"byte";
523 & h , M && ,
unsigned = 1 ) {
526 e.f_data = Array( ex , h.size() , [ & ]( std::size_t r ) {
535 std::uint64_t n ,
unsigned = 1 ) {
536 if( data.size() != n )
537 throw( std::runtime_error(
"ByteEntries::decode: bad size" ) );
538 return(
encode( data , 0 ) );
543 [[nodiscard]]
int value( std::uint64_t r ,
int )
const noexcept {
544 return(
int( f_data.get( r ) ) );
548 [[nodiscard]] std::uint64_t
entries(
void )
const noexcept {
549 return( f_data.size() );
553 [[nodiscard]] std::size_t
bytes(
void )
const noexcept {
554 return( f_data.size() );
558 [[nodiscard]] std::vector< std::uint8_t >
payload(
void )
const {
559 return( detail::packed_bytes( f_data.words() ,
bytes() ) );
564 using Array = ADS::PackedArray< 8 >;
580 static constexpr std::uint32_t
code = 2;
581 static constexpr const char *
name =
"nibble";
588 & h , M && m ,
unsigned = 1 ) {
591 e.f_data = Array( ex , h.size() , [ & ]( std::size_t r ) {
592 return( std::uint64_t( excess( h[ r ] , m( r ) ) ) );
600 std::uint64_t n ,
unsigned = 1 ) {
601 if( data.size() != ( n + 1 ) / 2 )
602 throw( std::runtime_error(
"NibbleEntries::decode: bad size" ) );
605 e.f_data = Array( ex , n , [ & ]( std::size_t r ) {
606 return( detail::packed_field< 4 >( data , r ) );
613 [[nodiscard]]
int value( std::uint64_t r ,
int m )
const noexcept {
614 return( m + 2 *
int( f_data.get( r ) ) );
618 [[nodiscard]] std::uint64_t
clamped(
void )
const noexcept {
619 return( f_data.clamped() );
623 [[nodiscard]] std::uint64_t
entries(
void )
const noexcept {
624 return( f_data.size() );
628 [[nodiscard]] std::size_t
bytes(
void )
const noexcept {
629 return( ( f_data.size() + 1 ) / 2 );
633 [[nodiscard]] std::vector< std::uint8_t >
payload(
void )
const {
634 return( detail::packed_bytes( f_data.words() ,
bytes() ) );
639 [[nodiscard]]
static int excess(
int h ,
int m ) {
640 if( ( h < m ) || ( ( h - m ) % 2 ) )
641 throw( std::logic_error(
"NibbleEntries::excess: h - m is not even "
642 "and nonnegative" ) );
643 return( ( h - m ) / 2 );
648 using Array = ADS::PackedArray< 4 , true >;
668 static constexpr std::uint32_t
code = 3;
669 static constexpr const char *
name =
"mod3";
677 & h , M && ,
unsigned = 1 ) {
680 e.f_data = ADS::TritArray( ex , h.size() , [ & ]( std::size_t r ) {
681 return( unsigned( h[ r ] % 3 ) );
689 std::uint64_t n ,
unsigned = 1 ) {
690 if( data.size() != ( n + 4 ) / 5 )
691 throw( std::runtime_error(
"Mod3Entries::decode: bad size" ) );
692 for( std::uint8_t b : data )
694 throw( std::runtime_error(
"Mod3Entries::decode: bad byte" ) );
695 static constexpr unsigned power[ 5 ] = { 1 , 3 , 9 , 27 , 81 };
698 e.f_data = ADS::TritArray( ex , n , [ & ]( std::size_t r ) {
699 return( data[ r / 5 ] / power[ r % 5 ] % 3 );
707 [[nodiscard]]
int residue( std::uint64_t r ,
int )
const noexcept {
708 return(
int( f_data.get( r ) ) );
712 [[nodiscard]] std::uint64_t
entries(
void )
const noexcept {
713 return( f_data.size() );
717 [[nodiscard]] std::size_t
bytes(
void )
const noexcept {
718 return( f_data.bytes() );
722 [[nodiscard]] std::vector< std::uint8_t >
payload(
void )
const {
723 return( f_data.data() );
728 ADS::TritArray f_data;
747 static constexpr std::uint32_t
code = 6;
748 static constexpr const char *
name =
"bit";
756 const std::vector< std::uint8_t > & h , M && m ,
unsigned = 1 ) {
759 e.f_data = Array( ex , h.size() , [ & ]( std::size_t r ) {
760 static_cast< void >( NibbleEntries::excess( h[ r ] , m( r ) ) );
761 return( std::uint64_t( ( h[ r ] >> 1 ) & 1 ) );
769 std::vector< std::uint8_t > data , std::uint64_t n ,
unsigned = 1 ) {
770 if( data.size() != ( n + 7 ) / 8 )
771 throw( std::runtime_error(
"ParityBitEntries::decode: bad size" ) );
774 e.f_data = Array( ex , n , [ & ]( std::size_t r ) {
775 return( detail::packed_field< 1 >( data , r ) );
783 [[nodiscard]]
int residue( std::uint64_t r ,
int m )
const noexcept {
784 return( 2 *
int( f_data.get( r ) ) + ( m & 1 ) );
788 [[nodiscard]] std::uint64_t
entries(
void )
const noexcept {
789 return( f_data.size() );
793 [[nodiscard]] std::size_t
bytes(
void )
const noexcept {
794 return( ( f_data.size() + 7 ) / 8 );
798 [[nodiscard]] std::vector< std::uint8_t >
payload(
void )
const {
799 return( detail::packed_bytes( f_data.words() ,
bytes() ) );
804 using Array = ADS::PackedArray< 1 >;
825 static constexpr std::uint32_t
code = 4;
826 static constexpr const char *
name =
"min";
833 const std::vector< std::uint8_t > & h , M && m ,
unsigned c = 1 ) {
836 e.set_group( h.size() , c );
837 e.f_data = Array( ex , e.groups() , [ & ]( std::size_t g ) {
838 const std::uint64_t a = std::uint64_t( g ) << e.f_shift;
839 const std::uint64_t b = std::min( e.f_n , a + ( 1u << e.f_shift ) );
841 for( std::uint64_t r = a ; r < b ; ++r )
842 x = std::min( x , NibbleEntries::excess( h[ r ] , m( r ) ) );
843 return( std::uint64_t( x ) );
851 std::vector< std::uint8_t > data , std::uint64_t n ,
unsigned c = 1 ) {
853 e.set_group( n , c );
854 if( data.size() != ( e.groups() + 1 ) / 2 )
855 throw( std::runtime_error(
"MinNibbleEntries::decode: bad size" ) );
857 e.f_data = Array( ex , e.groups() , [ & ]( std::size_t g ) {
858 return( detail::packed_field< 4 >( data , g ) );
865 [[nodiscard]]
int value( std::uint64_t r ,
int m )
const noexcept {
866 return( m + 2 *
int( f_data.get( r >> f_shift ) ) );
870 [[nodiscard]] std::uint64_t
entries(
void )
const noexcept {
return( f_n ); }
873 [[nodiscard]]
unsigned group(
void )
const noexcept {
874 return( 1u << f_shift );
878 [[nodiscard]] std::size_t
bytes(
void )
const noexcept {
879 return( ( groups() + 1 ) / 2 );
883 [[nodiscard]] std::vector< std::uint8_t >
payload(
void )
const {
884 return( detail::packed_bytes( f_data.words() ,
bytes() ) );
889 using Array = ADS::PackedArray< 4 >;
892 void set_group( std::uint64_t n ,
unsigned c ) {
893 if( ( c == 0 ) || ! std::has_single_bit( c ) )
894 throw( std::invalid_argument(
"MinNibbleEntries::set_group: the group "
895 "is a power of 2" ) );
897 f_shift = std::countr_zero( c );
901 [[nodiscard]] std::uint64_t groups(
void )
const noexcept {
902 return( ( f_n + ( std::uint64_t( 1 ) << f_shift ) - 1 ) >> f_shift );
906 std::uint64_t f_n = 0;
929 static constexpr std::uint32_t
code = 5;
930 static constexpr const char *
name =
"sparse";
938 & h , M && m ,
unsigned = 1 ) {
939 ADS::BitVector b( h.size() );
941 for( std::uint64_t r = 0 ; r < h.size() ; ++r ) {
942 const int mr = m( r );
943 if( ( h[ r ] < mr ) || ( ( h[ r ] - mr ) % 2 ) )
944 throw( std::logic_error(
"SparseEntries::encode: h - m is not even "
945 "and nonnegative" ) );
946 const int e = ( h[ r ] - mr ) / 2;
950 x.push_back( Excesses::Word( e ) );
953 s.f_bits = ADS::RankSelect( std::move( b ) );
954 s.f_excess = std::move( x );
963 std::uint64_t n ,
unsigned = 1 ) {
964 const std::uint64_t words = ( n + 63 ) / 64;
965 if( data.size() < 8 * words )
966 throw( std::runtime_error(
"SparseEntries::decode: bad size" ) );
967 ADS::BitVector b( n );
969 for( std::uint64_t w = 0 ; w < words ; ++w ) {
971 for(
int i = 0 ; i < 8 ; ++i )
972 x |= std::uint64_t( data[ 8 * w + std::uint64_t( i ) ] ) << ( 8 * i );
973 if( ( w + 1 == words ) && ( n % 64 ) && ( x >> ( n % 64 ) ) )
974 throw( std::runtime_error(
"SparseEntries::decode: bits past the "
976 z += std::uint64_t( std::popcount( x ) );
977 for( ; x ; x &= x - 1 )
978 b.set( 64 * w + std::uint64_t( std::countr_zero( x ) ) );
980 if( data.size() != 8 * words + ( z + 1 ) / 2 )
981 throw( std::runtime_error(
"SparseEntries::decode: bad size" ) );
982 const std::vector< std::uint8_t > tail( data.begin() +
983 std::ptrdiff_t( 8 * words ) ,
987 s.f_bits = ADS::RankSelect( std::move( b ) );
988 s.f_excess = Excesses( ex , z , [ & ]( std::size_t i ) {
989 return( detail::packed_field< 4 >( tail , i ) );
997 [[nodiscard]]
int value( std::uint64_t r ,
int m )
const {
1000 return( m + 2 *
int( f_excess.get( f_bits.rank1( r ) ) ) );
1006 [[nodiscard]] std::uint64_t
entries(
void )
const noexcept {
1007 return( f_bits.size() );
1013 [[nodiscard]] std::uint64_t
nonzero(
void )
const noexcept {
1014 return( f_bits.ones() );
1020 [[nodiscard]] std::size_t
bytes(
void )
const noexcept {
1021 return( ( f_bits.size() + 63 ) / 64 * 8 + f_bits.directoryBits() / 8 +
1022 ( f_excess.size() + 1 ) / 2 );
1028 [[nodiscard]] std::vector< std::uint8_t >
payload(
void )
const {
1029 std::vector< std::uint8_t > d;
1030 const auto & w = f_bits.bits().words();
1031 const std::size_t words = ( f_bits.size() + 63 ) / 64;
1032 const auto x = detail::packed_bytes( f_excess.words() ,
1033 ( f_excess.size() + 1 ) / 2 );
1034 d.reserve( 8 * words + x.size() );
1035 for( std::size_t i = 0 ; i < words ; ++i )
1036 for(
int k = 0 ; k < 8 ; ++k )
1037 d.push_back( std::uint8_t( w[ i ] >> ( 8 * k ) ) );
1038 d.insert( d.end() , x.begin() , x.end() );
1046 using Excesses = ADS::PackedArray< 4 , true >;
1048 ADS::RankSelect f_bits;
1066template<
int W ,
int H ,
class Enc = NibbleEntries >
1089 : f_pattern( p ) , f_rule(
rule ) , f_compress( compress ) ,
1091 if constexpr( Enc::relative )
1093 throw( std::invalid_argument(
"PatternTable::PatternTable: the "
1094 "residues need the blank ignored" ) );
1095 if( f_entries.entries() != p.
entries() )
1096 throw( std::invalid_argument(
"PatternTable::PatternTable: entries and "
1097 "pattern differ" ) );
1098 for(
int i = 0 ; i < p.
size() ; ++i )
1099 for(
int c = 0 ; c <
cells ; ++c )
1100 v_md[ std::size_t( i ) ][ std::size_t( c ) ] =
1110 template< ADS::WorkerExecutor Executor = ADS::ThreadPool >
1114 threads = std::max( 1u , std::thread::hardware_concurrency() );
1116 ? distances_ignored< Executor >( p , threads )
1117 : distances_minimized< Executor >( p , threads );
1118 for( std::uint8_t x : h )
1120 throw( std::logic_error(
"PatternTable::distances: a placement is "
1130 const std::vector< std::uint8_t >
1131 & h ,
unsigned compress = 1 ) {
1132 std::vector< std::uint8_t > q( std::size_t( p.
size() ) );
1133 auto m = [ & ]( std::uint64_t r ) {
1134 p.
unrank( r , q.data() );
1138 Enc::encode( h , m , compress ) ) );
1144 template< ADS::WorkerExecutor Executor = ADS::ThreadPool >
1147 unsigned compress = 1 ,
1148 unsigned threads = 0 ) {
1156 [[nodiscard]]
int value(
const std::uint8_t * q )
const noexcept
1157 requires( ! Enc::relative ) {
1158 return( f_entries.value( f_pattern.rank( q ) ,
manhattan( q ) ) );
1164 [[nodiscard]]
int manhattan(
const std::uint8_t * q )
const noexcept {
1166 for(
int i = 0 ; i < f_pattern.size() ; ++i )
1167 m += v_md[ std::size_t( i ) ][ q[ i ] ];
1174 [[nodiscard]]
int residue(
const std::uint8_t * q )
const noexcept
1175 requires( Enc::relative ) {
1176 return( f_entries.residue( f_pattern.rank( q ) ,
manhattan( q ) ) );
1187 [[nodiscard]]
int exact(
const std::uint8_t * q )
const
1188 requires( Enc::relative ) {
1189 const int k = f_pattern.size();
1190 std::uint8_t p[
cells ];
1191 std::copy( q , q + k , p );
1192 constexpr int M = Enc::modulus;
1193 std::uint64_t r = f_pattern.rank( p );
1195 while( r != f_pattern.goal_rank() ) {
1196 const int want = (
residue( p ) + M - 1 ) % M;
1197 std::uint32_t occ = 0;
1198 for(
int i = 0 ; i < k ; ++i )
1199 occ |= std::uint32_t( 1 ) << p[ i ];
1201 for(
int i = 0 ; ( i < k ) && ! moved ; ++i ) {
1203 for(
int j = 0 ; j < mv.n ; ++j ) {
1204 const int c = mv.cell[ j ];
1205 if( ( occ >> c ) & 1u )
1207 const std::uint8_t old = p[ i ];
1208 p[ i ] = std::uint8_t( c );
1210 r = f_pattern.rank( p );
1218 throw( std::logic_error(
"PatternTable::exact: no neighbour one step "
1219 "closer to the goal" ) );
1229 return( f_pattern );
1240 [[nodiscard]]
const Enc &
entries(
void )
const noexcept {
1241 return( f_entries );
1247 [[nodiscard]] std::size_t
bytes(
void )
const noexcept {
1248 return( f_entries.bytes() );
1255 return( f_from_file );
1268 void save(
const std::string & path )
const {
1269 std::vector< std::uint8_t > b = header( f_pattern , f_rule ,
1271 const auto pay = f_entries.payload();
1272 put( b , f_entries.entries() , 8 );
1273 put( b , pay.size() , 8 );
1274 b.insert( b.end() , pay.begin() , pay.end() );
1275 put( b ,
checksum( b.data() , b.size() ) , 8 );
1276 const std::string tmp = path +
".tmp" +
1277 std::to_string( std::hash< std::thread::id >()(
1278 std::this_thread::get_id() ) );
1280 std::ofstream out( tmp , std::ios::binary | std::ios::trunc );
1281 out.write(
reinterpret_cast< const char *
>( b.data() ) ,
1282 std::streamsize( b.size() ) );
1284 throw( std::runtime_error(
"PatternTable::save: cannot write " + tmp )
1287 std::filesystem::rename( tmp , path );
1298 unsigned compress = 1 ) {
1299 std::ifstream in( path , std::ios::binary );
1301 throw( std::runtime_error(
"PatternTable::load: cannot read " + path ) );
1302 std::vector< std::uint8_t > b( ( std::istreambuf_iterator< char >( in ) ) ,
1303 std::istreambuf_iterator< char >() );
1304 const std::vector< std::uint8_t > head = header( p ,
rule , compress );
1305 const std::size_t fixed = head.size() + 16;
1306 if( b.size() < fixed + 8 )
1307 throw( std::runtime_error(
"PatternTable::load: " + path +
1308 " is truncated" ) );
1309 if( ! std::equal( head.begin() , head.begin() + 12 , b.begin() ) )
1310 throw( std::runtime_error(
"PatternTable::load: " + path +
1311 " is not a table of this version" ) );
1312 if( get( b.data() + b.size() - 8 , 8 ) !=
1313 checksum( b.data() , b.size() - 8 ) )
1314 throw( std::runtime_error(
"PatternTable::load: " + path +
1315 " is corrupted (checksum)" ) );
1316 if( ! std::equal( head.begin() , head.end() , b.begin() ) )
1317 throw( std::runtime_error(
"PatternTable::load: " + path +
1318 " holds another table" ) );
1319 const std::uint64_t n = get( b.data() + head.size() , 8 );
1320 const std::uint64_t len = get( b.data() + head.size() + 8 , 8 );
1321 if( ( n != p.
entries() ) || ( len != b.size() - fixed - 8 ) )
1322 throw( std::runtime_error(
"PatternTable::load: " + path +
1323 " has wrong lengths" ) );
1324 std::vector< std::uint8_t > pay( b.begin() + std::ptrdiff_t( fixed ) ,
1327 Enc::decode( std::move( pay ) , n , compress ) ,
1336 unsigned compress = 1 ) {
1337 std::string s =
"pdb-" + std::to_string( W ) +
"x" + std::to_string( H ) +
1339 + Enc::name +
"-" + std::to_string( compress ) +
"-t";
1340 for( std::size_t i = 0 ; i < p.
tiles().size() ; ++i )
1341 s += ( i ?
"." :
"" ) + std::to_string( p.
tiles()[ i ] );
1342 const auto & g = p.
goal();
1344 std::snprintf( hex ,
sizeof( hex ) ,
"%016llx" ,
static_cast<
1345 unsigned long long >(
checksum( g.data() , g.size() ) ) );
1346 return( s +
"-g" + hex +
".pdb" );
1357 template< ADS::WorkerExecutor Executor = ADS::ThreadPool >
1361 unsigned compress = 1 ,
1362 unsigned threads = 0 ) {
1363 namespace fs = std::filesystem;
1364 const fs::path own = fs::path( dir ) /
file_name( p ,
rule , compress );
1365 if( fs::exists( own ) )
1367 return(
load( own.string() , p ,
rule , compress ) );
1369 catch( std::runtime_error & ) {}
1370 fs::create_directories( dir );
1372 const fs::path raw = fs::path( dir ) / Bytes::file_name( p ,
rule );
1373 std::vector< std::uint8_t > h;
1374 if( fs::exists( raw ) )
1376 h = Bytes::load( raw.string() , p ,
rule ).entries().payload();
1378 catch( std::runtime_error & ) {}
1386 t.
save( own.string() );
1393 [[nodiscard]]
static std::uint64_t
checksum(
const std::uint8_t * b ,
1394 std::size_t n )
noexcept {
1395 std::uint64_t h = ADS::splitmix64( 0x5042654653504442ULL ^ n );
1397 for( ; i + 8 <= n ; i += 8 )
1398 h = ADS::splitmix64( h ^ get( b + i , 8 ) ) + i;
1400 h = ADS::splitmix64( h ^ get( b + i ,
int( n - i ) ) );
1409 static constexpr std::uint8_t c_unseen = 0xFF;
1415 [[nodiscard]]
static std::vector< std::uint8_t > header(
const Pattern & p ,
1419 std::vector< std::uint8_t > b = {
'P' ,
'B' ,
'e' ,
'F' ,
'S' ,
'P' ,
'D' ,
1422 put( b , std::uint64_t( W ) , 4 );
1423 put( b , std::uint64_t( H ) , 4 );
1424 put( b , std::uint64_t(
rule ) , 4 );
1425 put( b , Enc::code , 4 );
1426 put( b , compress , 4 );
1427 put( b , std::uint64_t( p.size() ) , 4 );
1428 for(
int t : p.tiles() )
1429 b.push_back( std::uint8_t( t ) );
1430 b.insert( b.end() , p.goal().begin() , p.goal().end() );
1437 static void put( std::vector< std::uint8_t > & b , std::uint64_t x ,
1439 for(
int i = 0 ; i < k ; ++i )
1440 b.push_back( std::uint8_t( x >> ( 8 * i ) ) );
1446 [[nodiscard]]
static std::uint64_t get(
const std::uint8_t * b ,
int k )
1448 std::uint64_t x = 0;
1449 for(
int i = 0 ; i < k ; ++i )
1450 x |= std::uint64_t( b[ i ] ) << ( 8 * i );
1458 template<
class Executor ,
class F >
1459 static void blocks( std::uint64_t n ,
unsigned p , F && f ) {
1460 constexpr std::uint64_t block = 1 << 14;
1461 std::atomic< std::uint64_t > next{ 0 };
1464 const std::uint64_t a = next.fetch_add( block ,
1465 std::memory_order_relaxed );
1468 f( a , std::min( n , a + block ) );
1476 template<
class Executor >
1477 [[nodiscard]]
static std::vector< std::uint8_t > distances_ignored(
1478 const Pattern & pat ,
unsigned threads ) {
1479 const int k = pat.size();
1480 std::vector< std::uint8_t > h( pat.entries() , c_unseen );
1481 h[ pat.goal_rank() ] = 0;
1482 for(
int d = 0 ; ; ++d ) {
1483 if( d + 1 >= c_unseen )
1484 throw( std::logic_error(
"PatternTable::distances_ignored: a distance "
1486 std::atomic< std::uint64_t > fresh{ 0 };
1487 blocks< Executor >( h.size() , threads , [ & ]( std::uint64_t a ,
1489 std::uint64_t mine = 0;
1490 std::uint8_t p[ cells ];
1491 for( std::uint64_t r = a ; r < b ; ++r ) {
1492 if( std::atomic_ref< std::uint8_t >( h[ r ] ).load(
1493 std::memory_order_relaxed ) != d )
1495 pat.unrank( r , p );
1496 std::uint32_t occ = 0;
1497 for( int i = 0 ; i < k ; ++i )
1498 occ |= std::uint32_t( 1 ) << p[ i ];
1499 for( int i = 0 ; i < k ; ++i ) {
1500 const std::uint8_t old = p[ i ];
1501 const auto & mv = Pattern::moves( old );
1502 for( int j = 0 ; j < mv.n ; ++j ) {
1503 const int c = mv.cell[ j ];
1504 if( ( occ >> c ) & 1u )
1506 p[ i ] = std::uint8_t( c );
1507 std::uint8_t e = c_unseen;
1508 if( std::atomic_ref< std::uint8_t >( h[ pat.rank( p ) ] )
1509 .compare_exchange_strong( e , std::uint8_t( d + 1 ) ,
1510 std::memory_order_relaxed ) )
1516 fresh.fetch_add( mine , std::memory_order_relaxed );
1518 if( fresh.load() == 0 )
1528 template<
class Executor >
1529 [[nodiscard]]
static std::vector< std::uint8_t > distances_minimized(
1530 const Pattern & pat ,
unsigned threads ) {
1531 const int k = pat.size();
1532 const std::uint64_t nf = std::uint64_t( cells - k );
1533 const std::uint64_t states = pat.entries() * nf;
1534 std::vector< std::uint64_t > s( ( states + 31 ) / 32 , 0 );
1535 std::vector< std::uint8_t > h( pat.entries() , c_unseen );
1538 const auto index = [ nf ]( std::uint64_t r , std::uint32_t occ ,
int b ) {
1539 const std::uint32_t below = occ & ( ( std::uint32_t( 1 ) << b ) - 1u );
1540 return( r * nf + std::uint64_t( b - std::popcount( below ) ) );
1542 const auto mark = [ & ]( std::uint64_t i ) {
1543 std::atomic_ref< std::uint64_t > w( s[ i / 32 ] );
1544 const int sh = int( 2 * ( i % 32 ) );
1545 std::uint64_t old = w.load( std::memory_order_relaxed );
1547 if( ( old >> sh ) & 3u )
1549 if( w.compare_exchange_weak( old , old | ( std::uint64_t( 2 ) << sh ) ,
1550 std::memory_order_relaxed ) )
1555 std::uint8_t g[ cells ];
1556 pat.unrank( pat.goal_rank() , g );
1557 std::uint32_t gocc = 0;
1558 for(
int i = 0 ; i < k ; ++i )
1559 gocc |= std::uint32_t( 1 ) << g[ i ];
1560 for(
int b = 0 ; b < cells ; ++b )
1561 if( ! ( ( gocc >> b ) & 1u ) ) {
1562 const std::uint64_t i = index( pat.goal_rank() , gocc , b );
1563 s[ i / 32 ] |= std::uint64_t( 1 ) << ( 2 * ( i % 32 ) );
1565 h[ pat.goal_rank() ] = 0;
1567 constexpr std::uint64_t lo = 0x5555555555555555ULL;
1568 for(
int d = 0 ; ; ++d ) {
1569 if( d + 1 >= c_unseen )
1570 throw( std::logic_error(
"PatternTable::distances_minimized: a "
1571 "distance beyond 254" ) );
1572 blocks< Executor >( s.size() , threads , [ & ]( std::uint64_t a ,
1574 std::uint8_t p[ cells ];
1575 std::int8_t at[ cells ];
1576 for( std::uint64_t wi = a ; wi < e ; ++wi ) {
1577 const std::uint64_t w = std::atomic_ref< std::uint64_t >( s[ wi ] )
1578 .load( std::memory_order_relaxed );
1579 std::uint64_t cur = w & lo & ~( w >> 1 );
1581 const std::uint64_t i = wi * 32 +
1582 std::uint64_t( std::countr_zero( cur ) / 2 );
1586 const std::uint64_t r = i / nf;
1587 pat.unrank( r , p );
1588 std::uint32_t occ = 0;
1589 std::fill( at , at + cells , std::int8_t( -1 ) );
1590 for( int t = 0 ; t < k ; ++t ) {
1591 occ |= std::uint32_t( 1 ) << p[ t ];
1592 at[ p[ t ] ] = std::int8_t( t );
1594 const std::uint32_t free = Pattern::c_full & ~occ;
1595 const int b = Pattern::select( free , int( i % nf ) );
1596 const std::uint32_t reg = Pattern::region( free , b );
1597 if( std::countr_zero( reg ) != b )
1599 for( std::uint32_t rr = reg ; rr ; rr &= rr - 1u ) {
1600 const int c = std::countr_zero( rr );
1601 const auto & mv = Pattern::moves( c );
1602 for( int j = 0 ; j < mv.n ; ++j ) {
1603 const int a2 = mv.cell[ j ];
1604 const int t = at[ a2 ];
1607 p[ t ] = std::uint8_t( c );
1608 const std::uint64_t r2 = pat.rank( p );
1609 p[ t ] = std::uint8_t( a2 );
1610 const std::uint32_t occ2 = ( occ & ~( std::uint32_t( 1 ) << a2 ) ) |
1611 ( std::uint32_t( 1 ) << c );
1612 const std::uint32_t reg2 = Pattern::region( Pattern::c_full & ~occ2 ,
1614 for( std::uint32_t q = reg2 ; q ; q &= q - 1u )
1615 mark( index( r2 , occ2 , std::countr_zero( q ) ) );
1616 std::uint8_t un = c_unseen;
1617 std::atomic_ref< std::uint8_t >( h[ r2 ] ).compare_exchange_strong(
1618 un , std::uint8_t( d + 1 ) , std::memory_order_relaxed );
1626 std::atomic< std::uint64_t > fresh{ 0 };
1627 blocks< Executor >( s.size() , threads , [ & ]( std::uint64_t a ,
1629 std::uint64_t mine = 0;
1630 for( std::uint64_t wi = a ; wi < e ; ++wi ) {
1631 std::uint64_t w = s[ wi ];
1632 const std::uint64_t cur = w & lo & ~( w >> 1 );
1633 const std::uint64_t nxt = ( w >> 1 ) & lo & ~w;
1635 w = ( w & ~( nxt << 1 ) ) | nxt;
1637 mine += std::uint64_t( std::popcount( nxt ) );
1639 fresh.fetch_add( mine , std::memory_order_relaxed );
1641 if( fresh.load() == 0 )
1650 unsigned f_compress;
1653 std::array< std::array< std::uint8_t , cells > , cells > v_md{};
1674template<
int W ,
int H ,
class Enc = NibbleEntries >
1693 : v_tables( std::move(
tables ) ) {
1694 if( v_tables.empty() )
1695 throw( std::invalid_argument(
"AdditivePDB::AdditivePDB: no table" ) );
1696 v_goal = v_tables.front().pattern().goal();
1697 std::fill( v_owner.begin() , v_owner.end() , std::int8_t( -1 ) );
1698 for( std::size_t j = 0 ; j < v_tables.size() ; ++j ) {
1699 const Pattern & p = v_tables[ j ].pattern();
1700 if( p.goal() != v_goal )
1701 throw( std::invalid_argument(
"AdditivePDB::AdditivePDB: the tables "
1702 "have different goals" ) );
1703 for( int i = 0 ; i < p.size() ; ++i ) {
1704 const int t = p.tiles()[ std::size_t( i ) ];
1705 if( v_owner[ std::size_t( t ) ] >= 0 )
1706 throw( std::invalid_argument(
"AdditivePDB::AdditivePDB: the tile " +
1707 std::to_string( t ) +
1708 " is in two patterns" ) );
1709 v_owner[ std::size_t( t ) ] = std::int8_t( j );
1710 v_place[ std::size_t( t ) ] = std::int8_t( i );
1714 for(
int c = 0 ; c < cells ; ++c )
1715 if( v_goal[ c ] == 0 )
1717 f_reflect = reflect && ( W == H ) && ( blank / W == blank % W );
1720 for(
int c = 0 ; c < cells ; ++c ) {
1721 cell[ v_goal[ c ] ] = std::uint8_t( c );
1722 v_transpose[ c ] = std::uint8_t( ( c % W ) * W + c / W );
1724 for(
int t = 0 ; t < cells ; ++t )
1725 v_sigma[ t ] = v_goal[ v_transpose[ cell[ t ] ] ];
1738 :
AdditivePDB( make< ADS::ThreadPool >( partition , goal , o ) ) {}
1743 template<
class Executor >
1748 std::vector< Table > t;
1749 for(
const auto & tiles : partition ) {
1750 const Pattern p( tiles , goal );
1751 if( o.cache.empty() )
1752 t.push_back( Table::template build< Executor >( p , o.blank ,
1753 o.compress , o.threads ) );
1755 t.push_back( Table::template cached< Executor >( o.cache , p , o.blank ,
1759 return( AdditivePDB( std::move( t ) , o.reflect ) );
1765 [[nodiscard]]
int heuristic(
const std::uint8_t * q )
const noexcept
1766 requires( ! Enc::relative ) {
1767 const int a =
sum( q );
1770 std::uint8_t r[
cells ];
1772 return( std::max( a ,
sum( r ) ) );
1780 [[nodiscard]]
int sum(
const std::uint8_t * q )
const noexcept
1781 requires( ! Enc::relative ) {
1783 std::uint8_t p[
cells ];
1784 for(
const Table & t : v_tables ) {
1785 gather( t , q , p );
1795 [[nodiscard]]
int exact(
const std::uint8_t * q )
const
1796 requires( Enc::relative ) {
1797 const auto add = [ & ](
const std::uint8_t * x ) {
1799 std::uint8_t p[
cells ];
1800 for(
const Table & t : v_tables ) {
1801 gather( t , x , p );
1806 const int a = add( q );
1809 std::uint8_t r[
cells ];
1811 return( std::max( a , add( r ) ) );
1819 [[nodiscard]]
int delta(
const std::uint8_t * q ,
int t ,
int c )
const
1820 noexcept requires( Enc::relative ) {
1821 const int j = v_owner[ std::size_t( t ) ];
1824 const Table & tb = v_tables[ std::size_t( j ) ];
1825 std::uint8_t p[
cells ];
1826 gather( tb , q , p );
1827 const int before = tb.
residue( p );
1828 p[ std::size_t( v_place[ std::size_t( t ) ] ) ] = std::uint8_t( c );
1829 constexpr int M = Enc::modulus;
1830 return( ( tb.
residue( p ) - before + 1 + M ) % M - 1 );
1836 void reflection(
const std::uint8_t * q , std::uint8_t * r )
const noexcept
1838 for(
int t = 0 ; t <
cells ; ++t )
1839 r[ v_sigma[ t ] ] = v_transpose[ q[ t ] ];
1852 [[nodiscard]]
bool reflected(
void )
const noexcept {
return( f_reflect ); }
1857 [[nodiscard]]
const std::vector< Table > &
tables(
void )
const noexcept {
1864 [[nodiscard]] std::size_t
bytes(
void )
const noexcept {
1866 for(
const Table & t : v_tables )
1876 static void gather(
const Table & t ,
const std::uint8_t * q ,
1877 std::uint8_t * p )
noexcept {
1878 const auto & ts = t.pattern().tiles();
1879 for( std::size_t i = 0 ; i < ts.size() ; ++i )
1880 p[ i ] = q[ ts[ i ] ];
1883 std::vector< Table > v_tables;
1884 board_type v_goal{};
1885 bool f_reflect =
false;
1886 std::array< std::int8_t , cells > v_owner{};
1887 std::array< std::int8_t , cells > v_place{};
1888 std::array< std::uint8_t , cells > v_transpose{};
1889 std::array< std::uint8_t , cells > v_sigma{};
1906template<
int W ,
int H ,
class Enc = NibbleEntries >
1927 :
Base( start ,
pdb.goal() ) , f_pdb(
pdb ) {
1928 if constexpr( Enc::relative )
1929 if(
pdb.reflected() )
1930 throw( std::invalid_argument(
"SlidingTilePDB::SlidingTilePDB: the "
1931 "residues need the sum without the "
1939 std::uint8_t q[
cells ];
1941 if constexpr( Enc::relative )
1942 return( f_pdb.exact( q ) );
1944 return( f_pdb.heuristic( q ) );
1952 std::uint8_t q[
cells ];
1957 f( t , c , child_h( q , h , t , b ) );
1968 std::uint8_t q[
cells ];
1973 f( t , c , child_h( q , h , t , b ) , o );
1980 [[nodiscard]]
const PDB &
pdb(
void )
const noexcept {
return( f_pdb ); }
1986 for(
int c = 0 ; c <
cells ; ++c )
1987 q[
Base::tile( s , c ) ] = std::uint8_t( c );
1997 cost_type child_h( std::uint8_t * q , cost_type h , state_type t ,
int b )
1999 const int x = Base::tile( t , b );
2000 if constexpr( Enc::relative )
2001 return( h + f_pdb.delta( q , x , b ) );
2003 const int from = q[ x ];
2004 q[ x ] = std::uint8_t( b );
2005 q[ 0 ] = std::uint8_t( from );
2006 const cost_type v = f_pdb.heuristic( q );
2007 q[ x ] = std::uint8_t( from );
2008 q[ 0 ] = std::uint8_t( b );
2023 return(
Partition{ { 1 , 2 , 3 , 4 , 5 , 6 , 7 } ,
2024 { 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 } } );
2032 return(
Partition{ { 1 , 2 , 4 , 5 , 8 } , { 3 , 6 , 7 , 10 , 11 } ,
2033 { 9 , 12 , 13 , 14 , 15 } } );
2041 return(
Partition{ { 1 , 2 , 4 , 5 , 8 , 9 } ,
2042 { 3 , 6 , 7 , 10 , 11 , 15 } , { 12 , 13 , 14 } } );
2049 return(
Partition{ { 1 , 5 , 6 , 10 , 11 , 12 } ,
2050 { 2 , 3 , 4 , 7 , 8 , 9 } ,
2051 { 13 , 14 , 18 , 19 , 23 , 24 } ,
2052 { 15 , 16 , 17 , 20 , 21 , 22 } } );
Header file for the small helpers shared by the searches: a stopwatch, the placement of the workers o...
Header file for the class template SlidingTile, which implements the Domain concept [see Domain....
Header file for the choice of the set of data structures of A*: the arena of the nodes (NodePool),...
the additive heuristic of disjoint pattern tables
Definition PatternDatabase.h:1675
int delta(const std::uint8_t *q, int t, int c) const noexcept
the change of the sum when the tile t moves from the cells q to the cell c, from the residues of the ...
Definition PatternDatabase.h:1819
TilePattern< W, H > Pattern
a pattern
Definition PatternDatabase.h:1684
AdditivePDB(std::vector< Table > tables, bool reflect=true)
constructor, taking the tables, all with the same goal
Definition PatternDatabase.h:1692
static constexpr int cells
Definition PatternDatabase.h:1687
void reflection(const std::uint8_t *q, std::uint8_t *r) const noexcept
Definition PatternDatabase.h:1836
int exact(const std::uint8_t *q) const
the heuristic of the cells q, from the residues alone [see PatternTable::exact()]
Definition PatternDatabase.h:1795
int sum(const std::uint8_t *q) const noexcept
Definition PatternDatabase.h:1780
const std::vector< Table > & tables(void) const noexcept
Definition PatternDatabase.h:1857
const board_type & goal(void) const noexcept
Definition PatternDatabase.h:1845
typename Pattern::board_type board_type
a board
Definition PatternDatabase.h:1685
static AdditivePDB make(const Partition &partition, const board_type &goal=Pattern::korf_goal(), const PDBOptions &o={})
the heuristic of a partition, its tables built on Executor
Definition PatternDatabase.h:1744
AdditivePDB(const Partition &partition, const board_type &goal=Pattern::korf_goal(), const PDBOptions &o={})
constructor, building the tables of a partition for the goal
Definition PatternDatabase.h:1735
PatternTable< W, H, Enc > Table
a table
Definition PatternDatabase.h:1683
bool reflected(void) const noexcept
true if the heuristic also looks up the reflection
Definition PatternDatabase.h:1852
std::size_t bytes(void) const noexcept
the bytes of the entries of all the tables
Definition PatternDatabase.h:1864
int heuristic(const std::uint8_t *q) const noexcept
the heuristic of the state whose tile t is in the cell q[ t ]
Definition PatternDatabase.h:1765
the entries of a pattern table, one byte each: the distance itself
Definition PatternDatabase.h:511
std::uint64_t entries(void) const noexcept
the number of the entries
Definition PatternDatabase.h:548
static ByteEntries encode(const std::vector< std::uint8_t > &h, M &&, unsigned=1)
the encoding of the distances h
Definition PatternDatabase.h:522
static constexpr std::uint32_t code
the code in a file
Definition PatternDatabase.h:515
static constexpr bool relative
absolute values
Definition PatternDatabase.h:517
std::vector< std::uint8_t > payload(void) const
the bytes written in a file
Definition PatternDatabase.h:558
static ByteEntries decode(std::vector< std::uint8_t > data, std::uint64_t n, unsigned=1)
the encoding of n entries read from a file
Definition PatternDatabase.h:534
int value(std::uint64_t r, int) const noexcept
the value of the rank r, whose placement has Manhattan distance m
Definition PatternDatabase.h:543
std::size_t bytes(void) const noexcept
the bytes of the entries
Definition PatternDatabase.h:553
static constexpr const char * name
the name
Definition PatternDatabase.h:516
the entries of a pattern table, the least excess of each group of ranks
Definition PatternDatabase.h:821
std::uint64_t entries(void) const noexcept
the number of the entries
Definition PatternDatabase.h:870
static MinNibbleEntries encode(const std::vector< std::uint8_t > &h, M &&m, unsigned c=1)
the encoding of the distances h, by groups of c ranks
Definition PatternDatabase.h:832
static MinNibbleEntries decode(std::vector< std::uint8_t > data, std::uint64_t n, unsigned c=1)
the encoding of n entries read from a file
Definition PatternDatabase.h:850
unsigned group(void) const noexcept
the ranks per group
Definition PatternDatabase.h:873
static constexpr std::uint32_t code
the code in a file
Definition PatternDatabase.h:825
static constexpr bool relative
absolute values
Definition PatternDatabase.h:827
std::vector< std::uint8_t > payload(void) const
the bytes written in a file
Definition PatternDatabase.h:883
std::size_t bytes(void) const noexcept
the bytes of the entries
Definition PatternDatabase.h:878
int value(std::uint64_t r, int m) const noexcept
the value of the rank r, whose placement has Manhattan distance m
Definition PatternDatabase.h:865
static constexpr const char * name
the name
Definition PatternDatabase.h:826
the entries of a pattern table, the distance modulo 3, five in a byte
Definition PatternDatabase.h:664
std::uint64_t entries(void) const noexcept
the number of the entries
Definition PatternDatabase.h:712
int residue(std::uint64_t r, int) const noexcept
the residue modulo 3 of the distance of the rank r, whose placement has Manhattan distance m
Definition PatternDatabase.h:707
static constexpr std::uint32_t code
the code in a file
Definition PatternDatabase.h:668
static constexpr int modulus
values modulo 3
Definition PatternDatabase.h:671
static constexpr bool relative
relative values
Definition PatternDatabase.h:670
static Mod3Entries decode(std::vector< std::uint8_t > data, std::uint64_t n, unsigned=1)
the encoding of n entries read from a file
Definition PatternDatabase.h:688
std::vector< std::uint8_t > payload(void) const
the bytes written in a file
Definition PatternDatabase.h:722
std::size_t bytes(void) const noexcept
the bytes of the entries
Definition PatternDatabase.h:717
static Mod3Entries encode(const std::vector< std::uint8_t > &h, M &&, unsigned=1)
the encoding of the distances h
Definition PatternDatabase.h:676
static constexpr const char * name
the name
Definition PatternDatabase.h:669
the entries of a pattern table, 4 bits each: the excess over Manhattan
Definition PatternDatabase.h:576
std::uint64_t entries(void) const noexcept
the number of the entries
Definition PatternDatabase.h:623
static NibbleEntries encode(const std::vector< std::uint8_t > &h, M &&m, unsigned=1)
the encoding of the distances h
Definition PatternDatabase.h:587
static NibbleEntries decode(std::vector< std::uint8_t > data, std::uint64_t n, unsigned=1)
the encoding of n entries read from a file
Definition PatternDatabase.h:599
static constexpr std::uint32_t code
the code in a file
Definition PatternDatabase.h:580
static int excess(int h, int m)
the excess ( h - m ) / 2, checked to be a nonnegative integer
Definition PatternDatabase.h:639
static constexpr bool relative
absolute values
Definition PatternDatabase.h:582
std::uint64_t clamped(void) const noexcept
the entries saturated at the encoding
Definition PatternDatabase.h:618
std::vector< std::uint8_t > payload(void) const
the bytes written in a file
Definition PatternDatabase.h:633
std::size_t bytes(void) const noexcept
the bytes of the entries
Definition PatternDatabase.h:628
int value(std::uint64_t r, int m) const noexcept
the value of the rank r, whose placement has Manhattan distance m
Definition PatternDatabase.h:613
static constexpr const char * name
the name
Definition PatternDatabase.h:581
the entries of a pattern table, the second bit of the distance, eight in a byte
Definition PatternDatabase.h:743
std::uint64_t entries(void) const noexcept
the number of the entries
Definition PatternDatabase.h:788
int residue(std::uint64_t r, int m) const noexcept
the residue modulo 4 of the distance of the rank r, whose placement has Manhattan distance m
Definition PatternDatabase.h:783
static constexpr std::uint32_t code
the code in a file
Definition PatternDatabase.h:747
static constexpr int modulus
values modulo 4
Definition PatternDatabase.h:750
static constexpr bool relative
relative values
Definition PatternDatabase.h:749
static ParityBitEntries encode(const std::vector< std::uint8_t > &h, M &&m, unsigned=1)
the encoding of the distances h
Definition PatternDatabase.h:755
static ParityBitEntries decode(std::vector< std::uint8_t > data, std::uint64_t n, unsigned=1)
the encoding of n entries read from a file
Definition PatternDatabase.h:768
std::vector< std::uint8_t > payload(void) const
the bytes written in a file
Definition PatternDatabase.h:798
std::size_t bytes(void) const noexcept
the bytes of the entries
Definition PatternDatabase.h:793
static constexpr const char * name
the name
Definition PatternDatabase.h:748
the distances of a pattern of the sliding-tile puzzle, encoded by Enc
Definition PatternDatabase.h:1067
static std::string file_name(const Pattern &p, BlankRule rule, unsigned compress=1)
the name of the file of the table of p in a cache directory
Definition PatternDatabase.h:1334
bool from_file(void) const noexcept
Definition PatternDatabase.h:1254
const Enc & entries(void) const noexcept
Definition PatternDatabase.h:1240
const Pattern & pattern(void) const noexcept
the pattern
Definition PatternDatabase.h:1228
TilePattern< W, H > Pattern
the pattern
Definition PatternDatabase.h:1075
int value(const std::uint8_t *q) const noexcept
the value of the placement q, q[ i ] the cell of the i-th tile
Definition PatternDatabase.h:1156
static constexpr int cells
Definition PatternDatabase.h:1078
PatternTable(const Pattern &p, BlankRule rule, unsigned compress, Enc entries, bool from_file=false)
constructor, taking the pattern, its rule, the parameter of Enc and the entries already encoded
Definition PatternDatabase.h:1087
static PatternTable cached(const std::string &dir, const Pattern &p, BlankRule rule, unsigned compress=1, unsigned threads=0)
the table of p from the cache directory dir, or built and saved there
Definition PatternDatabase.h:1358
int exact(const std::uint8_t *q) const
the value of the placement q from the residues alone
Definition PatternDatabase.h:1187
static PatternTable build(const Pattern &p, BlankRule rule, unsigned compress=1, unsigned threads=0)
the table of p, built on threads workers of Executor
Definition PatternDatabase.h:1145
static std::vector< std::uint8_t > distances(const Pattern &p, BlankRule rule, unsigned threads=0)
the exact distances of the placements of p, one byte each
Definition PatternDatabase.h:1111
int manhattan(const std::uint8_t *q) const noexcept
Definition PatternDatabase.h:1164
static std::uint64_t checksum(const std::uint8_t *b, std::size_t n) noexcept
the checksum of the n bytes at b, by words of 8 bytes
Definition PatternDatabase.h:1393
typename Pattern::board_type board_type
a board
Definition PatternDatabase.h:1076
static PatternTable load(const std::string &path, const Pattern &p, BlankRule rule, unsigned compress=1)
reads the table of p from the file path
Definition PatternDatabase.h:1296
static PatternTable encode(const Pattern &p, BlankRule rule, const std::vector< std::uint8_t > &h, unsigned compress=1)
the table of p, from the exact distances h
Definition PatternDatabase.h:1128
BlankRule rule(void) const noexcept
Definition PatternDatabase.h:1235
std::size_t bytes(void) const noexcept
the bytes of the entries
Definition PatternDatabase.h:1247
int residue(const std::uint8_t *q) const noexcept
the residue of the value of the placement q, modulo Enc::modulus
Definition PatternDatabase.h:1174
static constexpr std::uint32_t file_version
Definition PatternDatabase.h:1081
void save(const std::string &path) const
writes the table to the file path
Definition PatternDatabase.h:1268
cost_type heuristic(state_type s) const
the heuristic of s, looked up in the tables
Definition PatternDatabase.h:1938
void for_each_successor(state_type s, cost_type h, F &&f) const
calls f( t , 1 , h( t ) ) for each successor t of s
Definition PatternDatabase.h:1951
AdditivePDB< W, H, Enc > PDB
the heuristic
Definition PatternDatabase.h:1916
static constexpr int cells
the cells
Definition PatternDatabase.h:1921
typename Base::cost_type cost_type
the cost type
Definition PatternDatabase.h:1918
static void cells_of(state_type s, std::uint8_t *q) noexcept
writes in q the cell of each tile of s
Definition PatternDatabase.h:1985
const PDB & pdb(void) const noexcept
the heuristic
Definition PatternDatabase.h:1980
void for_each_successor(state_type s, cost_type h, std::uint8_t op, F &&f) const
as above, but without the successor that op leads back to [see SlidingTile]
Definition PatternDatabase.h:1966
SlidingTilePDB(const board_type &start, const PDB &pdb)
constructor, taking the start board and the heuristic
Definition PatternDatabase.h:1926
typename Base::board_type board_type
a board
Definition PatternDatabase.h:1919
typename Base::state_type state_type
a packed board
Definition PatternDatabase.h:1917
SlidingTile< W, H > Base
the puzzle
Definition PatternDatabase.h:1915
void for_each_successor(state_type s, cost_type h, F &&f) const
calls f( t , 1 , h( t ) ) for each successor t of s
Definition SlidingTile.h:274
std::conditional_t< cells<=16, std::uint64_t, Word128 > state_type
a packed board
Definition SlidingTile.h:187
static constexpr int cells
the number of cells
Definition SlidingTile.h:180
static int blank(state_type s) noexcept
the cell of the blank in s, i.e., of the zero field of the integer
Definition SlidingTile.h:465
std::array< std::uint8_t, cells > board_type
a board
Definition SlidingTile.h:190
int cost_type
the cost type
Definition SlidingTile.h:189
SlidingTile(const board_type &start, const board_type &goal=korf_goal())
constructor, taking the start and the goal boards
Definition SlidingTile.h:209
static int tile(state_type s, int c) noexcept
the tile in the cell c of s
Definition SlidingTile.h:456
the entries of a pattern table whose excess is nonzero, by rank
Definition PatternDatabase.h:923
std::uint64_t entries(void) const noexcept
the number of the entries
Definition PatternDatabase.h:1006
static SparseEntries decode(std::vector< std::uint8_t > data, std::uint64_t n, unsigned=1)
the encoding of n entries read from a file: the words of B, then the excesses
Definition PatternDatabase.h:962
static constexpr std::uint32_t code
the code in a file
Definition PatternDatabase.h:929
static constexpr bool relative
absolute values
Definition PatternDatabase.h:931
std::uint64_t nonzero(void) const noexcept
the entries whose excess is nonzero
Definition PatternDatabase.h:1013
std::vector< std::uint8_t > payload(void) const
the bytes written in a file
Definition PatternDatabase.h:1028
static SparseEntries encode(const std::vector< std::uint8_t > &h, M &&m, unsigned=1)
the encoding of the distances h, m( r ) the Manhattan distance of r
Definition PatternDatabase.h:937
int value(std::uint64_t r, int m) const
the value of the rank r, whose placement has Manhattan distance m
Definition PatternDatabase.h:997
std::size_t bytes(void) const noexcept
the bytes of B, of its directory and of the excesses
Definition PatternDatabase.h:1020
static constexpr const char * name
the name
Definition PatternDatabase.h:930
a pattern of the sliding-tile puzzle and the ranking of its placements
Definition PatternDatabase.h:233
std::uint64_t entries(void) const noexcept
the number of the placements, n! / ( n - k )!
Definition PatternDatabase.h:333
std::uint64_t rank(const std::uint8_t *p) const noexcept
the rank of the placement p, p[ i ] the cell of the i-th tile
Definition PatternDatabase.h:347
const std::vector< int > & tiles(void) const noexcept
the tiles of the pattern
Definition PatternDatabase.h:312
static constexpr int cells
the number of cells
Definition PatternDatabase.h:241
static board_type korf_goal(void)
the goal of Korf (1985): the blank in the first cell, then 1 , 2 , ...
Definition PatternDatabase.h:258
std::uint64_t goal_rank(void) const noexcept
the rank of the goal placement
Definition PatternDatabase.h:340
const board_type & goal(void) const noexcept
the goal board
Definition PatternDatabase.h:319
std::array< std::uint8_t, cells > board_type
a board
Definition PatternDatabase.h:246
int goal_cell(int i) const noexcept
the goal cell of the i-th tile of the pattern
Definition PatternDatabase.h:326
TilePattern(const std::vector< int > &tiles, const board_type &goal=korf_goal())
constructor, taking the tiles of the pattern and the goal board
Definition PatternDatabase.h:271
int size(void) const noexcept
the number k of the tiles of the pattern
Definition PatternDatabase.h:307
int manhattan(const std::uint8_t *p) const noexcept
the Manhattan distance of the tiles of the placement p from the goal
Definition PatternDatabase.h:379
static const Moves & moves(int c) noexcept
the cells adjacent to the cell c
Definition PatternDatabase.h:389
static std::uint32_t region(std::uint32_t free, int b) noexcept
the cells that a blank in the cell b reaches through the cells of free, i.e., the region of b in the ...
Definition PatternDatabase.h:419
static constexpr std::uint32_t c_full
the mask of all the cells
Definition PatternDatabase.h:403
void unrank(std::uint64_t r, std::uint8_t *p) const noexcept
writes in p the placement of rank r < entries()
Definition PatternDatabase.h:363
static int distance(int a, int b) noexcept
the Manhattan distance between two cells
Definition PatternDatabase.h:396
static int select(std::uint32_t x, int j) noexcept
the place of the j-th set bit of x (from 0), which must exist
Definition PatternDatabase.h:409
namespace for the Parallel Best-First Search library
Definition AStar.h:83
Partition partition_15_5_5_5(void)
the partition 5-5-5 of the 15-puzzle of Felner, Korf and Hanan (JAIR 2004)
Definition PatternDatabase.h:2031
Partition partition_24_6_6_6_6(void)
the partition 6-6-6-6 of the 24-puzzle of Korf and Felner (AIJ 2002)
Definition PatternDatabase.h:2048
BlankRule
how the abstraction of a pattern treats the blank
Definition PatternDatabase.h:196
@ minimized
the blank is, and the table keeps the least distance
Definition PatternDatabase.h:198
@ ignored
the blank is not in the abstract state: consistent tables
Definition PatternDatabase.h:197
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
std::vector< std::vector< int > > Partition
a partition of the tiles into disjoint patterns
Definition PatternDatabase.h:204
Partition partition_15_7_8(void)
the partition 7-8 of the 15-puzzle of Korf and Felner (AIJ 2002)
Definition PatternDatabase.h:2022
Partition partition_15_6_6_3(void)
the partition 6-6-3 of the 15-puzzle of Felner, Korf and Hanan (JAIR 2004)
Definition PatternDatabase.h:2040
the options of the construction of an AdditivePDB
Definition PatternDatabase.h:209
std::string cache
directory of the tables ("": none)
Definition PatternDatabase.h:214
BlankRule blank
the rule of the blank
Definition PatternDatabase.h:210
bool reflect
also the reflection, where it is valid
Definition PatternDatabase.h:211
unsigned threads
workers of the construction (0: all)
Definition PatternDatabase.h:213
unsigned compress
ranks per entry of MinNibbleEntries
Definition PatternDatabase.h:212
the cells adjacent to a cell, in the order up, left, right, down
Definition PatternDatabase.h:249
int cell[4]
the cells
Definition PatternDatabase.h:251
int n
their number
Definition PatternDatabase.h:250