tatami_r
R bindings to tatami matrices
Loading...
Searching...
No Matches
sparse_matrix.hpp
Go to the documentation of this file.
1#ifndef TATAMI_R_SPARSE_MATRIX_HPP
2#define TATAMI_R_SPARSE_MATRIX_HPP
3
4#include "utils.hpp"
5#include "tatami/tatami.hpp"
6#include <type_traits>
7
13namespace tatami_r {
14
34template<class Function_>
35void parse_SVT_SparseMatrix(Rcpp::RObject matrix, Function_ fun) {
36 Rcpp::RObject raw_svt = matrix.slot("SVT");
37 if (raw_svt == R_NilValue) {
38 return;
39 }
40
41 Rcpp::IntegerVector svt_version(matrix.slot(".svt_version"));
42 if (svt_version.size() != 1) {
43 auto ctype = get_class_name(matrix);
44 throw std::runtime_error("'.svt_version' slot of a " + ctype + " should be an integer scalar");
45 }
46 int version = svt_version[0];
47 int index_x = (version == 0 ? 0 : 1);
48 int value_x = (version == 0 ? 1 : 0);
49
50 Rcpp::List svt(raw_svt);
51 int NC = svt.size();
52
53 for (int c = 0; c < NC; ++c) {
54 Rcpp::RObject raw_inner(svt[c]);
55 if (raw_inner == R_NilValue) {
56 continue;
57 }
58
59 Rcpp::List inner(raw_inner);
60 if (inner.size() != 2) {
61 auto ctype = get_class_name(matrix);
62 throw std::runtime_error("each entry of the 'SVT' slot of a " + ctype + " object should be a list of length 2 or NULL");
63 }
64
65 // Verify type to ensure that we're not making a view on a temporary array.
66 Rcpp::RObject raw_indices = inner[index_x];
67 if (raw_indices.sexp_type() != INTSXP) {
68 auto ctype = get_class_name(matrix);
69 throw std::runtime_error("indices of each element of the 'SVT' slot in a " + ctype + " object should be an integer vector");
70 }
71 Rcpp::IntegerVector curindices(raw_indices);
72 auto nnz = curindices.size();
73
74 Rcpp::RObject raw_values(inner[value_x]);
75 auto vsexp = raw_values.sexp_type();
76 bool has_values = raw_values != R_NilValue;
77 Rcpp::IntegerVector curvalues_i;
78 Rcpp::NumericVector curvalues_n;
79 Rcpp::LogicalVector curvalues_l;
80
81 if (has_values) {
82 decltype(nnz) vsize;
83 switch (vsexp) {
84 case INTSXP:
85 curvalues_i = Rcpp::IntegerVector(raw_values);
86 vsize = curvalues_i.size();
87 break;
88 case REALSXP:
89 curvalues_n = Rcpp::NumericVector(raw_values);
90 vsize = curvalues_n.size();
91 break;
92 case LGLSXP:
93 curvalues_l = Rcpp::LogicalVector(raw_values);
94 vsize = curvalues_l.size();
95 break;
96 default:
97 {
98 auto ctype = get_class_name(matrix);
99 throw std::runtime_error("value vector of an element of the 'SVT' slot in a " + ctype + " object is not a numeric or logical type");
100 }
101 }
102
103 if (nnz != vsize) {
104 auto ctype = get_class_name(matrix);
105 throw std::runtime_error("both vectors of an element of the 'SVT' slot in a " + ctype + " object should have the same length");
106 }
107 }
108
109 switch (vsexp) {
110 case INTSXP:
111 fun(c, curindices, !has_values, curvalues_i);
112 break;
113 case REALSXP:
114 fun(c, curindices, !has_values, curvalues_n);
115 break;
116 default:
117 fun(c, curindices, !has_values, curvalues_l);
118 break;
119 }
120 }
121}
122
126template<typename CachedValue_, typename CachedIndex_, typename Index_>
127void parse_sparse_matrix(
128 Rcpp::RObject matrix,
129 bool row,
130 std::vector<CachedValue_*>& value_ptrs,
131 std::vector<CachedIndex_*>& index_ptrs,
132 Index_* counts)
133{
134 auto ctype = get_class_name(matrix);
135 if (ctype != "SVT_SparseMatrix") {
136 // Can't be bothered to write a parser for COO_SparseMatrix objects,
137 // which are soon-to-be-superceded by SVT_SparseMatrix anyway; so we
138 // just forcibly coerce it.
139 auto methods_env = Rcpp::Environment::namespace_env("methods");
140 Rcpp::Function converter(methods_env["as"]);
141 matrix = converter(matrix, Rcpp::CharacterVector::create("SVT_SparseMatrix"));
142 }
143
144 bool needs_value = !value_ptrs.empty();
145 bool needs_index = !index_ptrs.empty();
146
147 parse_SVT_SparseMatrix(matrix, [&](int c, const auto& curindices, bool all_ones, const auto& curvalues) {
148 size_t nnz = curindices.size();
149
150 // Note that non-empty value_ptrs and index_ptrs may be longer than the
151 // number of rows/columns in the SVT matrix, due to the reuse of slabs.
152 if (row) {
153 if (needs_value) {
154 if (all_ones) {
155 for (size_t i = 0; i < nnz; ++i) {
156 auto ix = curindices[i];
157 value_ptrs[ix][counts[ix]] = 1;
158 }
159 } else {
160 for (size_t i = 0; i < nnz; ++i) {
161 auto ix = curindices[i];
162 value_ptrs[ix][counts[ix]] = curvalues[i];
163 }
164 }
165 }
166 if (needs_index) {
167 for (size_t i = 0; i < nnz; ++i) {
168 auto ix = curindices[i];
169 index_ptrs[ix][counts[ix]] = c;
170 }
171 }
172 for (size_t i = 0; i < nnz; ++i) {
173 ++(counts[curindices[i]]);
174 }
175
176 } else {
177 if (needs_value) {
178 if (all_ones) {
179 std::fill_n(value_ptrs[c], nnz, 1);
180 } else {
181 std::copy(curvalues.begin(), curvalues.end(), value_ptrs[c]);
182 }
183 }
184 if (needs_index) {
185 std::copy(curindices.begin(), curindices.end(), index_ptrs[c]);
186 }
187 counts[c] = nnz;
188 }
189 });
190}
195}
196
197#endif
tatami bindings for arbitrary R matrices.
void parse_SVT_SparseMatrix(Rcpp::RObject matrix, Function_ fun)
Definition sparse_matrix.hpp:35