55 static constexpr int rank = 10;
60 static constexpr bool scale =
false;
182 block_weight_policy = w;
193 variable_block_weight_parameters = v;
207 template<
bool weight_,
typename Data_,
typename Index_,
typename Block_>
209 const tatami::Matrix<Data_, Index_>* mat,
211 const pca_utils::BlockingDetails<weight_>& block_details,
212 const irlba::Irlba& irb,
213 Eigen::MatrixXd& pcs,
214 Eigen::MatrixXd& rotation,
215 Eigen::VectorXd& variance_explained,
216 Eigen::MatrixXd& center_m,
217 Eigen::VectorXd& scale_v,
220 auto ngenes = mat->nrow(), ncells = mat->ncol();
221 auto extracted = pca_utils::extract_sparse_for_pca(mat, nthreads);
222 pca_utils::SparseMatrix emat(ncells, ngenes, std::move(extracted.values), std::move(extracted.indices), std::move(extracted.ptrs), nthreads);
224 auto nblocks = block_details.num_blocks();
225 center_m.resize(nblocks, ngenes);
226 scale_v.resize(ngenes);
227 pca_utils::compute_mean_and_variance_regress<weight_>(emat, block, block_details, center_m, scale_v, nthreads);
228 total_var = pca_utils::process_scale_vector(scale, scale_v);
230 pca_utils::RegressWrapper<
decltype(emat), Block_> centered(&emat, block, ¢er_m);
231 if constexpr(weight_) {
233 irlba::Scaled<
decltype(centered)> scaled(¢ered, &scale_v);
234 pca_utils::SampleScaledWrapper<
decltype(scaled)> weighted(&scaled, &(block_details.expanded_weights));
235 irb.run(weighted, pcs, rotation, variance_explained);
237 pca_utils::SampleScaledWrapper<
decltype(centered)> weighted(¢ered, &(block_details.expanded_weights));
238 irb.run(weighted, pcs, rotation, variance_explained);
242 pca_utils::project_sparse_matrix(emat, pcs, rotation, scale, scale_v, nthreads);
245 Eigen::MatrixXd centering;
247 centering = (center_m * (rotation.array().colwise() / scale_v.array()).matrix()).adjoint();
249 centering = (center_m * rotation).adjoint();
251 for (
size_t i = 0, iend = pcs.cols(); i < iend; ++i) {
252 pcs.col(i) -= centering.col(block[i]);
255 pca_utils::clean_up_projected<true>(pcs, variance_explained);
257 pcs.adjointInPlace();
262 irlba::Scaled<
decltype(centered)> scaled(¢ered, &scale_v);
263 irb.run(scaled, pcs, rotation, variance_explained);
265 irb.run(centered, pcs, rotation, variance_explained);
268 pca_utils::clean_up(mat->ncol(), pcs, variance_explained);
270 pcs.adjointInPlace();
275 template<
bool weight_,
typename Data_,
typename Index_,
typename Block_>
277 const tatami::Matrix<Data_, Index_>* mat,
279 const pca_utils::BlockingDetails<weight_>& block_details,
280 const irlba::Irlba& irb,
281 Eigen::MatrixXd& pcs,
282 Eigen::MatrixXd& rotation,
283 Eigen::VectorXd& variance_explained,
284 Eigen::MatrixXd& center_m,
285 Eigen::VectorXd& scale_v,
288 auto emat = pca_utils::extract_dense_for_pca(mat, nthreads);
290 auto ngenes = emat.cols();
291 auto nblocks = block_details.num_blocks();
292 center_m.resize(nblocks, ngenes);
293 scale_v.resize(ngenes);
294 pca_utils::compute_mean_and_variance_regress<weight_>(emat, block, block_details, center_m, scale_v, nthreads);
295 total_var = pca_utils::process_scale_vector(scale, scale_v);
298 tatami::parallelize([&](
size_t,
size_t start,
size_t length) ->
void {
299 size_t ncells = emat.rows();
300 double* ptr = emat.data() +
static_cast<size_t>(start) * ncells;
301 for (
size_t g = start, end = start + length; g < end; ++g, ptr += ncells) {
302 for (
size_t c = 0; c < ncells; ++c) {
303 ptr[c] -= center_m.coeff(block[c], g);
307 auto sd = scale_v[g];
308 for (
size_t c = 0; c < ncells; ++c) {
313 }, ngenes, nthreads);
315 if constexpr(weight_) {
316 pca_utils::SampleScaledWrapper<
decltype(emat)> weighted(&emat, &(block_details.expanded_weights));
317 irb.run(weighted, pcs, rotation, variance_explained);
318 pcs.noalias() = emat * rotation;
319 pca_utils::clean_up_projected<false>(pcs, variance_explained);
321 irb.run(emat, pcs, rotation, variance_explained);
322 pca_utils::clean_up(pcs.rows(), pcs, variance_explained);
326 pcs.adjointInPlace();
330 template<
typename Data_,
typename Index_,
typename Block_>
332 const tatami::Matrix<Data_, Index_>* mat,
334 Eigen::MatrixXd& pcs,
335 Eigen::MatrixXd& rotation,
336 Eigen::VectorXd& variance_explained,
337 Eigen::MatrixXd& center_m,
338 Eigen::VectorXd& scale_v,
341 irlba::EigenThreadScope t(nthreads);
343 irb.set_number(rank);
344 irb.set_cap_number(
true);
346 if (block_weight_policy == WeightPolicy::NONE) {
347 auto bdetails = pca_utils::compute_blocking_details(mat->ncol(), block);
349 run_sparse<false>(mat, block, bdetails, irb, pcs, rotation, variance_explained, center_m, scale_v, total_var);
351 run_dense<false>(mat, block, bdetails, irb, pcs, rotation, variance_explained, center_m, scale_v, total_var);
355 auto bdetails = pca_utils::compute_blocking_details(mat->ncol(), block, block_weight_policy, variable_block_weight_parameters);
357 run_sparse<true>(mat, block, bdetails, irb, pcs, rotation, variance_explained, center_m, scale_v, total_var);
359 run_dense<true>(mat, block, bdetails, irb, pcs, rotation, variance_explained, center_m, scale_v, total_var);
429 template<
typename Data_,
typename Index_,
typename Block_>
430 Results run(
const tatami::Matrix<Data_, Index_>* mat,
const Block_* block)
const {
432 Eigen::MatrixXd rotation, center;
433 Eigen::VectorXd scale;
438 if (return_rotation) {
439 output.
rotation = std::move(rotation);
442 output.
center = center.adjoint();
445 output.
scale = std::move(scale);
470 template<
typename Data_,
typename Index_,
typename Block_,
typename Subset_>
471 Results run(
const tatami::Matrix<Data_, Index_>* mat,
const Block_* block,
const Subset_* features)
const {
473 return run(mat, block);
475 auto subsetted = pca_utils::subset_matrix_by_features(mat, features);
476 return run(subsetted.get(), block);