1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
#include <assert.h>
#include "DiscreteDistribution.h"
namespace coalescence {
namespace utils {
namespace markov{
/*!
* \brief Defines a template class to represent a discrete markovian transition kernel
*
* For each initial state x_0 of an initial state space S_0, defines the associated
* discrete markovian probability p( x_1 = X | x_0).
* The arrival states of the kernel do not have to be identical (states with zero probabily can be omitted).
* Allows for sampling the next state knowing the present state x_0.
*
* \tparam State is the type of the states of the markov process, or equivalently the support of the markovian probability distribution.
*/
template<class...T>
class TransitionKernel;
template<typename State, typename Distribution>
class TransitionKernel<State, Distribution> {
private:
using SelfType = TransitionKernel<State, Distribution>;
std::unordered_map<State, Distribution> m_distributions;
public:
TransitionKernel(){}
//! \remark Distribution must be copy assignable
TransitionKernel(State const& x_0, Distribution const& dis){
m_distributions[x_0] = dis;
}
//! \remark Distribution must be move assignable
TransitionKernel(State const& x_0, Distribution&& dis){
m_distributions[x_0] = std::move(dis);
}
TransitionKernel(const TransitionKernel&) = default;
TransitionKernel(TransitionKernel&&) = default;
SelfType& operator=(const SelfType&) = default;
SelfType& operator=(SelfType&&) = default;
SelfType& add(State const& x_0, Distribution const& dis){
m_distributions[x_0] = dis;
return *this;
}
SelfType& add(State const& x_0, Distribution&& dis){
m_distributions[x_0] = std::move(dis);
}
bool has_distribution(State const& x_0) const {
return m_distributions.find(x_0) != m_distributions.end();
}
//! \remark sample distribution from state x_0 with random number generator g
template<typename Generator>
State operator()(State const& x_0, Generator& g) {
return m_distributions.at(x_0).operator()(g);
}
};
// transition kernel variable in time
template<typename State, typename Time, typename Distribution>
class TransitionKernel<State, Time, Distribution> {
private:
using SelfType = TransitionKernel<State, Time, Distribution>;
using InsiderType = TransitionKernel<State, Distribution>;
std::unordered_map<Time, InsiderType> m_kernels;
public:
TransitionKernel(){}
TransitionKernel(State const& x_0, Time const& t, Distribution const& d){
m_kernels[t] = InsiderType(x_0, d);
}
TransitionKernel(State const& x_0, Time const& t, Distribution&& d){
m_kernels[t] = InsiderType(x_0, std::move(d));
}
TransitionKernel(const TransitionKernel&) = default;
TransitionKernel(TransitionKernel&&) = default;
SelfType& operator=(const SelfType&) = default;
SelfType& operator=(SelfType&&) = default;
SelfType& add(State const& x_0, Time const& t, Distribution const& d){
m_kernels[t] = InsiderType(x_0, d);
return *this;
}
SelfType& add(State const& x_0, Time const& t, Distribution&& d){
m_kernels[t] = InsiderType(x_0, std::move(d));
return *this;
}
bool has_distribution(State const& x_0, Time const& t) const {
bool answer = false;
if(m_kernels.find(t) != m_kernels.end()){
if(m_kernels.at(t).has_distribution(x_0)){
answer = true;
}
}
return answer;
}
template<typename Generator>
State operator()(State const& x_0, Time const& t, Generator& g) {
return m_kernels.at(t).operator()(x_0, g);
}
};
} // namespace markov
} // namespace utils
} // namespace coalescence |