PBeFS
Parallel Best-First Search
Loading...
Searching...
No Matches
TravelingSalesman.h
Go to the documentation of this file.
1/*--------------------------------------------------------------------------*/
2/*------------------------ File TravelingSalesman.h ------------------------*/
3/*--------------------------------------------------------------------------*/
16/*--------------------------------------------------------------------------*/
17/*------------------------------ DEFINITIONS -------------------------------*/
18/*--------------------------------------------------------------------------*/
19
20#ifndef __PBeFS_TravelingSalesman
21 #define __PBeFS_TravelingSalesman
22 /* self-identification: #endif at the end of the file */
23
24/*--------------------------------------------------------------------------*/
25/*-------------------------------- INCLUDES --------------------------------*/
26/*--------------------------------------------------------------------------*/
27
28#include <algorithm>
29
30#include <bit>
31
32#include <cmath>
33
34#include <cstddef>
35
36#include <cstdint>
37
38#include <limits>
39
40#include <random>
41
42#include <stdexcept>
43
44#include <utility>
45
46#include <vector>
47
48#include "PBeFS/astar/Domain.h"
49
50/*--------------------------------------------------------------------------*/
51/*------------------------------- NAMESPACE --------------------------------*/
52/*--------------------------------------------------------------------------*/
53
55namespace PBeFS_di_unipi_it
56{
57
58/*--------------------------------------------------------------------------*/
59/*------------------------ CLASS TravelingSalesman -------------------------*/
60/*--------------------------------------------------------------------------*/
62
74
76
77/*------------------------ PUBLIC PART OF THE CLASS ------------------------*/
78
79 public:
80
81/*------------------------------ PUBLIC TYPES ------------------------------*/
82
83 using state_type = std::uint64_t;
84 using cost_type = double;
85 using matrix_type = std::vector< std::vector< double > >;
87
88/*------------------------------ CONSTRUCTOR -------------------------------*/
89
92
94 : v_d( std::move( dist ) ) , f_n( int( v_d.size() ) ) {
95 if( ( f_n < 2 ) || ( f_n > 32 ) )
96 throw( std::invalid_argument(
97 "TravelingSalesman::TravelingSalesman: 2 to 32 cities" ) );
98 f_all = ( std::uint64_t( 1 ) << f_n ) - 1;
99 }
100
101/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
104
105 [[nodiscard]] static matrix_type random_cities( int n ,
106 std::uint64_t seed ) {
107 if( n < 0 )
108 throw( std::invalid_argument(
109 "TravelingSalesman::random_cities: negative n" ) );
110 std::mt19937_64 gen( seed );
111 std::vector< double > x( n ) , y( n );
112 for( int c = 0 ; c < n ; ++c ) {
113 x[ c ] = random_unit( gen );
114 y[ c ] = random_unit( gen );
115 }
116 matrix_type d( n , std::vector< double >( n ) );
117 for( int a = 0 ; a < n ; ++a )
118 for( int b = 0 ; b < n ; ++b )
119 d[ a ][ b ] = std::hypot( x[ a ] - x[ b ] , y[ a ] - y[ b ] );
120 return( d );
121 }
122
123/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
125
126 [[nodiscard]] static int city( std::uint64_t s ) noexcept {
127 return( int( ( s >> 32 ) & 31 ) );
128 }
129
130/*------------------------- METHODS OF THE DOMAIN --------------------------*/
131
132 [[nodiscard]] std::uint64_t initial_state( void ) const noexcept {
133 return( 1 );
134 }
135
136 [[nodiscard]] bool is_goal( std::uint64_t s ) const noexcept {
137 return( ( s >> 37 ) & 1 );
138 }
139
140 [[nodiscard]] std::uint64_t hash( std::uint64_t s ) const noexcept {
141 return( ADS::splitmix64( s ) );
142 }
143
144/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
146
147 [[nodiscard]] double heuristic( std::uint64_t s ) const {
148 if( is_goal( s ) )
149 return( 0 );
150 int u[ 32 ];
151 std::size_t m = 0;
152 for( int c = 0 ; c < f_n ; ++c )
153 if( ! ( s & ( std::uint64_t( 1 ) << c ) ) || ( c == 0 ) ||
154 ( c == city( s ) ) )
155 u[ m++ ] = c;
156 double key[ 32 ];
157 bool in[ 32 ];
158 for( std::size_t k = 0 ; k < m ; ++k ) {
159 key[ k ] = std::numeric_limits< double >::infinity();
160 in[ k ] = false;
161 }
162 key[ 0 ] = 0;
163 double tot = 0;
164 for( std::size_t it = 0 ; it < m ; ++it ) {
165 std::size_t b = 0;
166 double best = std::numeric_limits< double >::infinity();
167 for( std::size_t k = 0 ; k < m ; ++k )
168 if( ! in[ k ] && ( key[ k ] < best ) )
169 best = key[ b = k ];
170 in[ b ] = true;
171 tot += best;
172 for( std::size_t k = 0 ; k < m ; ++k )
173 if( ! in[ k ] )
174 key[ k ] = std::min( key[ k ] , v_d[ u[ b ] ][ u[ k ] ] );
175 }
176 return( tot );
177 }
178
179/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
182
183 template< class F >
184 void for_each_successor( std::uint64_t s , double , F && f ) const {
185 const int c = city( s );
186 if( ( s & f_all ) == f_all ) { // back to the first city
187 const std::uint64_t t = ( s & f_all ) | ( std::uint64_t( 1 ) << 37 );
188 f( t , v_d[ c ][ 0 ] , 0.0 );
189 return;
190 }
191 for( int k = 1 ; k < f_n ; ++k )
192 if( ! ( s & ( std::uint64_t( 1 ) << k ) ) ) {
193 const std::uint64_t t = ( ( s & f_all ) | ( std::uint64_t( 1 ) << k ) ) |
194 ( std::uint64_t( k ) << 32 );
195 f( t , v_d[ c ][ k ] , heuristic( t ) );
196 }
197 }
198
199/*---------------------- FEATURES FOR ZOBRIST HASHING ----------------------*/
201
202 [[nodiscard]] std::size_t num_features( void ) const noexcept {
203 return( 2 * std::size_t( f_n ) + 1 );
204 }
205
208
209 template< class F >
210 void for_each_feature( std::uint64_t s , F && f ) const {
211 for( std::uint64_t v = s & f_all ; v ; v &= v - 1 )
212 f( std::size_t( std::countr_zero( v ) ) );
213 f( std::size_t( f_n + city( s ) ) );
214 if( is_goal( s ) )
215 f( 2 * std::size_t( f_n ) );
216 }
217
218/*------------------------------ OTHER HASHES ------------------------------*/
220
221 [[nodiscard]] std::uint64_t perfect_hash( std::uint64_t s ) const noexcept {
222 return( s );
223 }
224
225/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
227
256
257 [[nodiscard]] double held_karp( void ) const {
258 const int n = f_n;
259 const double inf = std::numeric_limits< double >::infinity();
260 std::vector< double > c( ( std::size_t( 1 ) << n ) * std::size_t( n ) ,
261 inf );
262 const auto at = [ & ]( std::uint64_t s , int j ) -> double & {
263 return( c[ std::size_t( s ) * std::size_t( n ) + std::size_t( j ) ] );
264 };
265 at( 1 , 0 ) = 0;
266 for( std::uint64_t s = 1 ; s <= f_all ; s += 2 )
267 for( int j = 0 ; j < n ; ++j )
268 if( ( s & ( std::uint64_t( 1 ) << j ) ) && ( at( s , j ) < inf ) )
269 for( int k = 1 ; k < n ; ++k )
270 if( ! ( s & ( std::uint64_t( 1 ) << k ) ) ) {
271 double & t = at( s | ( std::uint64_t( 1 ) << k ) , k );
272 t = std::min( t , at( s , j ) + v_d[ j ][ k ] );
273 }
274 double best = inf;
275 for( int j = 1 ; j < n ; ++j )
276 best = std::min( best , at( f_all , j ) + v_d[ j ][ 0 ] );
277 return( best );
278 }
279
280/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
282
283 [[nodiscard]] int size( void ) const noexcept { return( f_n ); }
284
285/*----------------------- PRIVATE PART OF THE CLASS ------------------------*/
286
287 private:
288
289 matrix_type v_d;
290 int f_n;
291 std::uint64_t f_all;
292
293 }; // end( class( TravelingSalesman ) )
294
295/*--------------------------------------------------------------------------*/
296
297} // end( namespace PBeFS_di_unipi_it )
298
299/*--------------------------------------------------------------------------*/
300
301#endif /* __PBeFS_TravelingSalesman */
302
303/*--------------------------------------------------------------------------*/
304/*---------------------- End File TravelingSalesman.h ----------------------*/
305/*--------------------------------------------------------------------------*/
Header file for the concepts a search problem has to satisfy in order to be searched by the algorithm...
void for_each_successor(std::uint64_t s, double, F &&f) const
calls f( t , c , h( t ) ) for each unvisited city, or for the way back to the city 0 once all are vis...
Definition TravelingSalesman.h:184
double cost_type
the cost type
Definition TravelingSalesman.h:84
std::vector< std::vector< double > > matrix_type
the distances
Definition TravelingSalesman.h:85
bool is_goal(std::uint64_t s) const noexcept
Definition TravelingSalesman.h:136
static matrix_type random_cities(int n, std::uint64_t seed)
the Euclidean distances of n random points of the unit square, drawn from the seed
Definition TravelingSalesman.h:105
std::uint64_t hash(std::uint64_t s) const noexcept
Definition TravelingSalesman.h:140
void for_each_feature(std::uint64_t s, F &&f) const
calls f( k ) for each visited city , f( n + c ) for the current city and f( 2 n ) if the tour is clo...
Definition TravelingSalesman.h:210
double held_karp(void) const
the cost of an optimal tour by the dynamic program of Held and Karp
Definition TravelingSalesman.h:257
std::uint64_t state_type
a packed state
Definition TravelingSalesman.h:83
std::uint64_t perfect_hash(std::uint64_t s) const noexcept
the perfect hash: the packed state
Definition TravelingSalesman.h:221
std::size_t num_features(void) const noexcept
the number of features: the visited cities, the current one, the end
Definition TravelingSalesman.h:202
int size(void) const noexcept
the number of cities
Definition TravelingSalesman.h:283
TravelingSalesman(matrix_type dist)
constructor, taking the distances,
Definition TravelingSalesman.h:93
double heuristic(std::uint64_t s) const
the cost of a minimum spanning tree of the cities still to be touched
Definition TravelingSalesman.h:147
std::uint64_t initial_state(void) const noexcept
Definition TravelingSalesman.h:132
static int city(std::uint64_t s) noexcept
the current city of the state s
Definition TravelingSalesman.h:126
namespace for the Parallel Best-First Search library
Definition AStar.h:83
double random_unit(Gen &gen)
a real number in [ 0 , 1 ) from the next word of a 64-bit generator
Definition SearchUtils.h:156