1#ifndef SCRAN_PCA_SIMPLE_PCA_HPP
2#define SCRAN_PCA_SIMPLE_PCA_HPP
11#include "tatami_stats/tatami_stats.hpp"
12#include "quickstats/quickstats.hpp"
15#include "irlba_tatami/irlba_tatami.hpp"
17#include "sanisizer/sanisizer.hpp"
33template<
typename EigenVector_ = Eigen::VectorXd>
89template<
typename Value_,
typename Index_,
class EigenVector_>
90void compute_row_means_and_variances(
const tatami::Matrix<Value_, Index_>& mat,
const int num_threads, EigenVector_& center_v, EigenVector_& scale_v) {
91 tatami_stats::RssOptions<typename EigenVector_::Scalar> opts;
92 opts.num_threads = num_threads;
93 opts.mean_placeholder = 0;
95 tatami_stats::RssBuffers<typename EigenVector_::Scalar> buffers;
96 buffers.mean = center_v.data();
97 buffers.rss = scale_v.data();
98 tatami_stats::rss(
true, mat, buffers, opts);
100 const auto ncells = mat.
ncol();
102 scale_v /= ncells - 1;
106template<
class EigenVector_,
class EigenMatrix_>
107std::unique_ptr<irlba::Matrix<EigenVector_, EigenMatrix_> > prepare_deferred_matrix_for_irlba(
109 const SimplePcaOptions<EigenVector_>& options,
110 const EigenVector_& center_v,
111 const EigenVector_& scale_v
113 std::unique_ptr<irlba::Matrix<EigenVector_, EigenMatrix_> > alt;
114 alt.reset(
new irlba::CenteredMatrix<EigenVector_, EigenMatrix_, I<
decltype(ptr)>, I<
decltype(¢er_v)> >(std::move(ptr), ¢er_v));
118 alt.reset(
new irlba::ScaledMatrix<EigenVector_, EigenMatrix_, I<
decltype(ptr)>, I<
decltype(&scale_v)> >(std::move(ptr), &scale_v,
true,
true));
125template<
class EigenMatrix_,
typename Value_,
typename Index_,
class EigenVector_>
126std::unique_ptr<irlba::Matrix<EigenVector_, EigenMatrix_> > prepare_sparse_matrix_for_irlba(
128 const SimplePcaOptions<EigenVector_>& options,
129 EigenVector_& center_v,
130 EigenVector_& scale_v,
131 typename EigenVector_::Scalar& total_var
133 const auto ngenes = mat.
nrow();
134 sanisizer::resize(center_v, ngenes);
135 sanisizer::resize(scale_v, ngenes);
136 std::unique_ptr<irlba::Matrix<EigenVector_, EigenMatrix_> > output;
138 if (options.realize_matrix) {
152 const Index_ ncells = mat.
ncol();
156 I<
decltype(extracted.value)>,
157 I<
decltype(extracted.index)>,
158 I<
decltype(extracted.pointers)>
162 std::move(extracted.value),
163 std::move(extracted.index),
164 std::move(extracted.pointers),
168 output.reset(sparse_ptr);
171 const auto& pointers = sparse_ptr->get_pointers();
172 const auto& values = sparse_ptr->get_values();
173 quickstats::RssWorkspace<typename EigenVector_::Scalar> work;
175 for (Index_ g = start, end = start + length; g < end; ++g) {
176 const auto offset = pointers[g];
177 const auto next_offset = pointers[g + 1];
178 const Index_ num_nonzero = next_offset - offset;
179 const auto results = quickstats::rss(ncells, num_nonzero, values.data() + offset, work);
180 center_v.coeffRef(g) = results.mean;
181 scale_v.coeffRef(g) = results.rss;
183 }, ngenes, options.num_threads);
187 scale_v /= ncells - 1;
188 }
else if (!ncells) {
190 std::fill(center_v.begin(), center_v.end(), 0);
193 total_var = process_scale_vector(options.scale, scale_v);
196 compute_row_means_and_variances(mat, options.num_threads, center_v, scale_v);
197 total_var = process_scale_vector(options.scale, scale_v);
199 new irlba_tatami::Transposed<EigenVector_, EigenMatrix_, Value_, Index_,
decltype(&mat)>(&mat, options.num_threads)
203 return prepare_deferred_matrix_for_irlba(std::move(output), options, center_v, scale_v);
206template<
class EigenMatrix_,
typename Value_,
typename Index_,
class EigenVector_>
207std::unique_ptr<irlba::Matrix<EigenVector_, EigenMatrix_> > prepare_dense_matrix_for_irlba(
209 const SimplePcaOptions<EigenVector_>& options,
210 EigenVector_& center_v,
211 EigenVector_& scale_v,
212 typename EigenVector_::Scalar& total_var
214 const Index_ ngenes = mat.
nrow();
215 sanisizer::resize(center_v, ngenes);
216 sanisizer::resize(scale_v, ngenes);
218 if (options.realize_matrix) {
220 const Index_ ncells = mat.
ncol();
221 auto emat = std::make_unique<EigenMatrix_>(
222 sanisizer::cast<I<
decltype(std::declval<EigenMatrix_>().rows())> >(ncells),
223 sanisizer::cast<I<
decltype(std::declval<EigenMatrix_>().cols())> >(ngenes)
228 static_assert(!EigenMatrix_::IsRowMajor);
234 tatami::ConvertToDenseOptions opt;
235 opt.num_threads = options.num_threads;
240 center_v.array() = emat->array().colwise().sum();
244 emat->array().rowwise() -= center_v.adjoint().array();
246 scale_v.array() = emat->array().colwise().squaredNorm();
248 scale_v /= ncells - 1;
251 total_var = process_scale_vector(options.scale, scale_v);
253 emat->array().rowwise() /= scale_v.adjoint().array();
256 return std::unique_ptr<irlba::Matrix<EigenVector_, EigenMatrix_> >(
261 compute_row_means_and_variances(mat, options.num_threads, center_v, scale_v);
262 total_var = process_scale_vector(options.scale, scale_v);
263 std::unique_ptr<irlba::Matrix<EigenVector_, EigenMatrix_> > output(
264 new irlba_tatami::Transposed<EigenVector_, EigenMatrix_, Value_, Index_,
decltype(&mat)>(&mat, options.num_threads)
266 return prepare_deferred_matrix_for_irlba(std::move(output), options, center_v, scale_v);
278template<
typename EigenMatrix_,
typename EigenVector_>
335template<
typename Value_,
typename Index_,
typename EigenMatrix_,
class EigenVector_,
class SubsetFunction_>
336void simple_pca_internal(
340 SubsetFunction_ subset_fun
345 std::unique_ptr<irlba::Matrix<EigenVector_, EigenMatrix_> > ptr;
347 ptr = prepare_sparse_matrix_for_irlba<EigenMatrix_>(mat, options, output.
center, scale, output.
total_variance);
349 ptr = prepare_dense_matrix_for_irlba<EigenMatrix_>(mat, options, output.
center, scale, output.
total_variance);
362 output.
scale = std::move(scale);
392template<
typename Value_,
typename Index_,
typename EigenMatrix_,
class EigenVector_>
398 [](
const EigenMatrix_&,
const EigenVector_&) ->
void {}
417template<
typename EigenMatrix_ = Eigen::MatrixXd,
class EigenVector_ = Eigen::VectorXd,
typename Value_,
typename Index_>
virtual Index_ ncol() const=0
virtual Index_ nrow() const=0
virtual std::unique_ptr< MyopicSparseExtractor< Value_, Index_ > > sparse(bool row, const Options &opt) const=0
Metrics compute(const Matrix_ &matrix, const Eigen::Index number, EigenMatrix_ &outU, EigenMatrix_ &outV, EigenVector_ &outD, const Options< EigenVector_ > &options)
Principal component analysis on single-cell data.
void simple_pca(const tatami::Matrix< Value_, Index_ > &mat, const SimplePcaOptions< EigenVector_ > &options, SimplePcaResults< EigenMatrix_, EigenVector_ > &output)
Definition simple_pca.hpp:393
CompressedSparseContents< StoredValue_, StoredIndex_, StoredPointer_ > retrieve_compressed_sparse_contents(const Matrix< InputValue_, InputIndex_ > &matrix, const bool row, const RetrieveCompressedSparseContentsOptions &options)
int parallelize(Function_ fun, const Index_ tasks, const int workers)
void convert_to_dense(const Matrix< InputValue_, InputIndex_ > &matrix, const bool row_major, StoredValue_ *const store, const ConvertToDenseOptions &options)
Container_ create_container_of_Index_size(const Index_ x, Args_ &&... args)
Options for simple_pca().
Definition simple_pca.hpp:34
bool scale
Definition simple_pca.hpp:58
int number
Definition simple_pca.hpp:51
bool realize_matrix
Definition simple_pca.hpp:70
int num_threads
Definition simple_pca.hpp:78
bool transpose
Definition simple_pca.hpp:64
irlba::Options< EigenVector_ > irlba_options
Definition simple_pca.hpp:83
Results of simple_pca().
Definition simple_pca.hpp:279
EigenMatrix_ components
Definition simple_pca.hpp:288
std::optional< EigenVector_ > scale
Definition simple_pca.hpp:324
EigenMatrix_ rotation
Definition simple_pca.hpp:308
EigenVector_ center
Definition simple_pca.hpp:315
EigenVector_ variance_explained
Definition simple_pca.hpp:295
EigenVector_::Scalar total_variance
Definition simple_pca.hpp:301
irlba::Metrics metrics
Definition simple_pca.hpp:329