Browse code

Added tatami and byteme for other packages.

LTLA authored on 26/05/2022 22:17:09
Showing1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,553 @@
1
+#ifndef TATAMI_MATRIX_H
2
+#define TATAMI_MATRIX_H
3
+
4
+#include "SparseRange.hpp"
5
+#include "Workspace.hpp"
6
+
7
+/**
8
+ * @file Matrix.hpp
9
+ *
10
+ * Virtual class for a matrix with a defined type.
11
+ */
12
+
13
+namespace tatami {
14
+
15
+/**
16
+ * @brief Virtual class for a matrix with a defined type.
17
+ * 
18
+ * @tparam T Type of the matrix data.
19
+ * @tparam IDX Type of the row/column indices.
20
+ */
21
+template <typename T, typename IDX = int>
22
+class Matrix {
23
+public:
24
+    virtual ~Matrix() = default;
25
+
26
+    // Defining the other constructors for rule of 5. The move constructors
27
+    // don't get auto-made when a destructor is declared, and if I'm defining
28
+    // them, I might as well define the copy constructors.  Technically I
29
+    // suppose I don't need them because this class is just an interface, but
30
+    // who knows if I'll add some move-able stuff here later.
31
+
32
+    /**
33
+     * Default move constructor.
34
+     */
35
+    Matrix(Matrix&&) = default;
36
+
37
+    /**
38
+     * Default move assignment operator.
39
+     */
40
+    Matrix& operator=(Matrix&&) = default;
41
+
42
+    /**
43
+     * Default copy constructor.
44
+     */
45
+    Matrix(const Matrix&) = default;
46
+
47
+    /**
48
+     * Default copy assignment operator.
49
+     */
50
+    Matrix& operator=(const Matrix&) = default;
51
+
52
+protected:
53
+    Matrix() = default;
54
+
55
+public:
56
+    /** 
57
+     * Type of data to be returned by getters.
58
+     */
59
+    typedef T data_type;
60
+
61
+    /** 
62
+     * Type of index to be returned by the sparse getters.
63
+     */
64
+    typedef IDX index_type;
65
+public:
66
+    /**
67
+     * @return Number of rows.
68
+     */
69
+    virtual size_t nrow() const = 0;
70
+
71
+    /**
72
+     * @return Number of columns.
73
+     */
74
+    virtual size_t ncol() const = 0;
75
+
76
+    /**
77
+     * @param row Should a workspace for row extraction be returned?
78
+     *
79
+     * @return A shared pointer to a `Workspace` for row or column extraction, or a null pointer if no workspace is required.
80
+     * Defaults to returning a null pointer if no specialized method is provided in derived classes.
81
+     */
82
+    virtual std::shared_ptr<Workspace> new_workspace(bool row) const { return nullptr; }
83
+
84
+    /**
85
+     * @return Is this matrix sparse?
86
+     * Defaults to `false` if no specialized method is provided in derived classes.
87
+     */
88
+    virtual bool sparse() const { return false; }
89
+
90
+    /**
91
+     * @return The preferred dimension for extracting values.
92
+     * If `true`, row-wise extraction is preferred; if `false`, column-wise extraction is preferred.
93
+     * Defaults to `false` if no specialized method is provided in derived classes.
94
+     */
95
+    virtual bool prefer_rows() const { return false; }
96
+
97
+    /**
98
+     * @return A `pair` containing the number of matrix elements that prefer row-level access (`first`) or column-level access (`second`).
99
+     *
100
+     * This method is useful for determining the return value of `prefer_rows()` in combined matrices consisting of both row- and column-preferred submatrices.
101
+     * In such cases, the net preference can be determined based on the combined size of the submatrices for each preference.
102
+     *
103
+     * For simpler matrices, the return value contains the total size of the matrix in one of the `double`s and zero in the other.
104
+     */
105
+    virtual std::pair<double, double> dimension_preference () const {
106
+        double size = static_cast<double>(nrow()) * static_cast<double>(ncol());
107
+        if (prefer_rows()) {
108
+            return std::make_pair(size, 0.0);
109
+        } else {
110
+            return std::make_pair(0.0, size);
111
+        }
112
+    }
113
+
114
+public:
115
+    /**
116
+     * `buffer` may not necessarily be filled upon extraction if a pointer can be returned to the underlying data store.
117
+     * This can be checked by comparing the returned pointer to `buffer`; if they are the same, `buffer` has been filled.
118
+     *
119
+     * If `work` is not a null pointer, it should have been generated by `new_workspace()` with `row = true`.
120
+     * This is optional and should only affect the efficiency of extraction, not the contents.
121
+     *
122
+     * @param r Index of the row.
123
+     * @param buffer Pointer to an array with enough space for at least `last - first` values.
124
+     * @param first First column to extract for row `r`.
125
+     * @param last One past the last column to extract in `r`.
126
+     * @param work Pointer to a workspace.
127
+     *
128
+     * @return Pointer to the values of row `r`, starting from the value in the `first` column and containing `last - first` valid entries.
129
+     */
130
+    virtual const T* row(size_t r, T* buffer, size_t first, size_t last, Workspace* work=nullptr) const = 0;
131
+
132
+    /**
133
+     * `buffer` may not necessarily be filled upon extraction if a pointer can be returned to the underlying data store.
134
+     * This can be checked by comparing the returned pointer to `buffer`; if they are the same, `buffer` has been filled.
135
+     *
136
+     * If `work` is not a null pointer, it should have been generated by `new_workspace()` with `row = false`.
137
+     * This is optional and should only affect the efficiency of extraction, not the contents.
138
+     *
139
+     * @param c Index of the column.
140
+     * @param buffer Pointer to an array with enough space for at least `last - first` values.
141
+     * @param first First row to extract for column `c`.
142
+     * @param last One past the last row to extract in `c`.
143
+     * @param work Pointer to a workspace.
144
+     *
145
+     * @return Pointer to the values of column `c`, starting from the value in the `first` row and containing `last - first` valid entries.
146
+     */
147
+    virtual const T* column(size_t c, T* buffer, size_t first, size_t last, Workspace* work=nullptr) const = 0;
148
+
149
+    /**
150
+     * @param r Index of the row.
151
+     * @param buffer Pointer to an array with enough space for at least `ncol()` values.
152
+     * @param work Pointer to a workspace, see `row()` for details.
153
+     *
154
+     * @return Pointer to the values of row `r`.
155
+     */
156
+    const T* row(size_t r, T* buffer, Workspace* work=nullptr) const {
157
+        return row(r, buffer, 0, this->ncol(), work);
158
+    }
159
+
160
+    /**
161
+     * @param c Index of the column.
162
+     * @param buffer Pointer to an array with enough space for at least `nrow()` values.
163
+     * @param work Pointer to a workspace, see `column()` for details.
164
+     *
165
+     * @return Pointer to the values of column `c`.
166
+     */
167
+    const T* column(size_t c, T* buffer, Workspace* work=nullptr) const {
168
+        return column(c, buffer, 0, this->nrow(), work);
169
+    }
170
+
171
+public:
172
+    /**
173
+     * @param r Index of the row.
174
+     * @param buffer Pointer to an array with enough space for at least `last - first` values.
175
+     * @param first First column to extract for row `r`.
176
+     * @param last One past the last column to extract in `r`.
177
+     * @param work Pointer to a workspace, see `row()` for details.
178
+     *
179
+     * @return The array at `buffer` is filled with the values of row `r`, starting from the value in the `first` column and containing `last - first` valid entries.
180
+     * `buffer` itself is returned.
181
+     */
182
+    const T* row_copy(size_t r, T* buffer, size_t first, size_t last, Workspace* work=nullptr) const {
183
+        auto ptr = row(r, buffer, first, last, work);
184
+        copy_over(ptr, buffer, last - first);
185
+        return buffer;
186
+    }
187
+
188
+    /**
189
+     * @param c Index of the column.
190
+     * @param buffer Pointer to an array with enough space for at least `last - first` values.
191
+     * @param first First row to extract for column `c`.
192
+     * @param last One past the last row to extract in `c`.
193
+     * @param work Pointer to a workspace, see `column()` for details.
194
+     *
195
+     * @return The array at `buffer` is filled with the values of column `c`, starting from the value in the `first` row and containing `last - first` valid entries.
196
+     * `buffer` itself is returned.
197
+     */
198
+    const T* column_copy(size_t c, T* buffer, size_t first, size_t last, Workspace* work=nullptr) const {
199
+        auto ptr = column(c, buffer, first, last, work);
200
+        copy_over(ptr, buffer, last - first);
201
+        return buffer;
202
+    }
203
+
204
+    /**
205
+     * @param r Index of the row.
206
+     * @param buffer Pointer to an array with enough space for at least `ncol()` values.
207
+     * @param work Pointer to a workspace, see `row()` for details.
208
+     *
209
+     * @return The array at `buffer` is filled with all values of row `r`.
210
+     * `buffer` itself is returned.
211
+     */
212
+    const T* row_copy(size_t r, T* buffer, Workspace* work=nullptr) const {
213
+        return row_copy(r, buffer, 0, this->ncol(), work);
214
+    }
215
+
216
+    /**
217
+     * @param c Index of the column.
218
+     * @param buffer Pointer to an array with enough space for at least `nrow()` values.
219
+     * @param work Pointer to a workspace, see `column()` for details.
220
+     *
221
+     * @return The array at `buffer` is filled with all values of column `c`.
222
+     * `buffer` itself is returned.
223
+     */
224
+    const T* column_copy(size_t c, T* buffer, Workspace* work=nullptr) const {
225
+        return column_copy(c, buffer, 0, this->nrow(), work);
226
+    }
227
+
228
+private:
229
+    template<typename X>
230
+    static void copy_over(const X* src, X* dest, size_t n) {
231
+        if (src!=dest) {
232
+            std::copy(src, src + n, dest);
233
+        }
234
+        return;
235
+    }
236
+
237
+public:
238
+    /**
239
+     * A more convenient but (slightly) less efficient version of the `row()` method.
240
+     * Callers do not have to supply `buffer`; instead a new allocation is performed every time.
241
+     *
242
+     * @param r Index of the row.
243
+     * @param first First column to extract for row `r`.
244
+     * @param last One past the last column to extract in `r`.
245
+     * @param work Pointer to a workspace, see `row()` for details.
246
+     *
247
+     * @return A vector containing the values of row `r`, starting from the value in the `first` column and containing `last - first` valid entries.
248
+     */
249
+    std::vector<T> row(size_t r, size_t first, size_t last, Workspace* work=nullptr) const {
250
+        std::vector<T> output(last - first);
251
+        auto ptr = row_copy(r, output.data(), first, last, work);
252
+        return output;
253
+    }
254
+
255
+    /**
256
+     * A more convenient but (slightly) less efficient version of the `column()` method.
257
+     * Callers do not have to supply `buffer`; instead a new allocation is performed every time.
258
+     *
259
+     * @param c Index of the column.
260
+     * @param first First row to extract for column `c`.
261
+     * @param last One past the last row to extract in `c`.
262
+     * @param work Pointer to a workspace, see `column()` for details.
263
+     *
264
+     * @return A vector containing the values of column `c`, starting from the value in the `first` row and containing `last - first` valid entries.
265
+     */
266
+    std::vector<T> column(size_t c, size_t first, size_t last, Workspace* work=nullptr) const {
267
+        std::vector<T> output(last - first);
268
+        auto ptr = column_copy(c, output.data(), first, last, work);
269
+        return output;
270
+    }
271
+
272
+    /**
273
+     * @param r Index of the row.
274
+     * @param work Pointer to a workspace, see `row()` for details.
275
+     *
276
+     * @return A vector containing all values of row `r`.
277
+     */
278
+    std::vector<T> row(size_t r, Workspace* work=nullptr) const {
279
+        return row(r, 0, this->ncol(), work);
280
+    }
281
+
282
+    /**
283
+     * @param c Index of the column.
284
+     * @param work Pointer to a workspace, see `column()` for details.
285
+     *
286
+     * @return A vector containing all values of column `c`.
287
+     */
288
+    std::vector<T> column(size_t c, Workspace* work=nullptr) const {
289
+        return column(c, 0, this->nrow(), work);
290
+    }
291
+
292
+public:
293
+    /**
294
+     * `vbuffer` may not necessarily be filled upon extraction if a pointer can be returned to the underlying data store.
295
+     * This be checked by comparing the returned `SparseRange::value` pointer to `vbuffer`; if they are the same, `vbuffer` has been filled. 
296
+     * The same applies for `ibuffer` and the returned `SparseRange::index` pointer.
297
+     *
298
+     * Values in `vbuffer` are not guaranteed to be non-zero.
299
+     * If zeroes are explicitly initialized in the underlying representation, they will be reported here.
300
+     * However, one can safely assume that all values _not_ in `vbuffer` are zero.
301
+     *
302
+     * If `work` is not a null pointer, it should have been generated by `new_workspace()` with `row = false`.
303
+     * This is optional and should only affect the efficiency of extraction, not the contents.
304
+     *
305
+     * Setting `sorted = false` can reduce computational work in situations where the order of non-zero elements does not matter.
306
+     *
307
+     * @param r Index of the row.
308
+     * @param vbuffer Pointer to an array with enough space for at least `last - first` values.
309
+     * @param ibuffer Pointer to an array with enough space for at least `last - first` indices.
310
+     * @param first First column to extract for row `r`.
311
+     * @param last One past the last column to extract in `r`.
312
+     * @param work Pointer to a workspace.
313
+     * @param sorted Should the non-zero elements be sorted by their indices?
314
+     *
315
+     * @return A `SparseRange` object containing the number of non-zero elements in `r` from column `first` up to `last`.
316
+     * This also contains pointers to arrays containing their column indices and values.
317
+     */
318
+    virtual SparseRange<T, IDX> sparse_row(size_t r, T* vbuffer, IDX* ibuffer, size_t first, size_t last, Workspace* work=nullptr, bool sorted=true) const {
319
+        const T* val = row(r, vbuffer, first, last, work);
320
+        for (size_t i = first; i < last; ++i) {
321
+            ibuffer[i - first] = i;
322
+        }
323
+        return SparseRange(last - first, val, ibuffer); 
324
+    }
325
+
326
+    /**
327
+     * `vbuffer` may not necessarily be filled upon extraction if a pointer can be returned to the underlying data store.
328
+     * This be checked by comparing the returned `SparseRange::value` pointer to `vbuffer`; if they are the same, `vbuffer` has been filled. 
329
+     * The same applies for `ibuffer` and the returned `SparseRange::index` pointer.
330
+     *
331
+     * Values in `vbuffer` are not guaranteed to be non-zero.
332
+     * If zeroes are explicitly initialized in the underlying representation, they will be reported here.
333
+     * However, one can safely assume that all values _not_ in `vbuffer` are zero.
334
+     *
335
+     * If `work` is not a null pointer, it should have been generated by `new_workspace()` with `row = true`.
336
+     * This is optional and should only affect the efficiency of extraction, not the contents.
337
+     *
338
+     * Setting `sorted = false` can reduce computational work in situations where the order of non-zero elements does not matter.
339
+     *
340
+     * @param c Index of the column.
341
+     * @param vbuffer Pointer to an array with enough space for at least `last - first` values.
342
+     * @param ibuffer Pointer to an array with enough space for at least `last - first` indices.
343
+     * @param first First row to extract for column `c`.
344
+     * @param last One past the last row to extract in `c`.
345
+     * @param work Pointer to a workspace.
346
+     * @param sorted Should the non-zero elements be sorted by their indices?
347
+     *
348
+     * @return A `SparseRange` object containing the number of non-zero elements in `c` from column `first` up to `last`.
349
+     * This also contains pointers to arrays containing their row indices and values.
350
+     */
351
+    virtual SparseRange<T, IDX> sparse_column(size_t c, T* vbuffer, IDX* ibuffer, size_t first, size_t last, Workspace* work=nullptr, bool sorted=true) const {
352
+        const T* val = column(c, vbuffer, first, last, work);
353
+        for (size_t i = first; i < last; ++i) {
354
+            ibuffer[i - first] = i;
355
+        }
356
+        return SparseRange(last - first, val, ibuffer); 
357
+    }
358
+
359
+    /**
360
+     * @param r Index of the row.
361
+     * @param vbuffer Pointer to an array with enough space for at least `ncol()` values.
362
+     * @param ibuffer Pointer to an array with enough space for at least `ncol()` indices.
363
+     * @param work Pointer to a workspace, see comments in `sparse_row()`.
364
+     * @param sorted Should the non-zero elements be sorted by their indices?
365
+     *
366
+     * @return A `SparseRange` object containing the number of non-zero elements in `r`.
367
+     * This also contains pointers to arrays containing their column indices and values.
368
+     */
369
+    SparseRange<T, IDX> sparse_row(size_t r, T* vbuffer, IDX* ibuffer, Workspace* work=nullptr, bool sorted=true) const {
370
+        return sparse_row(r, vbuffer, ibuffer, 0, this->ncol(), work, sorted);
371
+    }
372
+
373
+    /**
374
+     * @param c Index of the column.
375
+     * @param vbuffer Pointer to an array with enough space for at least `nrow()` values.
376
+     * @param ibuffer Pointer to an array with enough space for at least `nrow()` indices.
377
+     * @param work Pointer to a workspace, see comments in `sparse_column()`.
378
+     * @param sorted Should the non-zero elements be sorted by their indices?
379
+     *
380
+     * @return A `SparseRange` object containing the number of non-zero elements in `c`.
381
+     * This also contains pointers to arrays containing their row indices and values.
382
+     */
383
+    SparseRange<T, IDX> sparse_column(size_t c, T* vbuffer, IDX* ibuffer, Workspace* work=nullptr, bool sorted=true) const {
384
+        return sparse_column(c, vbuffer, ibuffer, 0, this->nrow(), work, sorted);
385
+    }
386
+
387
+public:
388
+    /**
389
+     * @param r Index of the row.
390
+     * @param vbuffer Pointer to an array with enough space for at least `last - first` values.
391
+     * @param ibuffer Pointer to an array with enough space for at least `last - first` indices.
392
+     * @param first First column to extract for row `r`.
393
+     * @param last One past the last column to extract in `r`.
394
+     * @param copy Whether the non-zero values and/or indices should be copied into `vbuffer` and `ibuffer`, respectively.
395
+     * @param work Pointer to a workspace, see comments in `sparse_row()`.
396
+     * @param sorted Should the non-zero elements be sorted by their indices? See `sparse_row()` for details.
397
+     *
398
+     * @return A `SparseRange` object containing the number of non-zero elements in `r` from column `first` up to `last`.
399
+     * This also contains pointers to arrays containing their column indices and values.
400
+     * Depending on `copy`, values and incides will be copied into `vbuffer` and/or `ibuffer`.
401
+     */
402
+    SparseRange<T, IDX> sparse_row_copy(size_t r, T* vbuffer, IDX* ibuffer, size_t first, size_t last, SparseCopyMode copy, Workspace* work=nullptr, bool sorted=true) const {
403
+        auto output = sparse_row(r, vbuffer, ibuffer, first, last, work, sorted);
404
+        
405
+        if ((copy == SPARSE_COPY_BOTH || copy == SPARSE_COPY_INDEX) && output.index != ibuffer) {
406
+            copy_over(output.index, ibuffer, output.number);
407
+            output.index = ibuffer;
408
+        }
409
+
410
+        if ((copy == SPARSE_COPY_BOTH || copy == SPARSE_COPY_VALUE) && output.value != vbuffer) {
411
+            copy_over(output.value, vbuffer, output.number);
412
+            output.value = vbuffer;
413
+        }
414
+
415
+        return output;
416
+    }
417
+
418
+    /**
419
+     * @param c Index of the column.
420
+     * @param vbuffer Pointer to an array with enough space for at least `last - first` values.
421
+     * @param ibuffer Pointer to an array with enough space for at least `last - first` indices.
422
+     * @param first First row to extract for column `c`.
423
+     * @param last One past the last row to extract in `c`.
424
+     * @param copy Whether the non-zero values and/or indices should be copied into `vbuffer` and `ibuffer`, respectively.
425
+     * @param work Pointer to a workspace, see comments in `sparse_column()`.
426
+     * @param sorted Should the non-zero elements be sorted by their indices? See `sparse_column()` for details.
427
+     *
428
+     * @return A `SparseRange` object containing the number of non-zero elements in `c` from column `first` up to `last`.
429
+     * This also contains pointers to arrays containing their row indices and values.
430
+     * Depending on `copy`, values and incides will be copied into `vbuffer` and/or `ibuffer`.
431
+     */
432
+    SparseRange<T, IDX> sparse_column_copy(size_t c, T* vbuffer, IDX* ibuffer, size_t first, size_t last, SparseCopyMode copy, Workspace* work=nullptr, bool sorted=true) const {
433
+        auto output = sparse_column(c, vbuffer, ibuffer, first, last, work, sorted);
434
+
435
+        if ((copy == SPARSE_COPY_BOTH || copy == SPARSE_COPY_INDEX) && output.index != ibuffer) {
436
+            copy_over(output.index, ibuffer, output.number);
437
+            output.index = ibuffer;
438
+        }
439
+
440
+        if ((copy == SPARSE_COPY_BOTH || copy == SPARSE_COPY_VALUE) && output.value != vbuffer) {
441
+            copy_over(output.value, vbuffer, output.number);
442
+            output.value = vbuffer;
443
+        }
444
+
445
+        return output;
446
+    }
447
+
448
+    /**
449
+     * @param r Index of the row.
450
+     * @param vbuffer Pointer to an array with enough space for at least `ncol()` values.
451
+     * @param ibuffer Pointer to an array with enough space for at least `ncol()` indices.
452
+     * @param copy Whether the non-zero values and/or indices should be copied into `vbuffer` and `ibuffer`, respectively.
453
+     * @param work Pointer to a workspace, see comments in `sparse_row()`.
454
+     * @param sorted Should the non-zero elements be sorted by their indices? See `sparse_row()` for details.
455
+     *
456
+     * @return A `SparseRange` object containing the number of non-zero elements in `r`.
457
+     * This also contains pointers to arrays containing their column indices and values.
458
+     * Depending on `copy`, values and incides will be copied into `vbuffer` and/or `ibuffer`.
459
+     */
460
+    SparseRange<T, IDX> sparse_row_copy(size_t r, T* vbuffer, IDX* ibuffer, SparseCopyMode copy, Workspace* work=nullptr, bool sorted=true) const {
461
+        return sparse_row_copy(r, vbuffer, ibuffer, 0, this->ncol(), copy, work, sorted);
462
+    }
463
+
464
+    /**
465
+     * @param c Index of the column.
466
+     * @param vbuffer Pointer to an array with enough space for at least `nrow()` values.
467
+     * @param ibuffer Pointer to an array with enough space for at least `nrow()` indices.
468
+     * @param copy Whether the non-zero values and/or indices should be copied into `vbuffer` and `ibuffer`, respectively.
469
+     * @param work Pointer to a workspace, see comments in `sparse_column()`.
470
+     * @param sorted Should the non-zero elements be sorted by their indices? See `sparse_column()` for details.
471
+     *
472
+     * @return A `SparseRange` object containing the number of non-zero elements in `c`.
473
+     * This also contains pointers to arrays containing their row indices and values.
474
+     * Depending on `copy`, values and incides will be copied into `vbuffer` and/or `ibuffer`.
475
+     */
476
+    SparseRange<T, IDX> sparse_column_copy(size_t c, T* vbuffer, IDX* ibuffer, SparseCopyMode copy, Workspace* work=nullptr, bool sorted=true) const {
477
+        return sparse_column_copy(c, vbuffer, ibuffer, 0, this->nrow(), copy, work, sorted);
478
+    }
479
+
480
+public:
481
+    /**
482
+     * @param r Index of the row.
483
+     * @param first First column to extract for row `r`.
484
+     * @param last One past the last column to extract in `r`.
485
+     * @param work Pointer to a workspace, see comments in `sparse_row()`.
486
+     * @param sorted Should the non-zero elements be sorted by their indices? See `sparse_row()` for details.
487
+     *
488
+     * @return A `SparseRange` object containing the number of non-zero elements in `r` from column `first` up to `last`.
489
+     * This also contains pointers to arrays containing their column indices and values.
490
+     * Depending on `copy`, values and incides will be copied into `vbuffer` and/or `ibuffer`.
491
+     */
492
+    SparseRangeCopy<T, IDX> sparse_row(size_t r, size_t first, size_t last, Workspace* work=nullptr, bool sorted=true) const {
493
+        SparseRangeCopy<T, IDX> output(last - first);
494
+        auto ret = sparse_row_copy(r, output.value.data(), output.index.data(), first, last, SPARSE_COPY_BOTH, work, sorted);
495
+        output.index.resize(ret.number);
496
+        output.value.resize(ret.number);
497
+        return output;
498
+    }
499
+
500
+    /**
501
+     * @param c Index of the column.
502
+     * @param first First row to extract for column `c`.
503
+     * @param last One past the last row to extract in `c`.
504
+     * @param work Pointer to a workspace, see comments in `sparse_column()`.
505
+     * @param sorted Should the non-zero elements be sorted by their indices? See `sparse_column()` for details.
506
+     *
507
+     * @return A `SparseRange` object containing the number of non-zero elements in `c` from column `first` up to `last`.
508
+     * This also contains pointers to arrays containing their row indices and values.
509
+     * Depending on `copy`, values and incides will be copied into `vbuffer` and/or `ibuffer`.
510
+     */
511
+    SparseRangeCopy<T, IDX> sparse_column(size_t c, size_t first, size_t last, Workspace* work=nullptr, bool sorted=true) const {
512
+        SparseRangeCopy<T, IDX> output(last - first);
513
+        auto ret = sparse_column_copy(c, output.value.data(), output.index.data(), first, last, SPARSE_COPY_BOTH, work, sorted);
514
+        output.index.resize(ret.number);
515
+        output.value.resize(ret.number);
516
+        return output;
517
+    }
518
+
519
+    /**
520
+     * @param r Index of the row.
521
+     * @param work Pointer to a workspace, see comments in `sparse_row()`.
522
+     * @param sorted Should the non-zero elements be sorted by their indices? See `sparse_row()` for details.
523
+     *
524
+     * @return A `SparseRange` object containing the number of non-zero elements in `r`.
525
+     * This also contains pointers to arrays containing their column indices and values.
526
+     * Depending on `copy`, values and incides will be copied into `vbuffer` and/or `ibuffer`.
527
+     */
528
+    SparseRangeCopy<T, IDX> sparse_row(size_t r, Workspace* work=nullptr, bool sorted=true) const {
529
+        return sparse_row(r, 0, this->ncol(), work, sorted);
530
+    }
531
+
532
+    /**
533
+     * @param c Index of the column.
534
+     * @param work Pointer to a workspace, see comments in `sparse_column()`.
535
+     * @param sorted Should the non-zero elements be sorted by their indices? See `sparse_column()` for details.
536
+     *
537
+     * @return A `SparseRange` object containing the number of non-zero elements in `c`.
538
+     * This also contains pointers to arrays containing their row indices and values.
539
+     * Depending on `copy`, values and incides will be copied into `vbuffer` and/or `ibuffer`.
540
+     */
541
+    SparseRangeCopy<T, IDX> sparse_column(size_t c, Workspace* work=nullptr, bool sorted=true) const {
542
+        return sparse_column(c, 0, this->nrow(), work, sorted);
543
+    }
544
+};
545
+
546
+/**
547
+ * A convenient shorthand for the most common use case of double-precision matrices.
548
+ */
549
+using NumericMatrix = Matrix<double, int>;
550
+
551
+}
552
+
553
+#endif