/*******************************************************************************
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 2011-2013 by M. Ferrero, O. Parcollet
*
* TRIQS is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* TRIQS. If not, see .
*
******************************************************************************/
#ifndef TRIQS_TOOLS_MC_MOVE_SET2_H
#define TRIQS_TOOLS_MC_MOVE_SET2_H
#include
#include
#include
#include
#include "./random_generator.hpp"
#include "./impl_tools.hpp"
namespace triqs { namespace mc_tools {
// mini concept checking
template struct has_attempt : std::false_type {};
template struct has_attempt ().attempt()))> : std::true_type {};
template struct has_accept : std::false_type {};
template struct has_accept ().accept())> : std::true_type {};
template struct has_reject : std::false_type {};
template struct has_reject().reject())> : std::true_type {};
//----------------------------------
template
class move {
std::shared_ptr impl_;
std::function clone_;
size_t hash_;
std::string type_name_;
std::function attempt_, accept_;
std::function reject_;
std::function h5_r, h5_w;
uint64_t NProposed, Naccepted;
double acceptance_rate_;
template
void construct_delegation (MoveType * p) {
impl_= std::shared_ptr (p);
hash_ = typeid(MoveType).hash_code();
type_name_ = typeid(MoveType).name();
clone_ = [p](){return MoveType(*p);};
attempt_ = [p](){return p->attempt();};
accept_ = [p](){return p->accept();};
reject_ = [p](){p->reject();};
h5_r = make_h5_read(p); // make_h5_read in impl_tools
h5_w = make_h5_write(p);
NProposed=0;
Naccepted=0;
acceptance_rate_ =-1;
}
public :
template
move (MoveType && p ) {
static_assert( is_move_constructible::value, "This move is not MoveConstructible");
static_assert( has_attempt::value, "This move has no attempt method (or is has an incorrect signature) !");
static_assert( has_accept::value, "This move has no accept method (or is has an incorrect signature) !");
static_assert( has_reject::value, "This move has no reject method (or is has an incorrect signature) !");
construct_delegation( new typename std::remove_reference::type(std::forward(p)));
}
// Close to value semantics. Everyone at the end call move = ...
// no default constructor.
move(move const &rhs) {*this = rhs;}
move(move &rhs) {*this = rhs;} // to avoid clash with tempalte construction !
move(move && rhs) { *this = std::move(rhs);}
move & operator = (move const & rhs) { *this = rhs.clone_(); return *this;}
#ifndef TRIQS_WORKAROUND_INTEL_COMPILER_BUGS
move & operator = (move && rhs) = default;
#else
move & operator = (move && rhs) { // how painful is icc !
using std::swap;
#define SW(X) swap(X,rhs.X)
SW(impl_); SW(hash_); SW(type_name_); SW(clone_);
SW(attempt_); SW(accept_); SW(reject_); SW(h5_r); SW(h5_w);
SW(NProposed);SW(Naccepted); SW(acceptance_rate_);
#undef SW
return *this;
}
#endif
MCSignType attempt(){ NProposed++; return attempt_();}
MCSignType accept() { Naccepted++; return accept_(); }
void reject() { reject_(); }
double acceptance_rate() const { return acceptance_rate_;}
void collect_statistics(boost::mpi::communicator const & c) {
uint64_t nacc_tot=0, nprop_tot=1;
boost::mpi::reduce(c, Naccepted, nacc_tot, std::plus(), 0);
boost::mpi::reduce(c, NProposed, nprop_tot, std::plus(), 0);
acceptance_rate_ = nacc_tot/static_cast(nprop_tot);
}
// true iif the stored object has type MoveType Cf hash_code doc.
template bool has_type() const { return (typeid(MoveType).hash_code() == hash_); };
template void check_type() const {
if (!(has_type()))
TRIQS_RUNTIME_ERROR << "Trying to retrieve a move of type "<< typeid(MoveType).name() << " from a move of type "<< type_name_;
};
// retrieve an object of the correct type
template MoveType & get() { check_type(); return *(static_cast(impl_.get())); }
template MoveType const & get() const { check_type(); return *(static_cast(impl_.get())); }
// redirect the h5 call to the object lambda, if it not empty (i.e. if the underlying object can be called with h5_read/write
friend void h5_write (h5::group g, std::string const & name, move const & m){ if (m.h5_w) m.h5_w(g,name);};
friend void h5_read (h5::group g, std::string const & name, move & m) { if (m.h5_r) m.h5_r(g,name);};
};
//--------------------------------------------------------------------
/// A vector of (moves, proposition_probability), which is also a move itself
template
class move_set {
std::vector > move_vec;
std::vector names_;
move * current;
size_t current_move_number;
random_generator * RNG;
std::vector Proba_Moves, Proba_Moves_Acc_Sum;
MCSignType try_sign_ratio;
uint64_t debug_counter;
public:
///
move_set(random_generator & R): RNG(&R) { Proba_Moves.push_back(0); debug_counter=0;}
///
move_set(move_set const &) = default;
move_set(move_set &&) = default;
move_set& operator = (move_set const &) = default;
#ifndef TRIQS_WORKAROUND_INTEL_COMPILER_BUGS
move_set& operator = (move_set &&) = default;
#else
move_set& operator = (move_set && rhs) {
using std::swap;
#define SW(X) swap(X,rhs.X)
SW(move_vec); SW(names_); SW(current); SW(current_move_number); SW(RNG);
SW(Proba_Moves); SW(Proba_Moves_Acc_Sum); SW(try_sign_ratio); SW(debug_counter);
#undef SW
return *this;
}
#endif
/**
* Add move M with its probability of being proposed.
* NB : the proposition_probability needs to be >0 but does not need to be
* normalized. Normalization is automatically done with all the added moves
* before starting the run
*/
template
void add (MoveType && M, std::string name, double proposition_probability) {
move_vec.emplace_back(std::forward(M));
assert(proposition_probability >=0);
Proba_Moves.push_back(proposition_probability);
names_.push_back(name);
normaliseProba();// ready to run after each add !
}
/**
* - Picks up one of the move at random (weighted by their proposition probability),
* - Call attempt method of that move
* - Returns the metropolis ratio R (see move concept).
* The sign ratio returned by the try method of the move is kept.
*/
double attempt() {
assert( Proba_Moves_Acc_Sum.size()>0);
// Choice of move with its probability
double proba = (*RNG)(); assert(proba>=0);
current_move_number =0; while (proba >= Proba_Moves_Acc_Sum[current_move_number] ) { current_move_number++;}
assert(current_move_number>0); assert(current_move_number<=move_vec.size());
current_move_number--;
current = & move_vec[current_move_number];
#ifdef TRIQS_TOOLS_MC_DEBUG
std::cerr << "*******************************************************"<< std::endl;
std::cerr << "move number : " << debug_counter++ << std::endl;
std::cerr << "Name of the proposed move: " << name_of_currently_selected() << std::endl;
std::cerr <<" Proposition probability = "<attempt();
if (!std::isfinite(std::abs(rate_ratio)))
TRIQS_RUNTIME_ERROR<<"Monte Carlo Error : the rate is not finite in move "<=0));
try_sign_ratio = ( abs_rate_ratio> 1.e-14 ? rate_ratio/abs_rate_ratio : 1); // keep the sign
return abs_rate_ratio;
}
/**
* accept the move previously selected and tried.
* Returns the Sign computed as, if M is the move :
* Sign = sign (M.attempt()) * M.accept()
*/
MCSignType accept() {
MCSignType accept_sign_ratio = current->accept();
// just make sure that accept_sign_ratio is a sign!
assert(std::abs(std::abs(accept_sign_ratio)-1.0) < 1.e-10);
#ifdef TRIQS_TOOLS_MC_DEBUG
std::cerr.setf(std::ios::scientific, std::ios::floatfield);
std::cerr<<" ... Move accepted"<reject();
}
/// Pretty printing of the acceptance probability of the moves.
std::string get_statistics(boost::mpi::communicator const & c, int shift = 0) {
std::ostringstream s;
for (unsigned int u =0; u< move_vec.size(); ++u) {
move_vec[u].collect_statistics(c);
for(int i=0; i()) {
auto & ms = move_vec[u].template get();
s << "Move set " << names_[u] << ": " << move_vec[u].acceptance_rate() << "\n";
s << ms.get_statistics(c,shift+2);
} else {
s << "Move " << names_[u] << ": " << move_vec[u].acceptance_rate() << "\n";
}
}
return s.str();
}
private:
void normaliseProba() { // Computes the normalised accumulated probability
if (move_vec.size() ==0) TRIQS_RUNTIME_ERROR<<" no moves registered";
double acc = 0;
Proba_Moves_Acc_Sum.clear();
for (unsigned int u = 0; u0);
for (unsigned int u = 0; u
MoveType & get_move(std::string const & name) {
int u=0; for (;u();
}
template
MoveType const & get_move(std::string const & name) const {
int u=0; for (;u();
}
};// class move_set
}}// end namespace
#endif