1 #ifndef HOPS_GAUSSIANPROCESS_HPP
2 #define HOPS_GAUSSIANPROCESS_HPP
7 #include <Eigen/Cholesky>
18 template<
typename MatrixType>
20 MatrixType newRhs(rhs.rows() + lhs.rows(), lhs.cols());
29 template<
typename MatrixType,
typename VectorType>
33 newRhs << rhs, lhs.transpose();
35 newRhs << lhs.transpose();
40 template<
typename VectorType>
52 template<
typename MatrixType,
typename VectorType,
typename Kernel>
56 kernel(kernel), isNewObservations(true) {
57 priorMeanFunction = [=](
VectorType) ->
double {
return constantPriorMean; };
61 priorMeanFunction(priorMeanFunction),
63 isNewObservations(true) {
73 gp.storedInputs = storedInputs;
74 gp.inputPriorMean = inputPriorMean;
76 gp.observationInputCovariance = observationInputCovariance;
77 gp.inputCovariance = inputCovariance;
79 gp.posteriorMean = posteriorMean;
80 gp.posteriorCovariance = posteriorCovariance;
81 gp.sqrtPosteriorCovariance = sqrtPosteriorCovariance;
83 gp.isNewObservations = isNewObservations;
84 gp.observedCovariance = observedCovariance;
85 gp.sqrtObservedCovariance = sqrtObservedCovariance;
87 gp.observedInputs = observedInputs;
88 gp.observedValues = observedValues;
89 gp.observedValueErrors = observedValueErrors;
99 bool isNewInput = (!storedInputs.size() || input != storedInputs);
100 if (isNewObservations || isNewInput) {
101 observationInputCovariance = kernel(observedInputs, input);
105 inputCovariance = kernel(input, input);
106 inputPriorMean = priorMean(input);
108 storedInputs = input;
111 if (isNewObservations) {
113 sqrtObservedCovariance = observedCovariance.llt().matrixL();
115 assert(sqrtObservedCovariance.isLowerTriangular()
116 &&
"error computing the cholesky factorization of the observed covariance, check code.");
118 posteriorMean = sqrtObservedCovariance.template triangularView<Eigen::Lower>().solve(observedValues - priorMean(observedInputs));
119 posteriorMean = sqrtObservedCovariance.template triangularView<Eigen::Lower>().transpose().solve(posteriorMean);
121 posteriorCovariance = sqrtObservedCovariance.template triangularView<Eigen::Lower>().solve(observationInputCovariance);
122 posteriorCovariance = sqrtObservedCovariance.template triangularView<Eigen::Lower>().transpose().solve(posteriorCovariance);
132 posteriorMean = inputPriorMean + observationInputCovariance.transpose() * posteriorMean;
140 posteriorCovariance = inputCovariance - observationInputCovariance.transpose() * posteriorCovariance;
143 Eigen::BDCSVD<MatrixType> solver(
MatrixType(posteriorCovariance), Eigen::ComputeFullU);
144 sqrtPosteriorCovariance = solver.matrixU() * solver.singularValues().cwiseSqrt().asDiagonal();
146 isNewObservations =
false;
156 size_t& maxElement) {
160 auto standardNormal = std::normal_distribution<double>();
162 for (
long i = 0; i < input.rows(); ++i) {
163 draw(i) = standardNormal(randomNumberGenerator);
164 assert(!std::isnan(draw(i)));
167 draw = posteriorMean + sqrtPosteriorCovariance * draw;
168 draw.maxCoeff(&maxElement);
174 size_t& maxElement) {
175 return sample(storedInputs, randomNumberGenerator, maxElement);
181 return sample(x, randomNumberGenerator, max);
186 return sample(storedInputs, randomNumberGenerator, max);
202 bool isUnique =
false) {
203 assert(x.size() == y.size());
204 assert(y.size() ==
error.size());
207 std::vector<long> updateCandidates;
208 std::vector<long> notFound;
209 for (
long i = 0; i < x.rows(); ++i) {
210 bool foundInput =
false;
211 for (
long j = 0; j < observedInputs.rows(); ++j) {
212 if (x.row(i) == observedInputs.row(j)) {
213 updateCandidates.push_back(j);
225 notFound.push_back(i);
230 if (updateCandidates.size() > 0) {
231 isNewObservations =
true;
234 for (
size_t i = 0; i < updateCandidates.size(); ++i) {
235 size_t k = updateCandidates[i];
238 observedValues(k) = y(i);
239 observedValueErrors(k) =
error(i);
244 observedCovariance(k, k) = kernel(observedInputs.row(k), observedInputs.row(k))(0, 0) + observedValueErrors(k);
254 MatrixType inputsNotFound(notFound.size(), x.cols());
258 for (
size_t i = 0; i < notFound.size(); ++i) {
259 long k = notFound[i];
261 inputsNotFound.row(i) = x.row(k);
262 valuesNotFound.row(i) = y.row(k);
263 errorsNotFound.row(i) =
error.row(k);
269 return {inputsNotFound, valuesNotFound, errorsNotFound};
288 assert(x.size() == y.size());
289 assert(y.size() ==
error.size());
291 isNewObservations =
true;
293 auto n = observedValues.size();
304 MatrixType newObservedCovariance = MatrixType::Zero(n + m, n + m);
306 newObservedCovariance.block(0, 0, n, n) = observedCovariance;
307 newObservedCovariance.block(0, n, n, m) = kernel(observedInputs, x);
308 newObservedCovariance.block(n, 0, m, n) = newObservedCovariance.block(0, n, n, m).transpose().eval();
309 newObservedCovariance.block(n, n, m, m) = kernel(x, x);
312 newObservedCovariance.block(n, n, m, m) +=
MatrixType(
error.asDiagonal());
319 MatrixType control = kernel(observedInputs, observedInputs);
320 control += Eigen::MatrixXd(observedValueErrors.asDiagonal());
322 control -= newObservedCovariance;
323 assert((control.size() == 0 || control.cwiseAbs().maxCoeff() < 1.e-5));
329 observedCovariance = newObservedCovariance;
343 return posteriorMean;
348 return posteriorCovariance;
353 return sqrtPosteriorCovariance;
363 return priorMeanFunction;
367 double oldSigma = kernel.m_sigma;
368 kernel.m_sigma = m_sigma;
369 observedCovariance -=
MatrixType(observedValueErrors.asDiagonal());
370 observedCovariance.array() *= (m_sigma / oldSigma);
371 observedCovariance +=
MatrixType(observedValueErrors.asDiagonal());
392 bool isNewObservations;
402 for (
long i = 0; i < x.rows(); ++i) {
403 prior(i) = priorMeanFunction(x.row(i));
436 #endif // HOPS_GAUSSIANPROCESS_HPP