kmeans_tatami
tatami wrappers for k-means clustering
Loading...
Searching...
No Matches
kmeans_tatami.hpp
Go to the documentation of this file.
1#ifndef KMEANS_TATAMI_HPP
2#define KMEANS_TATAMI_HPP
3
4#include <memory>
5#include <type_traits>
6#include <cstddef>
7
8#include "tatami/tatami.hpp"
9#include "kmeans/kmeans.hpp"
10
20namespace kmeans_tatami {
21
25template<typename KIndex_, typename KData_, typename TValue_, typename TIndex_, class Extractor_ = tatami::MyopicDenseExtractor<TValue_, TIndex_> >
26class Random final : public kmeans::RandomAccessExtractor<KIndex_, KData_> {
27public:
28 Random(std::unique_ptr<Extractor_> ext, TIndex_ ndim) : my_ext(std::move(ext)) {
30 if constexpr(!same_type) {
32 }
33 }
34
35private:
36 std::unique_ptr<Extractor_> my_ext;
37 std::vector<TValue_> my_buffer;
38 static constexpr bool same_type = std::is_same<TValue_, KData_>::value;
39 typename std::conditional<same_type, bool, std::vector<KData_> > my_output;
40
41public:
42 const KData_* get_observation(KIndex_ i) {
43 auto ptr = my_ext->fetch(i, my_buffer.data());
44 if constexpr(same_type) {
45 return ptr;
46 } else {
47 std::copy_n(ptr, my_buffer.size(), my_output.data());
48 return my_output.data();
49 }
50 }
51};
52
53template<typename KIndex_, typename KData_, typename TValue_, typename TIndex_, class Extractor_ = tatami::OracularDenseExtractor<TValue_, TIndex_> >
54class Consecutive final : public kmeans::ConsecutiveAccessExtractor<KIndex_, KData_> {
55public:
56 Consecutive(std::unique_ptr<Extractor_> ext, TIndex_ ndim) : my_ext(std::move(ext)) {
58 if constexpr(!same_type) {
60 }
61 }
62
63private:
64 std::unique_ptr<Extractor_> my_ext;
65 std::vector<TValue_> my_buffer;
66 static constexpr bool same_type = std::is_same<TValue_, KData_>::value;
67 typename std::conditional<same_type, bool, std::vector<KData_> > my_output;
68
69public:
70 const KData_* get_observation() {
71 auto ptr = my_ext->fetch(my_buffer.data());
72 if constexpr(same_type) {
73 return ptr;
74 } else {
75 std::copy_n(ptr, my_buffer.size(), my_output.data());
76 return my_output.data();
77 }
78 }
79};
80
81template<typename KIndex_, typename KData_, typename TValue_, typename TIndex_, class Extractor_ = tatami::OracularDenseExtractor<TValue_, TIndex_> >
82class Indexed final : public kmeans::IndexedAccessExtractor<KIndex_, KData_> {
83public:
84 Indexed(std::unique_ptr<Extractor_> ext, TIndex_ ndim) : my_ext(std::move(ext)) {
86 if constexpr(!same_type) {
88 }
89 }
90
91private:
92 std::unique_ptr<Extractor_> my_ext;
93 std::vector<TValue_> my_buffer;
94 static constexpr bool same_type = std::is_same<TValue_, KData_>::value;
95 typename std::conditional<same_type, bool, std::vector<KData_> > my_output;
96
97public:
98 const KData_* get_observation() {
99 auto ptr = my_ext->fetch(my_buffer.data());
100 if constexpr(same_type) {
101 return ptr;
102 } else {
103 std::copy_n(ptr, my_buffer.size(), my_output.data());
104 return my_output.data();
105 }
106 }
107};
126template<typename KIndex_, typename KData_, typename TValue_, typename TIndex_, class MatrixPointer_ = std::shared_ptr<const tatami::Matrix<TValue_, TIndex_> > >
127class Matrix final : public kmeans::Matrix<KIndex_, KData_> {
128private:
129 MatrixPointer_ my_matrix;
130 KIndex_ my_nobs;
131 std::size_t my_ndim;
132 bool my_transposed;
133
134public:
140 Matrix(MatrixPointer_ matrix, bool transposed = false) : my_matrix(std::move(matrix)), my_transposed(transposed) {
141 TIndex_ cur_nobs;
142 if (my_transposed) {
143 cur_nobs = my_matrix->nrow();
144 my_ndim = my_matrix->ncol(); // cast is guaranteed to be safe as tatami indices can always fit in a size_t.
145 } else {
146 cur_nobs = my_matrix->ncol();
147 my_ndim = my_matrix->nrow();
148 }
149
150 // Making sure that we can cast to KIndex_.
151 // tatami extents are guaranteed to be positive and fit in a size_t, so we attest that.
152 my_nobs = sanisizer::cast<KIndex_>(sanisizer::attest_gez(sanisizer::attest_max_by_type<std::size_t>(cur_nobs)));
153 }
154
155 KIndex_ num_observations() const {
156 return my_nobs;
157 }
158
159 std::size_t num_dimensions() const {
160 return my_ndim;
161 }
162
163public:
164 std::unique_ptr<kmeans::RandomAccessExtractor<KIndex_, KData_> > new_extractor() const {
165 return std::make_unique<Random<KIndex_, KData_, TValue_, TIndex_> >(my_matrix->dense(my_transposed, {}), my_ndim);
166 }
167
168 std::unique_ptr<kmeans::ConsecutiveAccessExtractor<KIndex_, KData_> > new_extractor(KIndex_ start, KIndex_ length) const {
169 // Block should be castable from TIndex_ to KIndex_ as it should be less than num_observations().
170 auto optr = std::make_shared<tatami::ConsecutiveOracle<TIndex_> >(start, length);
171 return std::make_unique<Consecutive<KIndex_, KData_, TValue_, TIndex_> >(my_matrix->dense(my_transposed, std::move(optr), {}), my_ndim);
172 }
173
174 std::unique_ptr<kmeans::IndexedAccessExtractor<KIndex_, KData_> > new_extractor(const KIndex_* sequence, std::size_t length) const {
175 auto optr = std::make_shared<tatami::FixedViewOracle<TIndex_, const KIndex_*> >(sequence, length);
176 return std::make_unique<Indexed<KIndex_, KData_, TValue_, TIndex_> >(my_matrix->dense(my_transposed, std::move(optr), {}), my_ndim);
177 }
178};
179
180}
181
182#endif
kmeans-compatible wrapper around a tatami matrix.
Definition kmeans_tatami.hpp:127
Matrix(MatrixPointer_ matrix, bool transposed=false)
Definition kmeans_tatami.hpp:140
Wrapper around a tatami matrix.
void resize_container_to_Index_size(Container_ &container, const Index_ x, Args_ &&... args)