Skip to content

Commit 7392b6f

Browse files
committed
Reproducible results with different number of processes
1 parent 7d80519 commit 7392b6f

File tree

2 files changed

+41
-59
lines changed

2 files changed

+41
-59
lines changed

include/graphblas/algorithms/simulated_annealing_re.hpp

Lines changed: 32 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -43,32 +43,6 @@
4343
#define ISCLOSE(a,b) (std::abs((b)-(a))/std::abs(a) < 1e-4) || (std::abs((b)-(a)) < 1e-4)
4444

4545
namespace grb {
46-
namespace internal {
47-
/*
48-
* The following functions are used to ensure the correct type of the value in
49-
* in the exponential function.
50-
*/
51-
template< typename T >
52-
inline T exp(T x ){
53-
static_assert(
54-
std::is_same<T, float>::value
55-
|| std::is_same<T, double>::value
56-
|| std::is_same<T, long double>::value
57-
);
58-
return std::exp( x );
59-
}
60-
61-
template< typename T >
62-
inline T log(T x ){
63-
static_assert(
64-
std::is_same<T, float>::value
65-
|| std::is_same<T, double>::value
66-
|| std::is_same<T, long double>::value
67-
);
68-
return std::log( x );
69-
}
70-
} // namespace internal
71-
7246
namespace algorithms {
7347

7448
/*
@@ -154,13 +128,12 @@ namespace grb {
154128
assert( grb::size(energies) == n_replicas );
155129
assert( grb::size(betas) == n_replicas );
156130
#endif
157-
std::minstd_rand rng ( seed + s );
158-
std::exponential_distribution< EnergyType > rand ( 1.0 );
159131
struct data {
160132
EnergyType e;
161133
TempType b;
162134
EnergyType r;
163135
};
136+
// TODO: should these two be static? Probably.
164137
grb::Vector< StateType, backend > s0 ( n );
165138
grb::Vector< StateType, backend > s1 ( n );
166139
grb::set( s0, static_cast< StateType >( 0 ) );
@@ -170,13 +143,19 @@ namespace grb {
170143
rc = rc ? rc : grb::resize( s0, n );
171144
rc = rc ? rc : grb::resize( s1, n );
172145
if( rc != grb::SUCCESS ) return rc;
173-
const auto myrand = -rand( rng );
146+
147+
std::minstd_rand rng;
148+
std::exponential_distribution< EnergyType > rand ( 1.0 );
149+
150+
rng.seed( seed + s*n_replicas );
151+
const EnergyType myrand = -rand( rng );
174152

175153
for( size_t si = nprocs ; rc == grb::SUCCESS && si > 0; --si ){
176154
if( si-1 == s ){
177155
for( size_t i = n_replicas - 1 ; i > 0 ; --i ){
178156
const EnergyType de = ( energies[ i ] - energies[ i-1 ]) * (betas[ i ] - betas[ i-1 ]);
179157

158+
rng.seed( seed + s*n_replicas + i );
180159
if( -rand( rng ) < de ){
181160
std::swap( states[i], states[i-1] );
182161
std::swap( energies[i], energies[i-1] );
@@ -185,7 +164,7 @@ namespace grb {
185164
grb::set( s1, states[0] );
186165
msg[ 1 ].e = energies[ 0 ];
187166
msg[ 1 ].b = betas[0];
188-
// msg[ 1 ].r = rand;
167+
msg[ 1 ].r = myrand;
189168
}else if( si-2 == s ){
190169
grb::set( s0, states[ n_replicas - 1 ] );
191170
msg[ 0 ].e = energies[ n_replicas - 1 ];
@@ -200,6 +179,7 @@ namespace grb {
200179
rc = rc ? rc : grb::collectives<>::broadcast( msg[ 0 ].r, si-2 );
201180
rc = rc ? rc : grb::collectives<>::broadcast( msg[ 1 ].e, si-1 );
202181
rc = rc ? rc : grb::collectives<>::broadcast( msg[ 1 ].b, si-1 );
182+
rc = rc ? rc : grb::collectives<>::broadcast( msg[ 1 ].r, si-1 );
203183
#else
204184
assert( false ); // this should never run
205185
#endif
@@ -215,21 +195,21 @@ namespace grb {
215195

216196
const EnergyType de = ( msg[ 1 ].e - msg[ 0 ].e ) * ( msg[ 1 ].b - msg[ 0 ].b );
217197

218-
if( rc == grb::SUCCESS && ( msg[ 0 ].r < de ) ){
198+
if( rc == grb::SUCCESS && ( msg[ 1 ].r < de ) ){
219199
#ifdef _GRB_WITH_LPF
220-
rc = rc ? rc : grb::internal::broadcast( s0, si-2 );
221200
rc = rc ? rc : grb::internal::broadcast( s1, si-1 );
201+
rc = rc ? rc : grb::internal::broadcast( s0, si-2 );
222202
assert( grb::nnz(s0) == n ); // state has to be dense!
223203
assert( grb::nnz(s1) == n ); // state has to be dense!
224204
#else
225205
assert( false ); // this should never run
226206
#endif
227-
if( si == s+1 ){
228-
rc = rc ? rc : grb::set( states[ n_replicas - 1 ], s1 );
229-
rc = rc ? rc : grb::setElement(energies, msg[ 0 ].e, n_replicas - 1 );
230-
}else if( si == s+2 ){
207+
if( si-1 == s ){
231208
rc = rc ? rc : grb::set( states[ 0 ], s0 );
232-
rc = rc ? rc : grb::setElement(energies, msg[ 1 ].e, 0 );
209+
rc = rc ? rc : grb::setElement( energies, msg[ 0 ].e, 0 );
210+
}else if( si-2 == s ){
211+
rc = rc ? rc : grb::set( states[ n_replicas - 1 ], s1 );
212+
rc = rc ? rc : grb::setElement( energies, msg[ 1 ].e, n_replicas - 1 );
233213
}
234214
}
235215
}
@@ -308,18 +288,16 @@ namespace grb {
308288
(void) n;
309289
(void) s;
310290

291+
grb::RC rc = grb::SUCCESS;
292+
293+
#ifndef NDEBUG
311294
assert( n_replicas > 0 );
312295
assert( n_replicas == grb::size( betas ) );
313296

314297
for(size_t i = 0; i < n_replicas ; ++i ){
315298
assert( n == grb::size( states[ i ] ) );
316299
}
317-
318-
grb::RC rc = grb::SUCCESS;
319-
320-
321-
#ifndef NDEBUG
322-
if( grb::spmd<>::pid() == 0 ) {
300+
if( s == 0 ) {
323301
std::cerr << "DEBUG: Called simulated_annealing_RE with parameters: "
324302
<< "\n\t n = " << n
325303
<< "\n\t n_replicas = " << n_replicas
@@ -328,14 +306,18 @@ namespace grb {
328306
<< "\n\t use_pt = " << use_pt
329307
<< std::endl;
330308
}
309+
assert( grb::size(best_state) == n );
331310
#endif
332311

333312
best_energy = std::numeric_limits< EnergyType >::max();
334-
assert( grb::size(best_state) >= n );
335313

336314
for( size_t i_sweep = 0 ; rc == grb::SUCCESS && i_sweep < n_sweeps ; ++i_sweep ){
337315
for( size_t j = 0 ; j < n_replicas ; ++j ){
338-
316+
317+
const int seedi = i_sweep*n_procs*n_replicas + n_replicas*s + j;
318+
319+
std::get<8>(sweep_data).seed(seedi);
320+
339321
energies[j] += sweep( states[j], betas[j], sweep_data );
340322
grb::wait();
341323

@@ -352,7 +334,7 @@ namespace grb {
352334

353335
if( rc == SUCCESS && use_pt ){
354336
// do a Parallel Tempering move
355-
rc = pt< backend >( states, energies, betas, seed + i_sweep*n_procs + s );
337+
rc = pt( states, energies, betas, seed + i_sweep );
356338
}
357339

358340
#ifndef NDEBUG
@@ -421,21 +403,19 @@ namespace grb {
421403
grb::resize( frontier, n );
422404
grb::resize( w, n );
423405

424-
std::minstd_rand rng ( seed );
406+
std::minstd_rand rng ( seed );
425407

426408
// random shuffle w
427-
// const auto w_raw = grb::internal::getRaw( w );
428409
for( size_t i = 0 ; i < n ; ++i ){
429410
rc = rc ? rc : grb::setElement( w, i+1, i );
430411
}
431412
for( size_t i = 0 ; i < n ; ++i ){
432413
std::uniform_int_distribution< size_t > rand ( i, n-1 );
433-
const auto j = rand(rng);
414+
const auto j = rand( rng );
434415
const auto a = w[i];
435416
const auto b = w[j];
436417
rc = rc ? rc : grb::setElement( w, b, i );
437418
rc = rc ? rc : grb::setElement( w, a, j );
438-
// std::swap( w_raw[i], w_raw[j] );
439419
}
440420

441421
const grb::Semiring<
@@ -486,7 +466,7 @@ namespace grb {
486466
if( s == 0 ) {
487467
std::cerr << x.first << ", ";
488468
}
489-
cnt ++;
469+
cnt++;
490470
}
491471
}
492472
if( s == 0 ) {
@@ -610,7 +590,7 @@ namespace grb {
610590
grb::Vector< QType, backend > delta ( n );
611591
grb::Vector< QType, backend > dn ( n );
612592
grb::Vector< bool, backend > accept ( n );
613-
std::minstd_rand rng ( seed ); // minstd_rand or std::mt19937
593+
std::minstd_rand rng ( seed ); // minstd_rand or std::mt19937
614594

615595
rc = rc ? rc : grb::resize( h, n );
616596
rc = rc ? rc : grb::resize( rand, n );

tests/smoke/simulated_annealing_re_from_mpi.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -445,23 +445,25 @@ void grbProgram(
445445
}
446446

447447
// seed RNGs (C and C++ engines) using requested seed (hardcoded default 8 if not provided)
448-
std::minstd_rand rng ( data_in.seed + s ); // rng or std::mt19937
448+
std::minstd_rand rng ( data_in.seed ); // rng or std::mt19937
449449

450450
// create states storage and initialize with random 1/0 values
451451
const size_t n_replicas = data_in.n_replicas;
452452
std::vector< grb::Vector< IOType, internal_backend > > states0;
453453
std::vector< grb::Vector< IOType, internal_backend > > states;
454-
for ( size_t r = 0; r < n_replicas; ++r ) {
455-
states.emplace_back( grb::Vector< IOType, internal_backend >(n) );
456-
states0.emplace_back( grb::Vector< IOType, internal_backend >(n) );
454+
std::vector< IOType > rand_data (n);
455+
for ( size_t r = 0; r < nprocs * n_replicas; ++r ) {
457456
// initialize with random values
458457
std::uniform_int_distribution< unsigned short > randint(0,1);
459458
// we use buildvectorUnique with a random set of indices
460-
std::vector< IOType > rand_data;
461459
for ( size_t i = 0; i < n; ++i ) {
462-
rand_data.emplace_back( static_cast<IOType>(
463-
randint( rng ) ) );
460+
rand_data[i] = randint( rng );
464461
}
462+
463+
if( r/n_replicas != s ) continue;
464+
465+
states.emplace_back( grb::Vector< IOType, internal_backend >(n) );
466+
states0.emplace_back( grb::Vector< IOType, internal_backend >(n) );
465467
rc = rc ? rc : grb::buildVector(
466468
states0.back(),
467469
rand_data.cbegin(),

0 commit comments

Comments
 (0)