1 #ifndef HOPS_CSMMALA_HPP
2 #define HOPS_CSMMALA_HPP
4 #include <Eigen/Eigenvalues>
11 namespace CSmMALAProposalDetails {
12 template<
typename MatrixType>
15 double &logSqrtDeterminant) {
16 Eigen::BDCSVD<MatrixType> solver(metric, Eigen::ComputeFullU);
17 sqrtInvMetric = solver.matrixU() * solver.singularValues().cwiseInverse().cwiseSqrt().asDiagonal() *
18 solver.matrixU().adjoint();
19 logSqrtDeterminant = 0.5 * solver.singularValues().array().log().sum();
23 template<
typename ModelType,
typename InternalMatrixType>
48 void setStepSize(
typename MatrixType::Scalar newStepSize);
66 MatrixType::Scalar stateLogSqrtDeterminant = 0;
67 MatrixType::Scalar proposalLogSqrtDeterminant = 0;
68 MatrixType::Scalar stateNegativeLogLikelihood = 0;
69 MatrixType::Scalar proposalNegativeLogLikelihood = 0;
75 MatrixType::Scalar stepSize = 1;
76 MatrixType::Scalar fisherWeight = .5;
77 MatrixType::Scalar fisherScale = 1.;
78 MatrixType::Scalar geometricFactor = 0;
79 MatrixType::Scalar covarianceFactor = 0;
81 std::normal_distribution<MatrixType::Scalar> normalDistribution{0., 1.};
85 template<
typename ModelType,
typename InternalMatrixType>
90 ModelType(std::move(model)),
93 dikinEllipsoidCalculator(this->A, this->b) {
94 stateMetric = Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>::Zero(
95 currentState.rows(), currentState.rows());
96 proposalMetric = Eigen::Matrix<typename MatrixType::Scalar, Eigen::Dynamic, Eigen::Dynamic>::Zero(
97 currentState.rows(), currentState.rows());
103 template<
typename ModelType,
typename InternalMatrixType>
106 for (
long i = 0; i < m_proposal.rows(); ++i) {
107 m_proposal(i) = normalDistribution(randomNumberGenerator);
109 m_proposal = driftedState + covarianceFactor * (stateSqrtInvMetric * m_proposal);
112 template<
typename ModelType,
typename InternalMatrixType>
114 state.swap(m_proposal);
115 driftedState.swap(driftedProposal);
116 stateSqrtInvMetric.swap(proposalSqrtInvMetric);
117 stateMetric.swap(proposalMetric);
118 stateLogSqrtDeterminant = proposalLogSqrtDeterminant;
119 stateNegativeLogLikelihood = proposalNegativeLogLikelihood;
122 template<
typename ModelType,
typename InternalMatrixType>
123 typename MatrixType::Scalar
125 bool isProposalInteriorPoint = ((A * m_proposal - b).array() < 0).all();
126 if (!isProposalInteriorPoint) {
127 return -std::numeric_limits<typename MatrixType::Scalar>::infinity();
131 VectorType gradient = computeTruncatedGradient(m_proposal);
132 proposalMetric.setZero();
133 if (fisherWeight != 0) {
134 auto optionalFisherInformation = ModelType::computeExpectedFisherInformation(m_proposal);
135 if(optionalFisherInformation) {
136 auto fisherInformation = optionalFisherInformation.value();
137 proposalMetric += (fisherWeight * fisherScale * fisherInformation);
140 if (fisherWeight != 1) {
141 auto dikinEllipsoid = dikinEllipsoidCalculator.computeDikinEllipsoid(m_proposal);
142 proposalMetric += (1 - fisherWeight) * dikinEllipsoid;
146 proposalLogSqrtDeterminant);
147 driftedProposal = m_proposal +
148 0.5 * std::pow(covarianceFactor, 2) * proposalSqrtInvMetric * proposalSqrtInvMetric *
150 proposalNegativeLogLikelihood = ModelType::computeNegativeLogLikelihood(m_proposal);
152 double normDifference =
153 static_cast<double>((driftedState - m_proposal).transpose() * stateMetric * (driftedState - m_proposal)) -
154 static_cast<double>((state - driftedProposal).transpose() * proposalMetric * (state - driftedProposal));
156 return -proposalNegativeLogLikelihood
157 + stateNegativeLogLikelihood
158 + proposalLogSqrtDeterminant
159 - stateLogSqrtDeterminant
160 + geometricFactor * normDifference;
163 template<
typename ModelType,
typename InternalMatrixType>
168 template<
typename ModelType,
typename InternalMatrixType>
170 state.swap(newState);
172 VectorType gradient = computeTruncatedGradient(state);
173 stateMetric.setZero();
174 if (fisherWeight != 0) {
175 auto optionalFisherInformation = ModelType::computeExpectedFisherInformation(m_proposal);
176 if(optionalFisherInformation) {
177 auto fisherInformation = optionalFisherInformation.value();
178 proposalMetric += fisherWeight * fisherScale * fisherInformation;
181 if (fisherWeight != 1) {
182 auto dikinEllipsoid = dikinEllipsoidCalculator.computeDikinEllipsoid(state);
183 stateMetric += (1 - fisherWeight) * dikinEllipsoid;
187 stateLogSqrtDeterminant);
188 driftedState = state + 0.5 * std::pow(covarianceFactor, 2) * stateSqrtInvMetric * stateSqrtInvMetric *
190 stateNegativeLogLikelihood = ModelType::computeNegativeLogLikelihood(state);
193 template<
typename ModelType,
typename InternalMatrixType>
198 template<
typename ModelType,
typename InternalMatrixType>
203 template<
typename ModelType,
typename InternalMatrixType>
205 stepSize = newStepSize;
206 geometricFactor = A.cols() / (2 * stepSize * stepSize);
207 covarianceFactor = stepSize / std::sqrt(A.cols());
211 template<
typename ModelType,
typename InternalMatrixType>
213 typename MatrixType::Scalar newFisherWeight) {
214 if (fisherWeight > 1 || fisherWeight < 0) {
215 throw std::runtime_error(
"fisherWeight should be in [0, 1].");
217 fisherWeight = newFisherWeight;
221 template<
typename ModelType,
typename InternalMatrixType>
223 return stateNegativeLogLikelihood;
226 template<
typename ModelType,
typename InternalMatrixType>
231 template<
typename ModelType,
typename InternalMatrixType>
233 auto gradient = ModelType::computeLogLikelihoodGradient(x);
235 double norm = gradient.value().norm();
237 gradient.value() /= norm;
239 return gradient.value();
241 return VectorType::Zero(x.rows());
245 #endif //HOPS_CSMMALA_HPP