Skip to content

Commit 8f67ed9

Browse files
committed
Cleanup of useless ring parameter + function type templated
1 parent db2ae26 commit 8f67ed9

File tree

2 files changed

+67
-51
lines changed

2 files changed

+67
-51
lines changed

include/graphblas/algorithms/simulated_annealing_re.hpp

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -66,27 +66,27 @@ namespace grb {
6666
Backend backend
6767
>
6868
grb::RC pt(
69-
const std::vector< grb::Vector< StateType, backend > > &states,
70-
const grb::Vector< EnergyType > &energies,
71-
grb::Vector< TempType > &betas
69+
std::vector< grb::Vector< StateType, backend > > &states,
70+
grb::Vector< EnergyType > &energies,
71+
const grb::Vector< TempType > &betas
7272
){
7373
const size_t n_replicas = states.size();
7474

75-
for( size_t i = n_replicas-1 ; i > 0 ; --i ){
75+
for( size_t i = 1 ; i < n_replicas ; ++i ){
7676
const EnergyType de = ( energies[ i ] - energies[ i-1 ]) * (betas[ i ] - betas[ i-1 ]);
7777

7878
if( de >= 0 || std::rand() < RAND_MAX * exp( de ) ){
79-
std::swap( betas[i], betas[i-1] );
80-
}
79+
std::swap( states[i], states[i-1] );
80+
std::swap( energies[i], energies[i-1] );
81+
}
8182
}
8283

8384
return grb::SUCCESS;
8485
}
8586

8687
/*
87-
* Estimate a solution to a given Quadratic Unconstrained Binary Optimization
88-
* (QUBO) optimization problem. The solution is found using Simulated Annealing-
89-
* Replica Exchange (also known as Parallel Tempering).
88+
* Estimate a solution to a given optimization problem. The solution is found
89+
* using Simulated Annealing-Replica Exchange (also known as Parallel Tempering).
9090
*
9191
* The state will be optimized to minimize the value of the energy $U(x)$,
9292
* where $x$ is the binary state vector, and $couplings$ is the coupling matrix.
@@ -96,7 +96,7 @@ namespace grb {
9696
* returns the variation of energy made from its changes of the state.
9797
*
9898
* @param[in] sweep The sweeping function.
99-
* Should return the energy variation implied from the changes that it made on the state.
99+
* Should return the energy variation relative to the changes that it made on the state.
100100
* @param[in,out] states On input: initial states.
101101
* On output: optimized states.
102102
* @param[in] couplings The square (symmetric) couplings matrix.
@@ -113,7 +113,6 @@ namespace grb {
113113
* @tparam EnergyType The energy type.
114114
* @tparam TempType The inverse temperature type.
115115
* @tparam SweepDataType Type of data to be passed on to the sweep function (e.g. a tuple of references to temporary vectors).
116-
* @tparam Ring The semiring under which to make the sweeps.
117116
*
118117
*/
119118
template<
@@ -123,22 +122,18 @@ namespace grb {
123122
typename TempType,
124123
typename SweepDataType, // type of data to be passed through to the sweep function
125124
typename RSI, typename CSI, typename NZI, Backend backend,
126-
class Ring = Semiring<
127-
grb::operators::add< QType >, grb::operators::mul< QType >,
128-
grb::identities::zero, grb::identities::one
129-
>
130-
>
131-
grb::RC simulated_annealing_RE(
132-
const std::function<
125+
typename SweepFuncType = std::function<
133126
EnergyType(
134127
const grb::Matrix< QType, backend, RSI, CSI, NZI >&,
135128
const grb::Vector< QType, backend >&,
136129
grb::Vector< StateType, backend >&,
137130
const TempType&,
138-
SweepDataType&,
139-
const Ring&
131+
SweepDataType&
140132
)
141-
> &sweep,
133+
>
134+
>
135+
grb::RC simulated_annealing_RE(
136+
const SweepFuncType &sweep,
142137
std::vector< grb::Vector< StateType, backend > > &states,
143138
const grb::Matrix< QType, backend, RSI, CSI, NZI > &couplings,
144139
const grb::Vector< QType, backend > &local_fields,
@@ -148,8 +143,7 @@ namespace grb {
148143
grb::Vector< EnergyType > &temp_energies,
149144
SweepDataType& temp_sweep,
150145
const size_t &n_sweeps = 1,
151-
const bool &use_pt = false,
152-
const Ring &ring = Ring()
146+
const bool &use_pt = false
153147
){
154148

155149
const size_t n_replicas = states.size();
@@ -185,7 +179,9 @@ namespace grb {
185179
for( size_t i_sweep = 0 ; rc == grb::SUCCESS && i_sweep < n_sweeps ; ++i_sweep ){
186180
for( size_t j = 0 ; j < n_replicas ; ++j ){
187181

188-
energies[j] += sweep( couplings, local_fields, states[j], betas[j], temp_sweep, ring );
182+
grb::wait();
183+
energies[j] += sweep( couplings, local_fields, states[j], betas[j], temp_sweep );
184+
grb::wait();
189185

190186
// update_best state and energy
191187
if( energies[j] < temp_energies[j] ){
@@ -215,7 +211,7 @@ namespace grb {
215211
states = temp_states;
216212
energies = temp_energies;
217213
}
218-
214+
219215
return rc;
220216
}
221217

tests/smoke/simulated_annealing_re.cpp

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ using namespace grb;
4040

4141

4242
// Types
43-
using IOType = int8_t; // scalar/vector element type
44-
using JType = float; // coupling (matrix) value type
43+
using IOType = double; // scalar/vector element type
44+
using JType = double; // coupling (matrix) value type
4545
using EnergyType = double; // coupling (matrix) value type
4646

4747
/** Parser type */
@@ -126,10 +126,8 @@ namespace test_data {
126126

127127
const std::vector< std::vector< size_t > > row_blocks = {
128128
// {3, 1, 6, 7, 9, 11, 12, 13, 14, 15}, {5, 2, 0, 8, 10}, {4} // for python data files
129-
{0, 2, 4, 7, 9, 12, 13, 15},
130-
{1, 3, 6, 8, 11},
131-
{5, 10, 14},
132-
129+
{0, 2, 4, 7, 9, 12, 13, 15}, {1, 3, 6, 8, 11}, {5, 10, 14},
130+
// {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}
133131
};
134132

135133
std::minstd_rand global_rng ( 8 ); // or std::mt19937
@@ -291,6 +289,14 @@ EnergyType get_energy(
291289
}
292290

293291
template<
292+
typename SweepDataType = std::tuple<
293+
grb::Vector< JType >&,
294+
grb::Vector< JType >&,
295+
grb::Vector< IOType >&,
296+
const std::vector< grb::Vector< bool > >&,
297+
grb::Vector< EnergyType >&,
298+
grb::Vector< bool >&
299+
>,
294300
class Ring = Semiring<
295301
grb::operators::add< JType >, grb::operators::mul< JType >,
296302
grb::identities::zero, grb::identities::one
@@ -308,9 +314,10 @@ static EnergyType sequential_sweep_immediate(
308314
const std::vector< grb::Vector< bool > >&,
309315
grb::Vector< EnergyType >&,
310316
grb::Vector< bool >&
311-
> &data,
312-
const Ring &ring = Ring()
317+
> &data
313318
){
319+
const Ring ring = Ring();
320+
314321

315322
grb::RC rc = grb::SUCCESS;
316323
const size_t n = grb::size( state );
@@ -323,6 +330,7 @@ static EnergyType sequential_sweep_immediate(
323330
auto &dn = std::get<4>(data);
324331
auto &accept = std::get<5>(data);
325332

333+
rc = rc ? rc : grb::wait();
326334
rc = rc ? rc : grb::resize( h, n );
327335
rc = rc ? rc : grb::resize( log_rand, n );
328336
rc = rc ? rc : grb::resize( delta, n );
@@ -337,13 +345,12 @@ static EnergyType sequential_sweep_immediate(
337345
const auto rnd = rand( test_data::global_rng );
338346
rc = rc ? rc : grb::setElement(log_rand, std::log( rnd ), j );
339347
}
348+
// rc = rc ? rc : grb::wait();
340349
// print_vector( log_rand, 30, "log_rand" );
341350

342351
#ifndef NDEBUG
343352
const grb::Vector< IOType > old_state = state;
344-
const auto h0 = h;
345353
#endif
346-
grb::wait();
347354
for(const auto &mask : masks ){
348355

349356
rc = rc ? rc : grb::clear( accept );
@@ -358,17 +365,22 @@ static EnergyType sequential_sweep_immediate(
358365

359366
// ( dn >= 0 ) | ( log_rand < beta * dn )
360367
rc = rc ? rc : grb::set( accept, mask );
368+
rc = rc ? rc : grb::wait(); // ERROR: Segmentation Fault with nonblocking backend
361369
rc = rc ? rc : grb::eWiseLambda<>(
362370
[ &mask, &accept, &dn, &log_rand, beta ]( const size_t i ){
363371
(void) i;
364372
if( mask[i] ){
365373
accept[i] = ( dn[i] >= 0 ) || ( log_rand[i] < beta * dn[i] );
366374
}
367-
}, accept, log_rand, mask, dn );
375+
}, mask, log_rand, dn, accept );
376+
// print_vector( log_rand, 30, "log_rand" );
377+
// print_vector( mask, 30, "mask" );
378+
// print_vector( accept, 30, "accept" );
368379

369380
// new_state = np.where(accept, 1 - old, old)
370381
rc = rc ? rc : grb::foldl( state, accept, static_cast< IOType >( -1 ), ring.getMultiplicativeMonoid() );
371382
rc = rc ? rc : grb::foldl( state, accept, static_cast< IOType >( 1 ), ring.getAdditiveMonoid() );
383+
// print_vector( state, 30, "state" );
372384

373385
// delta = new - old ==> delta[accept] = 2*new_state[accept]-1
374386
rc = rc ? rc : grb::clear( delta );
@@ -378,12 +390,13 @@ static EnergyType sequential_sweep_immediate(
378390

379391
// Update delta_energy -= dot(dn, accept)
380392
rc = rc ? rc : grb::dot( delta_energy, delta, h, ring );
393+
// rc = rc ? rc : grb::wait();
381394

382395
// update h
383396
rc = rc ? rc : grb::mxv( h, couplings, delta, ring );
384397

385-
grb::wait();
386398
}
399+
rc = rc ? rc : grb::wait();
387400

388401
#ifndef NDEBUG
389402
if( rc != grb::SUCCESS ){
@@ -392,14 +405,18 @@ static EnergyType sequential_sweep_immediate(
392405
}
393406
assert( rc == grb::SUCCESS );
394407
const auto new_state = state;
408+
rc = rc ? rc : grb::wait();
395409

396-
// std::cerr << "\n\t Delta_energy: " << delta_energy;
397-
// std::cerr << "\n\t Real delta: " << (get_energy(couplings, local_fields, new_state) - get_energy(couplings, local_fields, old_state));
410+
const auto real_delta = get_energy(couplings, local_fields, new_state) - get_energy(couplings, local_fields, old_state);
411+
std::cerr << "\n\t Delta_energy: " << delta_energy;
412+
std::cerr << "\n\t Real delta: " << real_delta;
413+
std::cerr << "\n\t Discrepancy: " << real_delta - delta_energy;
398414
// std::cerr << "\n\t Old energy: " << get_energy(couplings, local_fields, old_state) ;
399415
// std::cerr << "\n\t New energy: " << get_energy(couplings, local_fields, new_state);
400-
// std::cerr << std::endl;
416+
std::cerr << std::endl;
401417

402-
assert( ISCLOSE(get_energy(couplings, local_fields, new_state) - get_energy(couplings, local_fields, old_state), delta_energy ) );
418+
assert( ISCLOSE(real_delta, delta_energy ) );
419+
// TODO: assert fails with nonblocking backend -> see issue #397
403420
#endif
404421

405422
return delta_energy;
@@ -415,19 +432,19 @@ template<
415432
grb::Vector< EnergyType >&,
416433
grb::Vector< bool >&
417434
>,
435+
typename SweepFuncType = std::function< EnergyType(
436+
const grb::Matrix< JType >&,
437+
const grb::Vector< JType >&,
438+
grb::Vector< IOType >&,
439+
const JType&,
440+
SweepDataType&
441+
) >,
418442
class Ring = Semiring<
419443
grb::operators::add< JType >, grb::operators::mul< JType >,
420444
grb::identities::zero, grb::identities::one
421445
>
422446
>
423-
std::function< EnergyType(
424-
const grb::Matrix< JType >&,
425-
const grb::Vector< JType >&,
426-
grb::Vector< IOType >&,
427-
const JType&,
428-
SweepDataType&,
429-
const Ring&
430-
) > get_sweep_function( std::string sweep_name ){
447+
SweepFuncType get_sweep_function( std::string sweep_name ){
431448
if( sweep_name != "sequential_sweep_immediate" ){
432449
std::cerr << "Warning: unknown sweep setting. Falling back to \"sequential_sweep_immediate\"" << std::endl;
433450
}
@@ -565,7 +582,9 @@ void grbProgram(
565582
for(const auto&i : v ){
566583
grb::setElement( masks.back(), 1, i );
567584
}
568-
print_vector( masks.back(), 30, "MASK" );
585+
if( s == 0 ){
586+
print_vector( masks.back(), 30, "MASK" );
587+
}
569588
}
570589

571590
// create states storage and initialize with random 1/0 values
@@ -631,7 +650,7 @@ void grbProgram(
631650
temp_dn,
632651
temp_accept
633652
);
634-
653+
grb::wait();
635654

636655

637656
out.rep = data_in.rep;
@@ -830,6 +849,7 @@ int main( int argc, char ** argv ) {
830849
}
831850

832851
// seed RNGs (C and C++ engines) using requested seed (hardcoded default 8 if not provided)
852+
in.seed += spmd<>::pid();
833853
std::srand( static_cast<unsigned>( in.seed ) );
834854
test_data::global_rng.seed(in.seed);
835855

0 commit comments

Comments
 (0)