/******************************************************************************* * * 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