Falcon
Loading...
Searching...
No Matches
columnsdata.hpp
1// ---------------------------------------------------------------------
2// This file is part of falcon-core.
3//
4// Copyright (C) 2021-present Neuro-Electronics Research Flanders
5//
6// Falcon-server is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// Falcon-server is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with falcon-core. If not, see <http://www.gnu.org/licenses/>.
18// ---------------------------------------------------------------------
19#pragma once
20
21#include "idata.hpp"
22#include "utilities/general.hpp"
23#include "utilities/iterators.hpp"
24#include "utilities/string.hpp"
25
26typedef Range<size_t> SampleRange;
27
28inline std::vector<std::string> generate_labels(size_t nchannels) {
29 std::vector<std::string> labels;
30 for (size_t i = 0; i < nchannels; i++) {
31 labels.push_back(std::to_string(i));
32 }
33
34 return labels;
35}
36
37namespace nsColumn {
38
39using ParentType = AnyType;
40
41struct Parameters {
42 Parameters(const std::vector<std::string>& labels, size_t nsamp = 0)
43 : ncolumns(labels.size()), nsamples(nsamp), labels(labels) {}
44
45 size_t ncolumns;
46 size_t nsamples;
47 std::vector<std::string> labels;
48};
49
50template <typename T>
51class Data : public IData<Data<T>, ParentType> {
52 public:
53 using BaseClass = IData<Data<T>, ParentType>;
60 Data(const std::vector<std::string>& labels, size_t nsamples) {
61 if (labels.size() == 0 || nsamples == 0) {
62 throw std::runtime_error(
63 "Column Data::Initialize - number of "
64 "columns/samples needs to be larger than 0.");
65 }
66 labels_ = labels;
67 ncolumns_ = labels.size();
68 nsamples_ = nsamples;
69 data_.resize(ncolumns_ * nsamples_);
70 }
71
76 Data(const Parameters& parameters) : Data(parameters.labels, parameters.nsamples) {}
77
78 static const std::string static_datatype() { return "columnar [" + get_type_string<T>() + "]"; }
79 static const std::string static_dataname() { return "data"; }
80
84 void ClearData() override { std::fill(data_.begin(), data_.end(), 0); }
85
86 Parameters parameters() const { return Parameters(labels_, nsamples_); }
87
88 size_t ncolumns() const { return ncolumns_; }
89 size_t nsamples() const { return nsamples_; }
90 std::vector<std::string> labels() const { return labels_; }
91
98 void set_data_column(std::string column, const std::vector<T>& data) {
99 if (data.size() != this->nsamples_) {
100 throw std::length_error(
101 ". the data vector to set should have the "
102 "same size as the number of columns (" +
103 std::to_string(ncolumns_) + " columns)");
104 }
105 std::copy(data.begin(), data.end(), begin_column(column));
106 }
107
114 void set_data_column(size_t column, const std::vector<T>& data) {
115 if (data.size() != this->nsamples_) {
116 throw std::length_error(
117 ". the data vector to set should have the "
118 "same size as the number of samples (" +
119 std::to_string(nsamples_) + " samples)");
120 }
121 std::copy(data.begin(), data.end(), begin_column(column));
122 }
123
129 void set_data_sample(size_t sample, const std::vector<T>& data) {
130 if (data.size() != ncolumns_) {
131 throw std::length_error(
132 ". the data vector to set should have the same size as the "
133 "number of column in the dataset (" +
134 std::to_string(ncolumns_) + " columns)");
135 }
136 std::copy(data.begin(), data.end(), begin_sample(sample));
137 }
138
146 void set_data_sample(size_t sample, size_t column, T data) {
147 if (sample >= nsamples_) {
148 throw std::out_of_range(". Sample index " + std::to_string(sample) +
149 " out of range. Max index is " + std::to_string(nsamples_ - 1));
150 }
151 if (column >= ncolumns_) {
152 throw std::out_of_range(". Channel index " + std::to_string(sample) +
153 " out of range. Max index is " + std::to_string(ncolumns_ - 1));
154 }
155 data_[flat_index(sample, column)] = data;
156 }
157
165 void set_data_sample(size_t sample, std::string column, T data) {
166 auto index = extract_index_from_column(column);
167 set_data_sample(sample, index, data);
168 }
169
176 std::vector<T>& data() { return data_; }
177 const std::vector<T>& data() const { return data_; }
178
186 const T& data_sample(size_t sample, size_t column = 0) const {
187 return data_[flat_index(sample, column)];
188 }
189
197 const T& data_sample(size_t sample, std::string column) const {
198 return data_[flat_index(sample, extract_index_from_column(column))];
199 }
200
201 // Operator based on sample index / column index
202
203 T& operator()(size_t sample, size_t column = 0) { return data_[flat_index(sample, column)]; }
204 const T& operator()(size_t sample, size_t column = 0) const {
205 return data_[flat_index(sample, column)];
206 }
207
208 // Operator based on sample index / column label
209
210 T& operator()(size_t sample, std::string column) {
211 auto index = extract_index_from_column(column);
212 return data_[flat_index(sample, index)];
213 }
214 const T& operator()(size_t sample, std::string column) const {
215 auto index = extract_index_from_column(column);
216 return data_[flat_index(sample, index)];
217 }
218
219 // operator based on index from the full dataset
220 // [column_index = index/ncolumns, sample_index = index%ncolumns]
221 T& operator()(size_t index) { return data_[index]; }
222 const T& operator()(size_t index) const { return data_[index]; }
223
224 // iterators
230 T* begin_sample(size_t sample) { return &data_[flat_index(sample)]; }
236 T* end_sample(size_t sample) { return begin_sample(sample) + ncolumns_; }
237
238 const T* begin_sample(size_t sample) const { return &data_[flat_index(sample)]; }
239 const T* end_sample(size_t sample) const { return begin_sample(sample) + ncolumns_; }
240
247 stride_iter<T*> begin_column(size_t column) {
248 return stride_iter<T*>(&data_[column], ncolumns_);
249 }
250
256 stride_iter<T*> end_column(size_t column) { return begin_column(column) + nsamples_; }
257
264 stride_iter<T*> begin_column(std::string column) {
265 auto index = extract_index_from_column(column);
266 return begin_column(index);
267 }
268
274 stride_iter<T*> end_column(std::string column) { return begin_column(column) + nsamples_; }
275
282 void SerializeBinary(std::ostream& stream, Serialization::Format format =
283 Serialization::Format::FULL) const override {
284 BaseClass::SerializeBinary(stream, format);
285 if (format == Serialization::Format::FULL) {
286 stream.write(reinterpret_cast<const char*>(data_.data()), data_.size() * sizeof(T));
287 }
288
289 if (format == Serialization::Format::COMPACT) {
290 uint32_t nsamples_out = static_cast<uint32_t>(nsamples_);
291 uint32_t ncolumns_out = static_cast<uint32_t>(ncolumns_);
292 stream.write(reinterpret_cast<const char*>(&nsamples_out), sizeof(uint32_t));
293 stream.write(reinterpret_cast<const char*>(&ncolumns_out), sizeof(uint32_t));
294
295 for (size_t k = 0; k < nsamples_; ++k) {
296 stream.write(reinterpret_cast<const char*>(&data_[flat_index(k)]),
297 sizeof(T) * ncolumns_);
298 }
299 }
300 }
301
308 void SerializeFlatBuffer(flexbuffers::Builder& flex_builder) override {
309 BaseClass::SerializeFlatBuffer(flex_builder);
310
311 flex_builder.TypedVector("labels", [&] {
312 for (const auto& label : labels_) flex_builder.Add(label);
313 });
314
315 flex_builder.TypedVector("data", [&] {
316 for (auto samples : data_) flex_builder.Add(samples);
317 });
318
319 flex_builder.UInt("ncolumns", ncolumns());
320 flex_builder.UInt("nsamples", nsamples());
321 }
322
328 void SerializeYAML(YAML::Node& node,
329 Serialization::Format format = Serialization::Format::FULL) const override {
330 BaseClass::SerializeYAML(node, format);
331 if (format == Serialization::Format::FULL || format == Serialization::Format::COMPACT) {
332 node["signal"] = data_;
333 }
334 }
335
342 void YAMLDescription(YAML::Node& node, Serialization::Format format =
343 Serialization::Format::FULL) const override {
344 BaseClass::YAMLDescription(node, format);
345 if (format == Serialization::Format::FULL) {
346 node.push_back("signal " + get_type_string<T>() + " (" +
347 std::to_string(nsColumn::Data<T>::nsamples()) + "," +
348 std::to_string(nsColumn::Data<T>::ncolumns()) + ")");
349 }
350
351 if (format == Serialization::Format::COMPACT) {
352 node.push_back("signal " + get_type_string<T>() + " (" +
353 std::to_string(nsColumn::Data<T>::ncolumns()) + ")");
354 }
355 }
356
365 T sum_column(std::string column, bool absolute = false) const {
366 auto index = extract_index_from_column(column);
367 return sum_column(index);
368 }
369
378 T sum_column(size_t column, bool absolute = false) const {
379 if (absolute) {
380 return std::accumulate(begin_column(column), end_column(column), 0,
381 [](T a, T b) { return a + std::abs(b); });
382 }
383
384 return std::accumulate(begin_column(column), end_column(column), 0.0);
385 }
386
395 T mean_column(std::string column, bool absolute = false) const {
396 return sum_column(column, absolute) / ncolumns_;
397 }
398
407 T mean_column(size_t column, bool absolute = false) const {
408 return sum_column(column, absolute) / ncolumns_;
409 }
410
419 T sum_sample(size_t sample, bool absolute = false) const {
420 if (absolute) {
421 return std::accumulate(begin_sample(sample), end_sample(sample), 0,
422 [](T a, T b) { return a + std::abs(b); });
423 }
424 return std::accumulate(begin_sample(sample), end_sample(sample), 0.0);
425 }
426
435 T mean_sample(size_t sample, bool absolute = false) const {
436 return sum_sample(sample, absolute) / ncolumns_;
437 }
438
439 private:
440 size_t extract_index_from_column(std::string column) const {
441 auto it = std::find(labels_.begin(), labels_.end(), column);
442
443 // If element was found
444 if (it == labels_.end()) {
445 throw std::runtime_error(". The column " + column + " does not exist in this dataset.");
446 }
447
448 return it - labels_.begin();
449 }
450
451 protected:
452 inline size_t flat_index(size_t sample, size_t channel) const {
453 return channel + sample * ncolumns_;
454 }
455 inline size_t flat_index(size_t sample) const { return sample * ncolumns_; }
456
457 protected:
458 size_t ncolumns_;
459 size_t nsamples_;
460
461 std::vector<std::string> labels_;
462 std::vector<T> data_;
463};
464
465class Capabilities {
466 public:
467 Capabilities(ChannelRange column_range,
468 SampleRange sample_range = SampleRange(1, std::numeric_limits<uint32_t>::max()))
469 : column_range_(column_range), sample_range_(sample_range), labels_({}) {}
470
471 Capabilities(std::vector<std::string> labels,
472 SampleRange sample_range = SampleRange(1, std::numeric_limits<uint32_t>::max()))
473 : column_range_(ChannelRange(labels.size())),
474 sample_range_(sample_range),
475 labels_(labels) {}
476
477 ChannelRange column_range() const { return column_range_; }
478 SampleRange sample_range() const { return sample_range_; }
479
480 template <class T>
481 void Validate(const Data<T>& prototype) {
482 if (!sample_range_.inrange(prototype.nsamples())) {
483 throw std::runtime_error("Number of samples cannot be zero and needs to be in range " +
484 sample_range_.to_string());
485 }
486
487 if (!column_range_.inrange(prototype.ncolumns())) {
488 throw std::runtime_error("Number of columns cannot be zero and needs to be in range " +
489 column_range_.to_string());
490 }
491
492 auto cl = prototype.labels();
493 for (auto label : labels_) {
494 if (std::find(cl.begin(), cl.end(), label) == cl.end()) {
495 throw std::runtime_error("Expected column: " + label +
496 " is not part of the column dataset given in input.");
497 }
498 }
499 }
500
501 protected:
502 ChannelRange column_range_;
503 SampleRange sample_range_;
504 std::vector<std::string> labels_;
505};
506
507} // namespace nsColumn
508
509template <typename T>
510using ColumnsType =
Convenient template class to define data types.
Definition idata.hpp:75
Base class of all data object classes.
Definition idata.hpp:95
Definition columnsdata.hpp:465
Definition columnsdata.hpp:51
T * end_sample(size_t sample)
end_sample iterator at the end of a sample index
Definition columnsdata.hpp:236
void YAMLDescription(YAML::Node &node, Serialization::Format format=Serialization::Format::FULL) const override
YAMLDescription - this datatype add to the metadata describing the data format the signal,...
Definition columnsdata.hpp:342
const T & data_sample(size_t sample, size_t column=0) const
data_sample - return the data for one sample index and one column index
Definition columnsdata.hpp:186
void set_data_column(std::string column, const std::vector< T > &data)
set_data_column set all samples for one column based on the name of the column
Definition columnsdata.hpp:98
T sum_sample(size_t sample, bool absolute=false) const
sum_sample - compute the (absolute) sum of all column data for the same sample index
Definition columnsdata.hpp:419
const T & data_sample(size_t sample, std::string column) const
data_sample - return the data for one sample index and one column label
Definition columnsdata.hpp:197
T * begin_sample(size_t sample)
begin_sample iterator at the start of a sample index
Definition columnsdata.hpp:230
void SerializeBinary(std::ostream &stream, Serialization::Format format=Serialization::Format::FULL) const override
SerializeBinary - add to the binary stream the data [columnxsample].
Definition columnsdata.hpp:282
void SerializeYAML(YAML::Node &node, Serialization::Format format=Serialization::Format::FULL) const override
SerializeYAML - add to the yaml node the data [columnxsample].
Definition columnsdata.hpp:328
T mean_sample(size_t sample, bool absolute=false) const
mean_sample - compute the mean of the (absolute) sum of all column data for the same sample index
Definition columnsdata.hpp:435
stride_iter< T * > end_column(size_t column)
end_column - iterator at the end of the column based on the location in the dataset
Definition columnsdata.hpp:256
void set_data_sample(size_t sample, size_t column, T data)
set_data_sample set one data for one column index and one sample index
Definition columnsdata.hpp:146
void set_data_sample(size_t sample, std::string column, T data)
set_data_sample set one data for one column label and one sample index
Definition columnsdata.hpp:165
void ClearData() override
ClearData - clear the data.
Definition columnsdata.hpp:84
T mean_column(size_t column, bool absolute=false) const
mean_column - compute the mean of the (absolute) sum of all samples in the same column
Definition columnsdata.hpp:407
void set_data_sample(size_t sample, const std::vector< T > &data)
set_data_sample set column data for one sample
Definition columnsdata.hpp:129
stride_iter< T * > begin_column(std::string column)
begin_column - iterator at the start of the column based on name of the column
Definition columnsdata.hpp:264
void set_data_column(size_t column, const std::vector< T > &data)
set_data_column set all samples for one column based on the column index
Definition columnsdata.hpp:114
Data(const std::vector< std::string > &labels, size_t nsamples)
Data constructor with the labels for each column and the number of samples.
Definition columnsdata.hpp:60
stride_iter< T * > begin_column(size_t column)
begin_column iterator at the start of the column based on the location in the dataset
Definition columnsdata.hpp:247
T sum_column(std::string column, bool absolute=false) const
sum_column - compute the (absolute) sum of all samples in the same column
Definition columnsdata.hpp:365
Data(const Parameters &parameters)
Data constructor from the parameters object.
Definition columnsdata.hpp:76
T mean_column(std::string column, bool absolute=false) const
mean_column - compute the mean of the (absolute) sum of all samples in the same column
Definition columnsdata.hpp:395
std::vector< T > & data()
data - return full data with this format [c1s1, c1s2.., c1sn, c2s1, c2s2 ..., cns1,...
Definition columnsdata.hpp:176
T sum_column(size_t column, bool absolute=false) const
sum_column - compute the (absolute) sum of all samples in the same column
Definition columnsdata.hpp:378
stride_iter< T * > end_column(std::string column)
end_column - iterator at the end of the column based on name of the column
Definition columnsdata.hpp:274
void SerializeFlatBuffer(flexbuffers::Builder &flex_builder) override
SerializeFlatBuffer - add to the flexbuffer the data labeled [label0:nsamples, label1:nsamples....
Definition columnsdata.hpp:308
Definition columnsdata.hpp:41