PBeFS
Parallel Best-First Search
Loading...
Searching...
No Matches
PatternDatabase.h
Go to the documentation of this file.
1/*--------------------------------------------------------------------------*/
2/*------------------------ File PatternDatabase.h --------------------------*/
3/*--------------------------------------------------------------------------*/
127/*--------------------------------------------------------------------------*/
128/*------------------------------ DEFINITIONS -------------------------------*/
129/*--------------------------------------------------------------------------*/
130
131#ifndef __PBeFS_PatternDatabase
132 #define __PBeFS_PatternDatabase
133 /* self-identification: #endif at the end of the file */
134
135/*--------------------------------------------------------------------------*/
136/*-------------------------------- INCLUDES --------------------------------*/
137/*--------------------------------------------------------------------------*/
138
139#include <algorithm>
140
141#include <array>
142
143#include <atomic>
144
145#include <bit>
146
147#include <cstddef>
148
149#include <cstdint>
150
151#include <cstdio>
152
153#include <cstdlib>
154
155#include <cstring>
156
157#include <filesystem>
158
159#include <fstream>
160
161#include <iterator>
162
163#include <stdexcept>
164
165#include <string>
166
167#include <thread>
168
169#include <utility>
170
171#include <vector>
172
174
176
178
179#include "ADS/succinct/PackedArray.h"
180
181#include "ADS/succinct/RankSelect.h"
182
183/*--------------------------------------------------------------------------*/
184/*------------------------------- NAMESPACE --------------------------------*/
185/*--------------------------------------------------------------------------*/
186
188namespace PBeFS_di_unipi_it
189{
190
191/*--------------------------------------------------------------------------*/
192/*--------------------------------- TYPES ----------------------------------*/
193/*--------------------------------------------------------------------------*/
195
196enum class BlankRule : std::uint8_t {
199 };
200
201/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
203
204using Partition = std::vector< std::vector< int > >;
205
206/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
208
211 bool reflect = true;
212 unsigned compress = 1;
213 unsigned threads = 0;
214 std::string cache;
215 };
216
217/*--------------------------------------------------------------------------*/
218/*---------------------------- CLASS TilePattern ---------------------------*/
219/*--------------------------------------------------------------------------*/
221
231
232template< int W , int H >
234
235/*------------------------ PUBLIC PART OF THE CLASS ------------------------*/
236
237 public:
238
239/*------------------------------ PUBLIC TYPES ------------------------------*/
240
241 static constexpr int cells = W * H;
242
243 static_assert( ( W >= 2 ) && ( H >= 2 ) && ( cells <= 32 ) ,
244 "TilePattern: at most 32 cells" );
245
246 using board_type = std::array< std::uint8_t , cells >;
247
249 struct Moves {
250 int n = 0;
251 int cell[ 4 ] = { 0 , 0 , 0 , 0 };
252 };
253
254/*------------------------------ CONSTRUCTOR -------------------------------*/
255
257
258 [[nodiscard]] static board_type korf_goal( void ) {
259 board_type b{};
260 for( int i = 0 ; i < cells ; ++i )
261 b[ i ] = static_cast< std::uint8_t >( i );
262 return( b );
263 }
264
265/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
267
270
271 explicit TilePattern( const std::vector< int > & tiles ,
272 const board_type & goal = korf_goal() )
273 : v_tiles( tiles ) , v_goal( goal ) {
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;
280 }
281 if( tiles.empty() || ( int( tiles.size() ) >= cells ) )
282 throw( std::invalid_argument( "TilePattern::TilePattern: a pattern has "
283 "1 to W H - 1 tiles" ) );
284 seen = 0;
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;
290 }
291 f_k = int( tiles.size() );
292 board_type cell{};
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 ];
298 f_entries = 1;
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() );
302 }
303
304/*---------------------- METHODS FOR READING THE DATA ----------------------*/
306
307 [[nodiscard]] int size( void ) const noexcept { return( f_k ); }
308
309/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
311
312 [[nodiscard]] const std::vector< int > & tiles( void ) const noexcept {
313 return( v_tiles );
314 }
315
316/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
318
319 [[nodiscard]] const board_type & goal( void ) const noexcept {
320 return( v_goal );
321 }
322
323/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
325
326 [[nodiscard]] int goal_cell( int i ) const noexcept {
327 return( v_goal_cell[ i ] );
328 }
329
330/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
332
333 [[nodiscard]] std::uint64_t entries( void ) const noexcept {
334 return( f_entries );
335 }
336
337/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
339
340 [[nodiscard]] std::uint64_t goal_rank( void ) const noexcept {
341 return( f_goal_rank );
342 }
343
344/*------------------------- RANKING THE PLACEMENTS -------------------------*/
346
347 [[nodiscard]] std::uint64_t rank( const std::uint8_t * p ) const noexcept {
348 std::uint64_t r = 0;
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 ] ) -
352 1u );
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 ];
356 }
357 return( r );
358 }
359
360/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
362
363 void unrank( std::uint64_t r , std::uint8_t * p ) const noexcept {
364 int d[ cells ];
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 );
368 }
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 ] );
373 }
374 }
375
376/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
378
379 [[nodiscard]] int manhattan( const std::uint8_t * p ) const noexcept {
380 int m = 0;
381 for( int i = 0 ; i < f_k ; ++i )
382 m += distance( p[ i ] , v_goal_cell[ i ] );
383 return( m );
384 }
385
386/*----------------------------- BOARD HELPERS ------------------------------*/
388
389 [[nodiscard]] static const Moves & moves( int c ) noexcept {
390 return( c_moves[ std::size_t( c ) ] );
391 }
392
393/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
395
396 [[nodiscard]] static int distance( int a , int b ) noexcept {
397 return( std::abs( a / W - b / W ) + std::abs( a % W - b % W ) );
398 }
399
400/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
402
403 static constexpr std::uint32_t c_full = cells == 32 ? ~std::uint32_t( 0 )
404 : ( std::uint32_t( 1 ) << cells ) - 1u;
405
406/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
408
409 [[nodiscard]] static int select( std::uint32_t x , int j ) noexcept {
410 for( ; j > 0 ; --j )
411 x &= x - 1u;
412 return( std::countr_zero( x ) );
413 }
414
415/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
418
419 [[nodiscard]] static std::uint32_t region( std::uint32_t free , int b )
420 noexcept {
421 std::uint32_t r = std::uint32_t( 1 ) << b , last = 0;
422 while( r != last ) {
423 last = r;
424 std::uint32_t g = r | ( r >> W ) | ( r << W ) |
425 ( ( r & ~c_right ) << 1 ) | ( ( r & ~c_left ) >> 1 );
426 r = g & free;
427 }
428 return( r );
429 }
430
431/*----------------------- PRIVATE PART OF THE CLASS ------------------------*/
432
433 private:
434
436 static constexpr std::uint32_t c_left = [] {
437 std::uint32_t m = 0;
438 for( int r = 0 ; r < H ; ++r )
439 m |= std::uint32_t( 1 ) << ( r * W );
440 return( m );
441 }();
442
444 static constexpr std::uint32_t c_right = c_left << ( W - 1 );
445
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 ) ];
452 if( r > 0 )
453 o.cell[ o.n++ ] = b - W;
454 if( k > 0 )
455 o.cell[ o.n++ ] = b - 1;
456 if( k < W - 1 )
457 o.cell[ o.n++ ] = b + 1;
458 if( r < H - 1 )
459 o.cell[ o.n++ ] = b + W;
460 }
461 return( m );
462 }();
463
464 std::vector< int > v_tiles;
465 board_type v_goal;
466 std::array< std::uint8_t , cells > v_goal_cell{};
467 int f_k = 0;
468 std::uint64_t f_entries = 0;
469 std::uint64_t f_goal_rank = 0;
470
471 }; // end( class( TilePattern ) )
472
473/*--------------------------------------------------------------------------*/
474/*----------------------------- THE ENCODINGS ------------------------------*/
475/*--------------------------------------------------------------------------*/
476
477namespace detail {
478
481[[nodiscard]] inline std::vector< std::uint8_t > packed_bytes(
482 const std::vector< std::uint64_t > & w , std::size_t n )
483{
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 ) ) );
487 return( b );
488 }
489
491
492template< unsigned B >
493[[nodiscard]] inline unsigned packed_field( const std::vector< std::uint8_t >
494 & d , std::uint64_t i ) noexcept
495{
496 const std::uint64_t bit = i * B;
497 return( ( d[ bit >> 3 ] >> ( bit & 7 ) ) & ( ( 1u << B ) - 1 ) );
498 }
499
500} // end( namespace detail )
501
502/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
504
510
512
513 public:
514
515 static constexpr std::uint32_t code = 1;
516 static constexpr const char * name = "byte";
517 static constexpr bool relative = false;
518
520
521 template< class M >
522 [[nodiscard]] static ByteEntries encode( const std::vector< std::uint8_t >
523 & h , M && , unsigned = 1 ) {
524 ADS::Sequential ex;
525 ByteEntries e;
526 e.f_data = Array( ex , h.size() , [ & ]( std::size_t r ) {
527 return( h[ r ] );
528 } );
529 return( e );
530 }
531
533
534 [[nodiscard]] static ByteEntries decode( std::vector< std::uint8_t > data ,
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 ) );
539 }
540
542
543 [[nodiscard]] int value( std::uint64_t r , int ) const noexcept {
544 return( int( f_data.get( r ) ) );
545 }
546
548 [[nodiscard]] std::uint64_t entries( void ) const noexcept {
549 return( f_data.size() );
550 }
551
553 [[nodiscard]] std::size_t bytes( void ) const noexcept {
554 return( f_data.size() );
555 }
556
558 [[nodiscard]] std::vector< std::uint8_t > payload( void ) const {
559 return( detail::packed_bytes( f_data.words() , bytes() ) );
560 }
561
562 private:
563
564 using Array = ADS::PackedArray< 8 >;
565
566 Array f_data;
567
568 }; // end( class( ByteEntries ) )
569
570/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
572
575
577
578 public:
579
580 static constexpr std::uint32_t code = 2;
581 static constexpr const char * name = "nibble";
582 static constexpr bool relative = false;
583
585
586 template< class M >
587 [[nodiscard]] static NibbleEntries encode( const std::vector< std::uint8_t >
588 & h , M && m , unsigned = 1 ) {
589 ADS::Sequential ex;
591 e.f_data = Array( ex , h.size() , [ & ]( std::size_t r ) {
592 return( std::uint64_t( excess( h[ r ] , m( r ) ) ) );
593 } );
594 return( e );
595 }
596
598
599 [[nodiscard]] static NibbleEntries decode( std::vector< std::uint8_t > data ,
600 std::uint64_t n , unsigned = 1 ) {
601 if( data.size() != ( n + 1 ) / 2 )
602 throw( std::runtime_error( "NibbleEntries::decode: bad size" ) );
603 ADS::Sequential ex;
605 e.f_data = Array( ex , n , [ & ]( std::size_t r ) {
606 return( detail::packed_field< 4 >( data , r ) );
607 } );
608 return( e );
609 }
610
612
613 [[nodiscard]] int value( std::uint64_t r , int m ) const noexcept {
614 return( m + 2 * int( f_data.get( r ) ) );
615 }
616
618 [[nodiscard]] std::uint64_t clamped( void ) const noexcept {
619 return( f_data.clamped() );
620 }
621
623 [[nodiscard]] std::uint64_t entries( void ) const noexcept {
624 return( f_data.size() );
625 }
626
628 [[nodiscard]] std::size_t bytes( void ) const noexcept {
629 return( ( f_data.size() + 1 ) / 2 );
630 }
631
633 [[nodiscard]] std::vector< std::uint8_t > payload( void ) const {
634 return( detail::packed_bytes( f_data.words() , bytes() ) );
635 }
636
638
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 );
644 }
645
646 private:
647
648 using Array = ADS::PackedArray< 4 , true >;
649
650 Array f_data;
651
652 }; // end( class( NibbleEntries ) )
653
654/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
656
663
665
666 public:
667
668 static constexpr std::uint32_t code = 3;
669 static constexpr const char * name = "mod3";
670 static constexpr bool relative = true;
671 static constexpr int modulus = 3;
672
674
675 template< class M >
676 [[nodiscard]] static Mod3Entries encode( const std::vector< std::uint8_t >
677 & h , M && , unsigned = 1 ) {
678 ADS::Sequential ex;
679 Mod3Entries e;
680 e.f_data = ADS::TritArray( ex , h.size() , [ & ]( std::size_t r ) {
681 return( unsigned( h[ r ] % 3 ) );
682 } );
683 return( e );
684 }
685
687
688 [[nodiscard]] static Mod3Entries decode( std::vector< std::uint8_t > data ,
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 )
693 if( b >= 243 )
694 throw( std::runtime_error( "Mod3Entries::decode: bad byte" ) );
695 static constexpr unsigned power[ 5 ] = { 1 , 3 , 9 , 27 , 81 };
696 ADS::Sequential ex;
697 Mod3Entries e;
698 e.f_data = ADS::TritArray( ex , n , [ & ]( std::size_t r ) {
699 return( data[ r / 5 ] / power[ r % 5 ] % 3 );
700 } );
701 return( e );
702 }
703
706
707 [[nodiscard]] int residue( std::uint64_t r , int ) const noexcept {
708 return( int( f_data.get( r ) ) );
709 }
710
712 [[nodiscard]] std::uint64_t entries( void ) const noexcept {
713 return( f_data.size() );
714 }
715
717 [[nodiscard]] std::size_t bytes( void ) const noexcept {
718 return( f_data.bytes() );
719 }
720
722 [[nodiscard]] std::vector< std::uint8_t > payload( void ) const {
723 return( f_data.data() );
724 }
725
726 private:
727
728 ADS::TritArray f_data;
729
730 }; // end( class( Mod3Entries ) )
731
732/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
735
742
744
745 public:
746
747 static constexpr std::uint32_t code = 6;
748 static constexpr const char * name = "bit";
749 static constexpr bool relative = true;
750 static constexpr int modulus = 4;
751
753
754 template< class M >
755 [[nodiscard]] static ParityBitEntries encode(
756 const std::vector< std::uint8_t > & h , M && m , unsigned = 1 ) {
757 ADS::Sequential ex;
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 ) );
762 } );
763 return( e );
764 }
765
767
768 [[nodiscard]] static ParityBitEntries decode(
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" ) );
772 ADS::Sequential ex;
774 e.f_data = Array( ex , n , [ & ]( std::size_t r ) {
775 return( detail::packed_field< 1 >( data , r ) );
776 } );
777 return( e );
778 }
779
782
783 [[nodiscard]] int residue( std::uint64_t r , int m ) const noexcept {
784 return( 2 * int( f_data.get( r ) ) + ( m & 1 ) );
785 }
786
788 [[nodiscard]] std::uint64_t entries( void ) const noexcept {
789 return( f_data.size() );
790 }
791
793 [[nodiscard]] std::size_t bytes( void ) const noexcept {
794 return( ( f_data.size() + 7 ) / 8 );
795 }
796
798 [[nodiscard]] std::vector< std::uint8_t > payload( void ) const {
799 return( detail::packed_bytes( f_data.words() , bytes() ) );
800 }
801
802 private:
803
804 using Array = ADS::PackedArray< 1 >;
805
806 Array f_data;
807
808 }; // end( class( ParityBitEntries ) )
809
810/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
812
820
822
823 public:
824
825 static constexpr std::uint32_t code = 4;
826 static constexpr const char * name = "min";
827 static constexpr bool relative = false;
828
830
831 template< class M >
832 [[nodiscard]] static MinNibbleEntries encode(
833 const std::vector< std::uint8_t > & h , M && m , unsigned c = 1 ) {
834 ADS::Sequential ex;
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 ) );
840 int x = 15;
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 ) );
844 } );
845 return( e );
846 }
847
849
850 [[nodiscard]] static MinNibbleEntries decode(
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" ) );
856 ADS::Sequential ex;
857 e.f_data = Array( ex , e.groups() , [ & ]( std::size_t g ) {
858 return( detail::packed_field< 4 >( data , g ) );
859 } );
860 return( e );
861 }
862
864
865 [[nodiscard]] int value( std::uint64_t r , int m ) const noexcept {
866 return( m + 2 * int( f_data.get( r >> f_shift ) ) );
867 }
868
870 [[nodiscard]] std::uint64_t entries( void ) const noexcept { return( f_n ); }
871
873 [[nodiscard]] unsigned group( void ) const noexcept {
874 return( 1u << f_shift );
875 }
876
878 [[nodiscard]] std::size_t bytes( void ) const noexcept {
879 return( ( groups() + 1 ) / 2 );
880 }
881
883 [[nodiscard]] std::vector< std::uint8_t > payload( void ) const {
884 return( detail::packed_bytes( f_data.words() , bytes() ) );
885 }
886
887 private:
888
889 using Array = ADS::PackedArray< 4 >;
890
891 // n entries in groups of c, a power of 2
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" ) );
896 f_n = n;
897 f_shift = std::countr_zero( c );
898 }
899
900 // the number of the groups
901 [[nodiscard]] std::uint64_t groups( void ) const noexcept {
902 return( ( f_n + ( std::uint64_t( 1 ) << f_shift ) - 1 ) >> f_shift );
903 }
904
905 Array f_data;
906 std::uint64_t f_n = 0;
907 int f_shift = 0;
908
909 }; // end( class( MinNibbleEntries ) )
910
911/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
913
922
924
925/*------------------------ PUBLIC PART OF THE CLASS ------------------------*/
926
927 public:
928
929 static constexpr std::uint32_t code = 5;
930 static constexpr const char * name = "sparse";
931 static constexpr bool relative = false;
932
933/*------------------------------ CONSTRUCTION ------------------------------*/
935
936 template< class M >
937 [[nodiscard]] static SparseEntries encode( const std::vector< std::uint8_t >
938 & h , M && m , unsigned = 1 ) {
939 ADS::BitVector b( h.size() );
940 Excesses x;
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;
947 if( e == 0 )
948 continue;
949 b.set( r );
950 x.push_back( Excesses::Word( e ) );
951 }
953 s.f_bits = ADS::RankSelect( std::move( b ) );
954 s.f_excess = std::move( x );
955 return( s );
956 }
957
958/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
961
962 [[nodiscard]] static SparseEntries decode( std::vector< std::uint8_t > data ,
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 );
968 std::uint64_t z = 0;
969 for( std::uint64_t w = 0 ; w < words ; ++w ) {
970 std::uint64_t x = 0;
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 "
975 "end" ) );
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 ) ) );
979 }
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 ) ,
984 data.end() );
985 ADS::Sequential ex;
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 ) );
990 } );
991 return( s );
992 }
993
994/*-------------------------------- LOOKUPS ---------------------------------*/
996
997 [[nodiscard]] int value( std::uint64_t r , int m ) const {
998 if( ! f_bits[ r ] )
999 return( m );
1000 return( m + 2 * int( f_excess.get( f_bits.rank1( r ) ) ) );
1001 }
1002
1003/*---------------------- METHODS FOR READING THE DATA ----------------------*/
1005
1006 [[nodiscard]] std::uint64_t entries( void ) const noexcept {
1007 return( f_bits.size() );
1008 }
1009
1010/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1012
1013 [[nodiscard]] std::uint64_t nonzero( void ) const noexcept {
1014 return( f_bits.ones() );
1015 }
1016
1017/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1019
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 );
1023 }
1024
1025/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1027
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() );
1039 return( d );
1040 }
1041
1042/*----------------------- PRIVATE PART OF THE CLASS ------------------------*/
1043
1044 private:
1045
1046 using Excesses = ADS::PackedArray< 4 , true >;
1047
1048 ADS::RankSelect f_bits;
1049 Excesses f_excess;
1050
1051 }; // end( class( SparseEntries ) )
1052
1053/*--------------------------------------------------------------------------*/
1054
1055/*--------------------------------------------------------------------------*/
1056/*---------------------------- CLASS PatternTable --------------------------*/
1057/*--------------------------------------------------------------------------*/
1059
1065
1066template< int W , int H , class Enc = NibbleEntries >
1068
1069/*------------------------ PUBLIC PART OF THE CLASS ------------------------*/
1070
1071 public:
1072
1073/*------------------------------ PUBLIC TYPES ------------------------------*/
1074
1077
1078 static constexpr int cells = W * H;
1079
1081 static constexpr std::uint32_t file_version = 1;
1082
1083/*------------------------------ CONSTRUCTOR -------------------------------*/
1086
1087 PatternTable( const Pattern & p , BlankRule rule , unsigned compress ,
1088 Enc entries , bool from_file = false )
1089 : f_pattern( p ) , f_rule( rule ) , f_compress( compress ) ,
1090 f_entries( std::move( entries ) ) , f_from_file( from_file ) {
1091 if constexpr( Enc::relative )
1092 if( rule != BlankRule::ignored )
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 ) ] =
1101 std::uint8_t( Pattern::distance( c , p.goal_cell( i ) ) );
1102 }
1103
1104/*------------------------------ CONSTRUCTION ------------------------------*/
1106
1109
1110 template< ADS::WorkerExecutor Executor = ADS::ThreadPool >
1111 [[nodiscard]] static std::vector< std::uint8_t > distances(
1112 const Pattern & p , BlankRule rule , unsigned threads = 0 ) {
1113 if( threads == 0 )
1114 threads = std::max( 1u , std::thread::hardware_concurrency() );
1115 auto h = rule == BlankRule::ignored
1116 ? distances_ignored< Executor >( p , threads )
1117 : distances_minimized< Executor >( p , threads );
1118 for( std::uint8_t x : h )
1119 if( x == c_unseen )
1120 throw( std::logic_error( "PatternTable::distances: a placement is "
1121 "not reached" ) );
1122 return( h );
1123 }
1124
1125/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1127
1128 [[nodiscard]] static PatternTable encode( const Pattern & p ,
1129 BlankRule rule ,
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() );
1135 return( p.manhattan( q.data() ) );
1136 };
1137 return( PatternTable( p , rule , compress ,
1138 Enc::encode( h , m , compress ) ) );
1139 }
1140
1141/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1143
1144 template< ADS::WorkerExecutor Executor = ADS::ThreadPool >
1145 [[nodiscard]] static PatternTable build( const Pattern & p ,
1146 BlankRule rule ,
1147 unsigned compress = 1 ,
1148 unsigned threads = 0 ) {
1149 return( encode( p , rule , distances< Executor >( p , rule , threads ) ,
1150 compress ) );
1151 }
1152
1153/*-------------------------------- LOOKUPS ---------------------------------*/
1155
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 ) ) );
1159 }
1160
1161/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1163
1164 [[nodiscard]] int manhattan( const std::uint8_t * q ) const noexcept {
1165 int m = 0;
1166 for( int i = 0 ; i < f_pattern.size() ; ++i )
1167 m += v_md[ std::size_t( i ) ][ q[ i ] ];
1168 return( m );
1169 }
1170
1171/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1173
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 ) ) );
1177 }
1178
1179/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1181
1186
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 );
1194 int v = 0;
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 ];
1200 bool moved = false;
1201 for( int i = 0 ; ( i < k ) && ! moved ; ++i ) {
1202 const auto & mv = Pattern::moves( p[ i ] );
1203 for( int j = 0 ; j < mv.n ; ++j ) {
1204 const int c = mv.cell[ j ];
1205 if( ( occ >> c ) & 1u )
1206 continue;
1207 const std::uint8_t old = p[ i ];
1208 p[ i ] = std::uint8_t( c );
1209 if( residue( p ) == want ) {
1210 r = f_pattern.rank( p );
1211 moved = true;
1212 break;
1213 }
1214 p[ i ] = old;
1215 }
1216 }
1217 if( ! moved )
1218 throw( std::logic_error( "PatternTable::exact: no neighbour one step "
1219 "closer to the goal" ) );
1220 ++v;
1221 }
1222 return( v );
1223 }
1224
1225/*---------------------- METHODS FOR READING THE DATA ----------------------*/
1227
1228 [[nodiscard]] const Pattern & pattern( void ) const noexcept {
1229 return( f_pattern );
1230 }
1231
1232/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1234
1235 [[nodiscard]] BlankRule rule( void ) const noexcept { return( f_rule ); }
1236
1237/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1239
1240 [[nodiscard]] const Enc & entries( void ) const noexcept {
1241 return( f_entries );
1242 }
1243
1244/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1246
1247 [[nodiscard]] std::size_t bytes( void ) const noexcept {
1248 return( f_entries.bytes() );
1249 }
1250
1251/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1253
1254 [[nodiscard]] bool from_file( void ) const noexcept {
1255 return( f_from_file );
1256 }
1257
1258/*------------------------------ PERSISTENCE -------------------------------*/
1260
1267
1268 void save( const std::string & path ) const {
1269 std::vector< std::uint8_t > b = header( f_pattern , f_rule ,
1270 f_compress );
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() ) );
1279 {
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() ) );
1283 if( ! out )
1284 throw( std::runtime_error( "PatternTable::save: cannot write " + tmp )
1285 );
1286 }
1287 std::filesystem::rename( tmp , path );
1288 }
1289
1290/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1292
1295
1296 [[nodiscard]] static PatternTable load( const std::string & path ,
1297 const Pattern & p , BlankRule rule ,
1298 unsigned compress = 1 ) {
1299 std::ifstream in( path , std::ios::binary );
1300 if( ! in )
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 ) ,
1325 b.end() - 8 );
1326 return( PatternTable( p , rule , compress ,
1327 Enc::decode( std::move( pay ) , n , compress ) ,
1328 true ) );
1329 }
1330
1331/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1333
1334 [[nodiscard]] static std::string file_name( const Pattern & p ,
1335 BlankRule rule ,
1336 unsigned compress = 1 ) {
1337 std::string s = "pdb-" + std::to_string( W ) + "x" + std::to_string( H ) +
1338 ( rule == BlankRule::ignored ? "-ignored-" : "-minimized-" )
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();
1343 char hex[ 17 ];
1344 std::snprintf( hex , sizeof( hex ) , "%016llx" , static_cast<
1345 unsigned long long >( checksum( g.data() , g.size() ) ) );
1346 return( s + "-g" + hex + ".pdb" );
1347 }
1348
1349/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1351
1356
1357 template< ADS::WorkerExecutor Executor = ADS::ThreadPool >
1358 [[nodiscard]] static PatternTable cached( const std::string & dir ,
1359 const Pattern & p ,
1360 BlankRule rule ,
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 ) )
1366 try {
1367 return( load( own.string() , p , rule , compress ) );
1368 }
1369 catch( std::runtime_error & ) {} // built again below
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 ) )
1375 try {
1376 h = Bytes::load( raw.string() , p , rule ).entries().payload();
1377 }
1378 catch( std::runtime_error & ) {}
1379 if( h.empty() ) {
1380 h = distances< Executor >( p , rule , threads );
1381 Bytes( p , rule , 1 , ByteEntries::encode( h , 0 ) ).save(
1382 raw.string() );
1383 }
1384 PatternTable t = encode( p , rule , h , compress );
1385 if( own != raw )
1386 t.save( own.string() );
1387 return( t );
1388 }
1389
1390/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1392
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 );
1396 std::size_t i = 0;
1397 for( ; i + 8 <= n ; i += 8 )
1398 h = ADS::splitmix64( h ^ get( b + i , 8 ) ) + i;
1399 if( i < n )
1400 h = ADS::splitmix64( h ^ get( b + i , int( n - i ) ) );
1401 return( h );
1402 }
1403
1404/*----------------------- PRIVATE PART OF THE CLASS ------------------------*/
1405
1406 private:
1407
1409 static constexpr std::uint8_t c_unseen = 0xFF;
1410
1411/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1412 // the first bytes of a file: magic, version, sizes, rule, encoding,
1413 // pattern and goal
1414
1415 [[nodiscard]] static std::vector< std::uint8_t > header( const Pattern & p ,
1416 BlankRule rule ,
1417 unsigned compress
1418 ) {
1419 std::vector< std::uint8_t > b = { 'P' , 'B' , 'e' , 'F' , 'S' , 'P' , 'D' ,
1420 'B' };
1421 put( b , file_version , 4 );
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() );
1431 return( b );
1432 }
1433
1434/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1435 // appends the k low bytes of x, the lowest first
1436
1437 static void put( std::vector< std::uint8_t > & b , std::uint64_t x ,
1438 int k ) {
1439 for( int i = 0 ; i < k ; ++i )
1440 b.push_back( std::uint8_t( x >> ( 8 * i ) ) );
1441 }
1442
1443/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1444 // the integer of the k bytes at b, the lowest first
1445
1446 [[nodiscard]] static std::uint64_t get( const std::uint8_t * b , int k )
1447 noexcept {
1448 std::uint64_t x = 0;
1449 for( int i = 0 ; i < k ; ++i )
1450 x |= std::uint64_t( b[ i ] ) << ( 8 * i );
1451 return( x );
1452 }
1453
1454/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1455 // calls f( a , b ) for the blocks [ a , b ) of [ 0 , n ) on p workers of
1456 // Executor, each worker taking the next block when it ends one
1457
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 };
1462 run_workers< Executor >( nullptr , p , [ & ]( unsigned ) {
1463 for( ; ; ) {
1464 const std::uint64_t a = next.fetch_add( block ,
1465 std::memory_order_relaxed );
1466 if( a >= n )
1467 break;
1468 f( a , std::min( n , a + block ) );
1469 }
1470 } );
1471 }
1472
1473/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1474 // BUILD-IGNORED: the distances with the blank ignored
1475
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 "
1485 "beyond 254" ) );
1486 std::atomic< std::uint64_t > fresh{ 0 };
1487 blocks< Executor >( h.size() , threads , [ & ]( std::uint64_t a ,
1488 std::uint64_t b ) {
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 )
1494 continue;
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 )
1505 continue;
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 ) )
1511 ++mine;
1512 }
1513 p[ i ] = old;
1514 }
1515 }
1516 fresh.fetch_add( mine , std::memory_order_relaxed );
1517 } );
1518 if( fresh.load() == 0 )
1519 return( h );
1520 }
1521 }
1522
1523/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1524 // BUILD-MINIMIZED: the distances with the blank minimized; the state of
1525 // ( r , b ) takes 2 bits (0 unseen, 1 current, 2 next, 3 old) at the
1526 // index r ( n - k ) + f, f being the index of b among the free cells
1527
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 );
1536
1537 // the index of the free cell b, and the mark of the state i as next
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 ) ) );
1541 };
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 );
1546 for( ; ; ) {
1547 if( ( old >> sh ) & 3u )
1548 return( false );
1549 if( w.compare_exchange_weak( old , old | ( std::uint64_t( 2 ) << sh ) ,
1550 std::memory_order_relaxed ) )
1551 return( true );
1552 }
1553 };
1554
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 ) );
1564 }
1565 h[ pat.goal_rank() ] = 0;
1566
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 ,
1573 std::uint64_t e ) {
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 ); // the fields = 1
1580 while( cur ) {
1581 const std::uint64_t i = wi * 32 +
1582 std::uint64_t( std::countr_zero( cur ) / 2 );
1583 cur &= cur - 1;
1584 if( i >= states )
1585 break;
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 );
1593 }
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 )
1598 continue; // not the least of its region
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 ];
1605 if( t < 0 )
1606 continue;
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 ,
1613 a2 );
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 );
1619 }
1620 }
1621 }
1622 }
1623 } );
1624
1625 // current -> old, next -> current
1626 std::atomic< std::uint64_t > fresh{ 0 };
1627 blocks< Executor >( s.size() , threads , [ & ]( std::uint64_t a ,
1628 std::uint64_t e ) {
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;
1634 w |= cur << 1;
1635 w = ( w & ~( nxt << 1 ) ) | nxt;
1636 s[ wi ] = w;
1637 mine += std::uint64_t( std::popcount( nxt ) );
1638 }
1639 fresh.fetch_add( mine , std::memory_order_relaxed );
1640 } );
1641 if( fresh.load() == 0 )
1642 return( h );
1643 }
1644 }
1645
1646/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1647
1648 Pattern f_pattern;
1649 BlankRule f_rule;
1650 unsigned f_compress;
1651 Enc f_entries;
1652 bool f_from_file;
1653 std::array< std::array< std::uint8_t , cells > , cells > v_md{};
1655
1656 }; // end( class( PatternTable ) )
1657
1658/*--------------------------------------------------------------------------*/
1659/*---------------------------- CLASS AdditivePDB ---------------------------*/
1660/*--------------------------------------------------------------------------*/
1662
1673
1674template< int W , int H , class Enc = NibbleEntries >
1676
1677/*------------------------ PUBLIC PART OF THE CLASS ------------------------*/
1678
1679 public:
1680
1681/*------------------------------ PUBLIC TYPES ------------------------------*/
1682
1686
1687 static constexpr int cells = W * H;
1688
1689/*------------------------------ CONSTRUCTOR -------------------------------*/
1691
1692 explicit AdditivePDB( std::vector< Table > tables , bool reflect = true )
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 );
1711 }
1712 }
1713 int blank = 0;
1714 for( int c = 0 ; c < cells ; ++c )
1715 if( v_goal[ c ] == 0 )
1716 blank = c;
1717 f_reflect = reflect && ( W == H ) && ( blank / W == blank % W );
1718 if( f_reflect ) {
1719 board_type cell{};
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 );
1723 }
1724 for( int t = 0 ; t < cells ; ++t )
1725 v_sigma[ t ] = v_goal[ v_transpose[ cell[ t ] ] ];
1726 }
1727 }
1728
1729/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1731
1734
1735 AdditivePDB( const Partition & partition ,
1736 const board_type & goal = Pattern::korf_goal() ,
1737 const PDBOptions & o = {} )
1738 : AdditivePDB( make< ADS::ThreadPool >( partition , goal , o ) ) {}
1739
1740/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1742
1743 template< class Executor >
1744 [[nodiscard]] static AdditivePDB make(
1745 const Partition & partition ,
1746 const board_type & goal = Pattern::korf_goal() ,
1747 const PDBOptions & o = {} ) {
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 ) );
1754 else
1755 t.push_back( Table::template cached< Executor >( o.cache , p , o.blank ,
1756 o.compress ,
1757 o.threads ) );
1758 }
1759 return( AdditivePDB( std::move( t ) , o.reflect ) );
1760 }
1761
1762/*-------------------------------- LOOKUPS ---------------------------------*/
1764
1765 [[nodiscard]] int heuristic( const std::uint8_t * q ) const noexcept
1766 requires( ! Enc::relative ) {
1767 const int a = sum( q );
1768 if( ! f_reflect )
1769 return( a );
1770 std::uint8_t r[ cells ];
1771 reflection( q , r );
1772 return( std::max( a , sum( r ) ) );
1773 }
1774
1775/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1777
1779
1780 [[nodiscard]] int sum( const std::uint8_t * q ) const noexcept
1781 requires( ! Enc::relative ) {
1782 int s = 0;
1783 std::uint8_t p[ cells ];
1784 for( const Table & t : v_tables ) {
1785 gather( t , q , p );
1786 s += t.value( p );
1787 }
1788 return( s );
1789 }
1790
1791/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1794
1795 [[nodiscard]] int exact( const std::uint8_t * q ) const
1796 requires( Enc::relative ) {
1797 const auto add = [ & ]( const std::uint8_t * x ) {
1798 int s = 0;
1799 std::uint8_t p[ cells ];
1800 for( const Table & t : v_tables ) {
1801 gather( t , x , p );
1802 s += t.exact( p );
1803 }
1804 return( s );
1805 };
1806 const int a = add( q );
1807 if( ! f_reflect )
1808 return( a );
1809 std::uint8_t r[ cells ];
1810 reflection( q , r );
1811 return( std::max( a , add( r ) ) );
1812 }
1813
1814/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1818
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 ) ];
1822 if( j < 0 )
1823 return( 0 );
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 );
1831 }
1832
1833/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1835
1836 void reflection( const std::uint8_t * q , std::uint8_t * r ) const noexcept
1837 {
1838 for( int t = 0 ; t < cells ; ++t )
1839 r[ v_sigma[ t ] ] = v_transpose[ q[ t ] ];
1840 }
1841
1842/*---------------------- METHODS FOR READING THE DATA ----------------------*/
1844
1845 [[nodiscard]] const board_type & goal( void ) const noexcept {
1846 return( v_goal );
1847 }
1848
1849/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1851
1852 [[nodiscard]] bool reflected( void ) const noexcept { return( f_reflect ); }
1853
1854/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1856
1857 [[nodiscard]] const std::vector< Table > & tables( void ) const noexcept {
1858 return( v_tables );
1859 }
1860
1861/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1863
1864 [[nodiscard]] std::size_t bytes( void ) const noexcept {
1865 std::size_t b = 0;
1866 for( const Table & t : v_tables )
1867 b += t.bytes();
1868 return( b );
1869 }
1870
1871/*----------------------- PRIVATE PART OF THE CLASS ------------------------*/
1872
1873 private:
1874
1875 // writes in p the placement of the tiles of t, from the cells q
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 ] ];
1881 }
1882
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{};
1890
1891 }; // end( class( AdditivePDB ) )
1892
1893/*--------------------------------------------------------------------------*/
1894/*-------------------------- CLASS SlidingTilePDB --------------------------*/
1895/*--------------------------------------------------------------------------*/
1897
1905
1906template< int W , int H , class Enc = NibbleEntries >
1907class SlidingTilePDB : public SlidingTile< W , H > {
1908
1909/*------------------------ PUBLIC PART OF THE CLASS ------------------------*/
1910
1911 public:
1912
1913/*------------------------------ PUBLIC TYPES ------------------------------*/
1914
1917 using state_type = typename Base::state_type;
1918 using cost_type = typename Base::cost_type;
1919 using board_type = typename Base::board_type;
1920
1921 static constexpr int cells = Base::cells;
1922
1923/*------------------------------ CONSTRUCTOR -------------------------------*/
1925
1926 SlidingTilePDB( const board_type & start , const PDB & pdb )
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 "
1932 "reflection" ) );
1933 }
1934
1935/*------------------------- METHODS OF THE DOMAIN --------------------------*/
1937
1938 [[nodiscard]] cost_type heuristic( state_type s ) const {
1939 std::uint8_t q[ cells ];
1940 cells_of( s , q );
1941 if constexpr( Enc::relative )
1942 return( f_pdb.exact( q ) );
1943 else
1944 return( f_pdb.heuristic( q ) );
1945 }
1946
1947/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1949
1950 template< class F >
1951 void for_each_successor( state_type s , cost_type h , F && f ) const {
1952 std::uint8_t q[ cells ];
1953 cells_of( s , q );
1954 const int b = Base::blank( s );
1955 Base::for_each_successor( s , h , [ & ]( state_type t , cost_type c ,
1956 cost_type ) {
1957 f( t , c , child_h( q , h , t , b ) );
1958 } );
1959 }
1960
1961/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1964
1965 template< class F >
1966 void for_each_successor( state_type s , cost_type h , std::uint8_t op ,
1967 F && f ) const {
1968 std::uint8_t q[ cells ];
1969 cells_of( s , q );
1970 const int b = Base::blank( s );
1971 Base::for_each_successor( s , h , op , [ & ]( state_type t , cost_type c ,
1972 cost_type , std::uint8_t o ) {
1973 f( t , c , child_h( q , h , t , b ) , o );
1974 } );
1975 }
1976
1977/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1979
1980 [[nodiscard]] const PDB & pdb( void ) const noexcept { return( f_pdb ); }
1981
1982/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
1984
1985 static void cells_of( state_type s , std::uint8_t * q ) noexcept {
1986 for( int c = 0 ; c < cells ; ++c )
1987 q[ Base::tile( s , c ) ] = std::uint8_t( c );
1988 }
1989
1990/*----------------------- PRIVATE PART OF THE CLASS ------------------------*/
1991
1992 private:
1993
1994 // the heuristic of the successor t of the state of cells q and heuristic
1995 // h, the blank of which was in b: the tile in b moved there from the
1996 // blank of t
1997 cost_type child_h( std::uint8_t * q , cost_type h , state_type t , int b )
1998 const noexcept {
1999 const int x = Base::tile( t , b );
2000 if constexpr( Enc::relative )
2001 return( h + f_pdb.delta( q , x , b ) );
2002 else {
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 );
2009 return( v );
2010 }
2011 }
2012
2013 const PDB & f_pdb;
2014
2015 }; // end( class( SlidingTilePDB ) )
2016
2017/*--------------------------------------------------------------------------*/
2018/*------------------------------- FUNCTIONS --------------------------------*/
2019/*--------------------------------------------------------------------------*/
2021
2022[[nodiscard]] inline Partition partition_15_7_8( void ) {
2023 return( Partition{ { 1 , 2 , 3 , 4 , 5 , 6 , 7 } ,
2024 { 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 } } );
2025 }
2026
2027/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
2030
2031[[nodiscard]] inline Partition partition_15_5_5_5( void ) {
2032 return( Partition{ { 1 , 2 , 4 , 5 , 8 } , { 3 , 6 , 7 , 10 , 11 } ,
2033 { 9 , 12 , 13 , 14 , 15 } } );
2034 }
2035
2036/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
2039
2040[[nodiscard]] inline Partition partition_15_6_6_3( void ) {
2041 return( Partition{ { 1 , 2 , 4 , 5 , 8 , 9 } ,
2042 { 3 , 6 , 7 , 10 , 11 , 15 } , { 12 , 13 , 14 } } );
2043 }
2044
2045/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
2047
2048[[nodiscard]] inline Partition partition_24_6_6_6_6( void ) {
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 } } );
2053 }
2054
2055/*--------------------------------------------------------------------------*/
2056
2057} // end( namespace PBeFS_di_unipi_it )
2058
2059/*--------------------------------------------------------------------------*/
2060
2061#endif /* __PBeFS_PatternDatabase */
2062
2063/*--------------------------------------------------------------------------*/
2064/*---------------------- End File PatternDatabase.h ------------------------*/
2065/*--------------------------------------------------------------------------*/
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