1 #ifndef HOPS_REVERSIBLEJUMPPROPOSAL_HPP
2 #define HOPS_REVERSIBLEJUMPPROPOSAL_HPP
14 std::pair<double, double>
15 distanceInCoordinateDirection(Eigen::MatrixXd A, Eigen::VectorXd b, Eigen::VectorXd x,
long coordinate) {
16 Eigen::VectorXd slacks = b - A * x;
17 Eigen::VectorXd inverseDistances = A.col(coordinate).cwiseQuotient(slacks);
18 double forwardDistance = 1. / inverseDistances.maxCoeff();
19 double backwardDistance = 1. / inverseDistances.minCoeff();
20 assert(backwardDistance <= 0 && forwardDistance >= 0);
21 return std::make_pair(backwardDistance, forwardDistance);
26 template<
typename MarkovChainImpl,
typename Model>
31 Eigen::VectorXi m_jumpIndices,
32 const typename MarkovChainImpl::StateType parameterDefaultValues) :
33 MarkovChainImpl(markovChainImpl),
35 jumpIndices_(std::move(m_jumpIndices)),
36 defaultParameterValues(parameterDefaultValues) {
37 for (
long i = 0; i < parameterDefaultValues.rows(); i++) {
38 parameterActivationStates_.emplace_back(1);
41 typename MarkovChainImpl::StateType parameterState = MarkovChainImpl::getState();
42 for (
long i = 0; i < jumpIndices_.rows(); ++i) {
43 parameterActivationStates_[jumpIndices_(i)] = 0;
44 parameterState[jumpIndices_(i)] = defaultParameterValues[jumpIndices_(i)];
46 MarkovChainImpl::setState(parameterState);
50 if (uniformRealDistribution(randomNumberGenerator) < m_modelJumpProbability) {
51 drawInModelSpace(randomNumberGenerator, parameterActivationStates_, defaultParameterValues);
58 std::vector<int> ¶meterActivationStates,
59 typename MarkovChainImpl::StateType m_defaultValues) {
60 typename MarkovChainImpl::StateType m_proposal = MarkovChainImpl::getState();
61 std::vector<int> proposalActivationStates(parameterActivationStates_);
63 double logModelJumpProbabilityDifferential = jumpModel(randomNumberGenerator,
64 proposalActivationStates,
69 double modelJumpAcceptanceProbability = stateNegativeLogLikelihood - proposalNegativeLogLikelihood +
70 logModelJumpProbabilityDifferential;
71 if (std::log(uniformRealDistribution(randomNumberGenerator)) <= modelJumpAcceptanceProbability) {
72 stateNegativeLogLikelihood = proposalNegativeLogLikelihood;
73 proposalActivationStates.swap(parameterActivationStates_);
74 MarkovChainImpl::setState(m_proposal);
83 MarkovChainImpl::propose(randomNumberGenerator);
84 for(
long i=0; i<MarkovChainImpl::m_proposal.rows(); ++i) {
85 if(!parameterActivationStates_[i]) {
87 MarkovChainImpl::m_proposal(i) = MarkovChainImpl::state(i);
91 double acceptanceChance = std::log(uniformRealDistribution(randomNumberGenerator));
92 if (acceptanceChance < acceptanceProbability) {
93 MarkovChainImpl::acceptProposal();
94 stateNegativeLogLikelihood = proposalNegativeLogLikelihood;
95 numberOfAcceptedProposals++;
100 double acceptanceProbability = 0;
102 acceptanceProbability += MarkovChainImpl::computeLogAcceptanceProbability();
104 if (std::isfinite(acceptanceProbability)) {
106 MarkovChainImpl::getProposal());
107 acceptanceProbability += stateNegativeLogLikelihood - proposalNegativeLogLikelihood;
109 return acceptanceProbability;
113 return static_cast<double>(numberOfAcceptedProposals) / numberOfProposals;
117 typename MarkovChainImpl::StateType parameterState = MarkovChainImpl::getState();
118 typename MarkovChainImpl::StateType state(parameterState.rows() + 1);
119 long modelIndex = std::accumulate(parameterActivationStates_.begin(),
120 parameterActivationStates_.end(),
122 [](
unsigned int x,
unsigned int y) { return (x << 1) + y; });
123 state << modelIndex, parameterState;
130 std::vector<std::string> names = {
"model index"};
131 names.insert(names.end(), parameterNames.begin(), parameterNames.end());
136 double stateNegativeLogLikelihood = 0;
137 double proposalNegativeLogLikelihood = 0;
140 typename MarkovChainImpl::StateType::Scalar m_modelJumpProbability = 0.5;
141 typename MarkovChainImpl::StateType::Scalar parameterActivationProbability = 0.1;
142 typename MarkovChainImpl::StateType::Scalar parameterDeactivationProbability = 0.1;
143 typename MarkovChainImpl::StateType::Scalar stepSize = 0.1;
144 std::uniform_real_distribution<double> uniformRealDistribution;
147 typename MarkovChainImpl::StateType defaultParameterValues;
148 Eigen::VectorXi jumpIndices_;
150 std::vector<int> parameterActivationStates_;
152 long numberOfAcceptedProposals = 0;
153 long numberOfProposals = 0;
157 std::vector<int> &proposalActivationState,
158 typename MarkovChainImpl::StateType &m_proposal,
159 typename MarkovChainImpl::StateType &m_defaultValues) {
160 Eigen::VectorXi activationTracker = Eigen::VectorXi::Zero(jumpIndices_.size());
161 Eigen::VectorXi deactivationTracker = Eigen::VectorXi::Zero(jumpIndices_.size());
163 Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic> permutationMatrix(jumpIndices_.size());
164 permutationMatrix.setIdentity();
166 permutationMatrix.indices().data() + permutationMatrix.indices().size(),
167 randomNumberGenerator);
168 Eigen::VectorXi shuffledJumpIndices = permutationMatrix * jumpIndices_;
169 auto A = Model::getA();
170 auto b = Model::getB();
173 std::vector<double> tester;
174 for (
long index = 0; index < shuffledJumpIndices.size(); ++index) {
176 double defaultValue = m_defaultValues[shuffledJumpIndices(index)];
177 if (proposalActivationState[shuffledJumpIndices(index)]) {
180 auto[backwardsDistance, forwardsDistance] = distanceInCoordinateDirection(
184 shuffledJumpIndices(index));
185 double width = (forwardsDistance - backwardsDistance);
188 m_proposal[shuffledJumpIndices(index)] - defaultValue, stepSize * width, backwardsDistance,
191 double procProb = std::min(temp * parameterDeactivationProbability, 1.);
192 if (uniformRealDistribution(randomNumberGenerator) < procProb) {
193 proposalActivationState[shuffledJumpIndices(index)] = 0;
194 m_proposal[shuffledJumpIndices(index)] = defaultValue;
195 deactivationTracker(shuffledJumpIndices(index)) = 1;
198 j_fwd *= 1 - procProb;
201 if (uniformRealDistribution(randomNumberGenerator) < parameterActivationProbability) {
202 proposalActivationState[shuffledJumpIndices(index)] = 1;
204 auto[backwardsDistance, forwardsDistance] = distanceInCoordinateDirection(
208 shuffledJumpIndices(index));
210 double width = (forwardsDistance - backwardsDistance);
212 assert((std::abs(width - 0.9) < 1e-12) || (std::abs(width - 9.9) < 1e-12));
215 m_proposal[shuffledJumpIndices(index)] += gaussianStepDistribution.
draw(randomNumberGenerator,
219 assert(defaultValue + backwardsDistance <= m_proposal[shuffledJumpIndices(index)] && forwardsDistance + defaultValue >= m_proposal[shuffledJumpIndices(index)]);
220 activationTracker(shuffledJumpIndices(index)) = 1;
223 m_proposal[shuffledJumpIndices(index)] - defaultValue, stepSize * width, backwardsDistance,
225 tester.push_back(m_proposal[shuffledJumpIndices(index)] - defaultValue);
226 tester.push_back(stepSize * width);
227 tester.push_back(temp);
230 u_fwd *= temp * width;
231 j_fwd *= parameterActivationProbability;
233 j_fwd *= 1 - parameterActivationProbability;
241 permutationMatrix.indices().data() + permutationMatrix.indices().size(),
242 randomNumberGenerator);
243 shuffledJumpIndices = permutationMatrix * jumpIndices_;
246 for (
long index = 0; index < shuffledJumpIndices.size(); ++index) {
248 if (!proposalActivationState[shuffledJumpIndices(index)]) {
249 if (deactivationTracker(shuffledJumpIndices(index))) {
251 auto[backwardsDistance, forwardsDistance] = distanceInCoordinateDirection(
255 shuffledJumpIndices(index));
256 j_bck *= parameterActivationProbability;
257 double defaultValue = m_defaultValues[shuffledJumpIndices(index)];
259 auto temp_old_state = this->
getState()[shuffledJumpIndices(index) + 1];
260 assert(defaultValue + backwardsDistance <= temp_old_state && forwardsDistance + defaultValue >= temp_old_state);
262 double width = (forwardsDistance - backwardsDistance);
264 assert((std::abs(width - 0.9) < 1e-12) || (std::abs(width - 9.9) < 1e-12));
266 this->
getState()[shuffledJumpIndices(index) + 1] - defaultValue, stepSize * width, backwardsDistance,
273 u_bck *= temp * width;
275 j_bck *= 1 - parameterActivationProbability;
278 double defaultValue = defaultParameterValues[shuffledJumpIndices(index)];
282 auto[backwardsDistance, forwardsDistance] = distanceInCoordinateDirection(
286 shuffledJumpIndices(index));
287 double width = (forwardsDistance - backwardsDistance);
289 assert((std::abs(width - 0.9) < 1e-12) || (std::abs(width - 9.9) < 1e-12));
295 m_proposal[shuffledJumpIndices(index)] - defaultValue, stepSize * width, backwardsDistance,
297 tester.push_back(m_proposal[shuffledJumpIndices(index)] - defaultValue);
298 tester.push_back(stepSize * width);
299 tester.push_back(temp);
300 double prob = std::min(temp * parameterDeactivationProbability, 1.);
301 if (activationTracker(shuffledJumpIndices(index))) {
308 return std::log(j_bck * u_bck / (j_fwd * u_fwd));
313 #endif //HOPS_REVERSIBLEJUMPPROPOSAL_HPP