1 /* 2 * Copyright (C) 1998-2018 ALPS Collaboration. See COPYRIGHT.TXT 3 * All rights reserved. Use is subject to license terms. See LICENSE.TXT 4 * For use in publications, see ACKNOWLEDGE.TXT 5 */ 6 7 #pragma once 8 9 #include <alps/config.hpp> 10 11 #include <alps/accumulators/wrappers.hpp> 12 #include <alps/accumulators/feature/weight.hpp> 13 14 #include <alps/hdf5/archive.hpp> 15 #include <alps/utilities/stacktrace.hpp> 16 #include <alps/utilities/short_print.hpp> 17 18 #include <boost/utility.hpp> 19 #include <boost/shared_ptr.hpp> 20 21 #include <stdexcept> 22 #include <type_traits> 23 24 namespace alps { 25 namespace accumulators { 26 // this should be called namespace tag { template<typename T> struct weight_holder; } 27 // but gcc <= 4.4 has lookup error, so name it different 28 template<typename T> struct weight_holder_tag; 29 30 namespace impl { 31 32 template<typename T, typename W, typename B> struct Accumulator<T, weight_holder_tag<W>, B> : public B { 33 34 public: 35 typedef W weight_type; 36 typedef Result<T, weight_holder_tag<W>, typename B::result_type> result_type; 37 38 // TODO: add external weight! 39 Accumulatoralps::accumulators::impl::Accumulator40 Accumulator(): B(), m_owner(true), m_weight(new ::alps::accumulators::derived_accumulator_wrapper<W>(W())) {} 41 Accumulatoralps::accumulators::impl::Accumulator42 Accumulator(Accumulator const & arg): B(arg), m_owner(arg.m_owner), m_weight(arg.m_weight) {} 43 Accumulatoralps::accumulators::impl::Accumulator44 template<typename ArgumentPack> Accumulator(ArgumentPack const & args, typename std::enable_if<!is_accumulator<ArgumentPack>::value, int>::type = 0) 45 : B(args), m_owner(true), m_weight(new ::alps::accumulators::derived_accumulator_wrapper<W>(W())) 46 {} 47 weightalps::accumulators::impl::Accumulator48 base_wrapper<T> const * weight() const { 49 // TODO: make library for scalar type 50 return m_weight.get(); 51 } 52 operator ()alps::accumulators::impl::Accumulator53 void operator()(T const & val) { 54 // TODO: throw if weight is owned ... 55 B::operator()(val); 56 } 57 58 template<typename X> typename std::enable_if<std::conditional< 59 std::is_scalar<typename value_type<weight_type>::type>::value 60 , typename std::is_convertible<X, typename value_type<weight_type>::type>::type 61 , typename std::is_same<X, typename value_type<weight_type>::type>::type operator ()alps::accumulators::impl::Accumulator62 >::value>::type operator()(T const & val, X const & weight) { 63 // TODO: how do we make sure, weight is updated only once? 64 B::operator()(val); 65 (m_weight->template extract<W>())(weight); 66 } 67 68 template<typename X> typename std::enable_if<!std::conditional< 69 std::is_scalar<typename value_type<weight_type>::type>::value 70 , typename std::is_convertible<X, typename value_type<weight_type>::type>::type 71 , typename std::is_same<X, typename value_type<weight_type>::type>::type operator ()alps::accumulators::impl::Accumulator72 >::value>::type operator()(T const & /*val*/, X const & /*weight*/) { 73 throw std::runtime_error("Invalid type for binary call operator" + ALPS_STACKTRACE); 74 } 75 printalps::accumulators::impl::Accumulator76 template<typename S> void print(S & os, bool terse=false) const { 77 B::print(os, terse); 78 os << ", weight: "; 79 m_weight->print(os, terse); 80 } 81 savealps::accumulators::impl::Accumulator82 void save(hdf5::archive & ar) const { 83 B::save(ar); 84 ar["weight/value"] = *weight(); 85 } 86 loadalps::accumulators::impl::Accumulator87 void load(hdf5::archive & ar) { // TODO: make archive const 88 B::load(ar); 89 ar["weight/value"] >> *m_weight; 90 } 91 rankalps::accumulators::impl::Accumulator92 static std::size_t rank() { return B::rank() + 1; } can_loadalps::accumulators::impl::Accumulator93 static bool can_load(hdf5::archive & ar) { // TODO: make archive const 94 using alps::hdf5::get_extent; 95 96 ar.set_context("weight/value"); 97 bool is = weight_type::can_load(ar); 98 ar.set_context("../.."); 99 100 return is && B::can_load(ar); 101 } 102 resetalps::accumulators::impl::Accumulator103 void reset() { 104 B::reset(); 105 m_weight->reset(); 106 } 107 108 /// Merge placeholder \remark FIXME: always throws 109 template <typename A> mergealps::accumulators::impl::Accumulator110 void merge(const A& /*rhs*/) 111 { 112 throw std::logic_error("Merging weight_holder accumulators is not yet implemented" 113 +ALPS_STACKTRACE); 114 } 115 116 #ifdef ALPS_HAVE_MPI collective_mergealps::accumulators::impl::Accumulator117 void collective_merge( 118 alps::mpi::communicator const & comm 119 , int root 120 ) { 121 B::collective_merge(comm, root); 122 m_weight->collective_merge(comm, root); 123 } 124 collective_mergealps::accumulators::impl::Accumulator125 void collective_merge( 126 alps::mpi::communicator const & comm 127 , int root 128 ) const { 129 B::collective_merge(comm, root); 130 m_weight->collective_merge(comm, root); 131 } 132 #endif 133 owns_weightalps::accumulators::impl::Accumulator134 bool owns_weight() const { 135 return m_owner; 136 } 137 138 private: 139 bool m_owner; 140 boost::shared_ptr< ::alps::accumulators::base_wrapper<typename value_type<weight_type>::type> > m_weight; 141 }; 142 143 template<typename T, typename W, typename B> class Result<T, weight_holder_tag<W>, B> : public B { 144 145 public: 146 typedef W weight_type; 147 typedef typename detail::make_scalar_result_type<impl::Result,T,weight_holder_tag<W>,B>::type scalar_result_type; 148 Result()149 Result() 150 : B() 151 , m_owner(true) 152 , m_weight(new ::alps::accumulators::derived_result_wrapper<W>(W())) 153 {} 154 Result(A const & acc)155 template<typename A> Result(A const & acc) 156 : B(acc) 157 , m_owner(acc.owns_weight()) 158 // TODO: implement shared weight 159 , m_weight(acc.weight()->result()) 160 {} 161 weight() const162 base_wrapper<typename value_type<weight_type>::type> const * weight() const { 163 return m_weight.get(); 164 } 165 print(S & os,bool terse=false) const166 template<typename S> void print(S & os, bool terse=false) const { 167 B::print(os, terse); 168 os << ", weight: "; 169 m_weight->print(os, terse); 170 } 171 save(hdf5::archive & ar) const172 void save(hdf5::archive & ar) const { 173 B::save(ar); 174 ar["weight/value"] = *weight(); 175 } 176 load(hdf5::archive & ar)177 void load(hdf5::archive & ar) { 178 B::load(ar); 179 ar["weight/value"] >> *m_weight; 180 } 181 rank()182 static std::size_t rank() { return B::rank() + 1; } can_load(hdf5::archive & ar)183 static bool can_load(hdf5::archive & ar) { // TODO: make archive const 184 using alps::hdf5::get_extent; 185 186 ar.set_context("weight/value"); 187 bool is = weight_type::can_load(ar); 188 ar.set_context("../.."); 189 190 return is && B::can_load(ar); 191 } 192 193 protected: 194 bool m_owner; 195 boost::shared_ptr< ::alps::accumulators::base_wrapper<typename value_type<weight_type>::type> > m_weight; 196 }; 197 198 } 199 } 200 } 201