1010 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
1111 */
1212
13- #ifndef INCLUDE_ALBATROSS_MODELS_SPARSE_GP_H_
14- #define INCLUDE_ALBATROSS_MODELS_SPARSE_GP_H_
13+ #ifndef ALBATROSS_SRC_MODELS_SPARSE_GP_HPP
14+ #define ALBATROSS_SRC_MODELS_SPARSE_GP_HPP
1515
1616namespace albatross {
1717
@@ -74,7 +74,7 @@ template <typename FeatureType> struct SparseGPFit {};
7474template <typename FeatureType> struct Fit <SparseGPFit<FeatureType>> {
7575
7676 std::vector<FeatureType> train_features;
77- Eigen::SerializableLDLT train_covariance;
77+ BlockDiagonalLDLT train_covariance;
7878 Eigen::MatrixXd sigma_R;
7979 Eigen::Matrix<int , Eigen::Dynamic, 1 > permutation_indices;
8080 Eigen::VectorXd information;
@@ -83,7 +83,7 @@ template <typename FeatureType> struct Fit<SparseGPFit<FeatureType>> {
8383 Fit (){};
8484
8585 Fit (const std::vector<FeatureType> &features_,
86- const Eigen::SerializableLDLT &train_covariance_,
86+ const BlockDiagonalLDLT &train_covariance_,
8787 const Eigen::MatrixXd sigma_R_,
8888 const Eigen::Matrix<int , Eigen::Dynamic, 1 > permutation_indices_,
8989 const Eigen::VectorXd &information_, Eigen::Index numerical_rank_)
@@ -351,12 +351,12 @@ class SparseGaussianProcessRegression
351351 // Sigma = (B^T B)^-1
352352 //
353353 Eigen::ColPivHouseholderQR<Eigen::MatrixXd>
354- compute_sigma_qr (const Eigen::SerializableLDLT &K_uu_ldlt,
354+ compute_sigma_qr (const BlockDiagonalLDLT &K_uu_ldlt,
355355 const BlockDiagonalLDLT &A_ldlt,
356356 const Eigen::MatrixXd &K_fu) const {
357357 Eigen::MatrixXd B (A_ldlt.rows () + K_uu_ldlt.rows (), K_uu_ldlt.rows ());
358358 B.topRows (A_ldlt.rows ()) = A_ldlt.sqrt_solve (K_fu);
359- B.bottomRows (K_uu_ldlt.rows ()) = K_uu_ldlt.sqrt_transpose ();
359+ B.bottomRows (K_uu_ldlt.rows ()) = K_uu_ldlt.sqrt_transpose (). to_dense () ;
360360 return B.colPivHouseholderQr ();
361361 };
362362
@@ -371,7 +371,12 @@ class SparseGaussianProcessRegression
371371 auto u = inducing_point_strategy_ (this ->covariance_function_ , features);
372372 ALBATROSS_ASSERT (!u.empty () && " Empty inducing points!" );
373373
374- const auto K_uu_ldlt = compute_kuu_ldlt (&u);
374+ // Compute K_uu = P_cols.T * D * P_cols
375+ // where D is a block diagonal. Instead of storing the permutation
376+ // we can just use D and reorder the inducing points
377+ const auto structured_K_uu_ldlt = compute_kuu_ldlt (&u);
378+ const auto &K_uu_ldlt = structured_K_uu_ldlt.matrix ;
379+ u = structured_K_uu_ldlt.P_cols * u;
375380
376381 BlockDiagonalLDLT A_ldlt;
377382 Eigen::MatrixXd K_fu;
@@ -401,14 +406,23 @@ class SparseGaussianProcessRegression
401406
402407 new_fit.train_features = new_inducing_points;
403408
404- const Eigen::MatrixXd K_zz =
405- this ->covariance_function_ (new_inducing_points, Base::threads_.get ());
406- new_fit.train_covariance = Eigen::SerializableLDLT (K_zz);
409+ auto K_zz = this ->covariance_function_ (new_fit.train_features ,
410+ Base::threads_.get ());
411+ K_zz.diagonal () +=
412+ inducing_nugget_.value * Eigen::VectorXd::Ones (K_zz.rows ());
413+ const auto block_diag_K_zz = linalg::infer_block_diagonal_matrix (K_zz);
407414
415+ // Store only the inner block diagonal representation and reorder
416+ // the inducing points to match;
417+ new_fit.train_covariance = block_diag_K_zz.matrix .ldlt ();
418+
419+ const auto &P = block_diag_K_zz.P_cols ;
420+ new_fit.train_features = P * new_fit.train_features ;
421+ JointDistribution prediction (P * prediction_.mean ,
422+ P * prediction_.covariance * P.transpose ());
408423 // We're going to need to take the sqrt of the new covariance which
409424 // could be extremely small, so here we add a small nugget to avoid
410425 // numerical instability
411- JointDistribution prediction (prediction_);
412426 prediction.covariance .diagonal () += Eigen::VectorXd::Constant (
413427 cast::to_index (prediction.size ()), 1 , details::DEFAULT_NUGGET);
414428 new_fit.information = new_fit.train_covariance .solve (prediction.mean );
@@ -439,6 +453,7 @@ class SparseGaussianProcessRegression
439453 // We can then compute and store the QR decomposition of B
440454 // as we do in a normal fit.
441455 const Eigen::SerializableLDLT C_ldlt (prediction.covariance );
456+ // think about this, probably a better way:
442457 const Eigen::MatrixXd sigma_inv_sqrt = C_ldlt.sqrt_solve (K_zz);
443458 const auto B_qr = sigma_inv_sqrt.colPivHouseholderQr ();
444459
@@ -529,7 +544,12 @@ class SparseGaussianProcessRegression
529544 auto u =
530545 inducing_point_strategy_ (this ->covariance_function_ , dataset.features );
531546
532- const auto K_uu_ldlt = compute_kuu_ldlt (&u);
547+ // Compute K_uu = P_cols.T * D * P_cols
548+ // where D is a block diagonal. Instead of storing the permutation
549+ // we can just use D and reorder the inducing points
550+ const auto structured_K_uu_ldlt = compute_kuu_ldlt (&u);
551+ const auto &K_uu_ldlt = structured_K_uu_ldlt.matrix ;
552+ u = structured_K_uu_ldlt.P_cols * u;
533553
534554 BlockDiagonalLDLT A_ldlt;
535555 Eigen::MatrixXd K_fu;
@@ -599,13 +619,14 @@ class SparseGaussianProcessRegression
599619
600620private:
601621 template <typename InducingFeatureType>
602- auto
622+ Structured<BlockDiagonalLDLT>
603623 compute_kuu_ldlt (std::vector<InducingFeatureType> *inducing_features) const {
604624 auto K_uu =
605625 this ->covariance_function_ (*inducing_features, Base::threads_.get ());
606626 K_uu.diagonal () +=
607627 inducing_nugget_.value * Eigen::VectorXd::Ones (K_uu.rows ());
608- return Eigen::SerializableLDLT (K_uu);
628+ const auto block_diag_K_uu = linalg::infer_block_diagonal_matrix (K_uu);
629+ return structured::ldlt (block_diag_K_uu);
609630 }
610631
611632 // This method takes care of a lot of the common book keeping required to
@@ -619,7 +640,7 @@ class SparseGaussianProcessRegression
619640 const std::vector<InducingFeatureType> &inducing_features,
620641 const std::vector<FeatureType> &out_of_order_features,
621642 const MarginalDistribution &out_of_order_targets,
622- const Eigen::SerializableLDLT &K_uu_ldlt, BlockDiagonalLDLT *A_ldlt,
643+ const BlockDiagonalLDLT &K_uu_ldlt, BlockDiagonalLDLT *A_ldlt,
623644 Eigen::MatrixXd *K_fu, Eigen::VectorXd *y) const {
624645
625646 ALBATROSS_ASSERT (A_ldlt != nullptr );
@@ -660,7 +681,8 @@ class SparseGaussianProcessRegression
660681 // Q_ff = K_fu K_uu^-1 K_uf
661682 // = K_fu K_uu^-T/2 K_uu^-1/2 K_uf
662683 // = P^T P
663- const Eigen::MatrixXd P = K_uu_ldlt.sqrt_solve (K_fu->transpose ());
684+ const Eigen::MatrixXd P =
685+ K_uu_ldlt.sqrt_solve (K_fu->transpose (), Base::threads_.get ());
664686
665687 // We only need the diagonal blocks of Q_ff to get A
666688 BlockDiagonal Q_ff_diag;
@@ -756,4 +778,4 @@ auto sparse_gp_from_covariance(CovFunc covariance_function,
756778
757779} // namespace albatross
758780
759- #endif /* INCLUDE_ALBATROSS_MODELS_SPARSE_GP_H_ */
781+ #endif // ALBATROSS_SRC_MODELS_SPARSE_GP_HPP
0 commit comments