Falcon
Loading...
Searching...
No Matches
channellist.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
20#pragma once
21
22#include <iostream>
23#include <regex>
24#include <vector>
25
26#include "utilities/string.hpp"
27#include "yaml-cpp/yaml.h"
28
29template <typename T>
30class ChannelList {
31 public:
32 ChannelList() {};
33
34 std::vector<std::pair<T, std::string>> get_channels() const { return channels_; }
35
36 std::vector<T> get_channel_numbers() const {
37 std::vector<T> channel_numbers;
38
39 std::transform(channels_.begin(), channels_.end(), std::back_inserter(channel_numbers),
40 [](auto const& pair) { return pair.first; });
41
42 return channel_numbers;
43 }
44
45 std::vector<std::string> get_labels() const {
46 std::vector<std::string> labels;
47
48 std::transform(channels_.begin(), channels_.end(), std::back_inserter(labels),
49 [](auto const& pair) { return pair.second; });
50
51 return labels;
52 }
53
54 void add_channels(T channel, std::string label = "") {
55 if (label == "") {
56 label = std::to_string(channel);
57 }
58 add_element(channel, label);
59 };
60
61 void add_channels(std::vector<T> channels, std::vector<std::string> labels = {}) {
62 channels_.insert(channels_.end(), channels.begin(), channels.end());
63
64 if (labels.size() == 0) {
65 for (auto c : channels) {
66 add_element(c, std::to_string(c));
67 }
68 } else if (labels.size() != channels.size()) {
69 throw std::length_error(". channels and labels should have the same size.");
70 } else {
71 for (uint i = 0; i < channels.size(); i++) {
72 add_element(channels[i], labels[i]);
73 }
74 }
75 };
76
77 void add_channels(T range_min, T range_max) {
78 for (T channel = range_min; channel <= range_max; channel++) {
79 add_channels(channel);
80 }
81 }
82
83 void remove_channels(double range_min, double range_max) {
84 auto to_remove = std::remove_if(
85 channels_.begin(), channels_.end(),
86 [range_min, range_max](T x) { return x.first >= range_min and x.first <= range_max; });
87
88 channels_.erase(to_remove, channels_.end());
89 }
90
91 void remove_channels(std::vector<T> channels) {
92 auto to_remove = std::remove_if(channels_.begin(), channels_.end(), [channels](T x) {
93 return std::find(channels.begin(), channels.end(), x.first) != channels.end();
94 });
95
96 channels_.erase(to_remove, channels_.end());
97 }
98
99 void remove_channels(std::vector<std::string> labels) {
100 auto to_remove = std::remove_if(channels_.begin(), channels_.end(), [labels](T x) {
101 return std::find(labels.begin(), labels.end(), x.second) != labels.end();
102 });
103
104 channels_.erase(to_remove, channels_.end());
105 }
106
107 auto size() const { return channels_.size(); };
108
109 T& operator[](size_t index) { return channels_[index]; };
110 const T& operator[](size_t index) const { return channels_[index]; };
111
112 auto begin() const { return channels_.begin(); };
113 auto end() const { return channels_.end(); };
114
115 auto begin() { return channels_.begin(); };
116 auto end() { return channels_.end(); };
117
125 std::string to_string() const {
126 std::string str = "[";
127 if (!channels_.empty()) {
128 unsigned int index = 0;
129 bool inrange = false;
130
131 while (index < channels_.size() - 1) {
132 if (channels_[index].first + 1 == channels_[index + 1].first) {
133 if (!inrange) {
134 str += std::to_string(channels_[index].first) + "-";
135 }
136 inrange = true;
137 } else {
138 str += std::to_string(channels_[index].first) + ", ";
139 inrange = false;
140 }
141 index++;
142 }
143 str += std::to_string(channels_[index].first);
144 }
145 str += "]";
146 return str;
147 }
148
156 bool all_in_range(T range_min, T range_max) const {
157 for (auto const& ch : channels_) {
158 if (ch.first >= range_max or ch.first < range_min) {
159 return false;
160 }
161 }
162 return true;
163 }
164
171 bool is_subset(std::vector<T> channels_vec) const {
172 const auto subset_vec = get_channel_numbers();
173 const std::set<T> subset(subset_vec.begin(), subset_vec.end());
174 const std::set<T> channels(channels_vec.begin(), channels_vec.end());
175
176 return std::includes(channels.begin(), channels.end(), subset.begin(), subset.end());
177 }
178
185 bool is_subset(std::vector<std::string> labels_vec) const {
186 const auto subset_vec = get_labels();
187 const std::set<std::string> subset(subset_vec.begin(), subset_vec.end());
188 const std::set<std::string> labels(labels_vec.begin(), labels_vec.end());
189 return std::includes(labels.begin(), labels.end(), subset.begin(), subset.end());
190 }
191
200 bool is_sorted(bool by_label = false) const {
201 if (by_label) {
202 return std::is_sorted(
203 channels_.begin(), channels_.end(),
204 [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
205 }
206
207 return std::is_sorted(channels_.begin(), channels_.end());
208 }
209
215 bool is_unique() const {
216 auto channels = get_channels();
217 std::sort(channels.begin(), channels.end());
218 return std::adjacent_find(channels.begin(), channels.end()) == channels.end();
219 }
220
232 void sort(bool by_label = false) {
233 if (by_label) {
234 std::sort(channels_.begin(), channels_.end(),
235 [](const auto& lhs, const auto& rhs) { return lhs.second < rhs.second; });
236 } else {
237 std::sort(channels_.begin(), channels_.end());
238 }
239 }
240
249 void unique() {
250 sort();
251 auto it = std::unique(channels_.begin(), channels_.end());
252 channels_.resize(std::distance(channels_.begin(), it));
253 }
254
255 private:
256 void add_element(T channel, std::string label) {
257 if (std::any_of(
258 channels_.begin(), channels_.end(),
259 [&label](const std::pair<T, std::string>& ch) { return ch.second == label; })) {
260 throw std::invalid_argument(". This label " + label +
261 " already exist in this channel list and should be unique");
262 }
263
264 channels_.push_back(std::make_pair(channel, label));
265 }
266
267 private:
268 std::vector<std::pair<T, std::string>> channels_;
269};
270
271namespace YAML {
272
273template <typename T>
274struct convert<ChannelList<T>> {
275 static Node encode(const ChannelList<T>& rhs) {
276 Node node;
277 node = rhs.get_channel_numbers();
278 return node;
279 }
280
281 static bool decode(const Node& node, ChannelList<T>& rhs) {
282 if (node.IsSequence()) {
283 auto channels = node.as<std::vector<std::string>>();
284 for (auto part : channels) {
285 part = std::regex_replace(part, std::regex(" "), "");
286 auto range = str_split(part, '-');
287 if (range.size() == 1) {
288 rhs.add_channels(atoi(range[0].c_str()));
289 } else if (range.size() == 2) {
290 rhs.add_channels(atoi(range[0].c_str()), atoi(range[1].c_str()));
291 } else {
292 throw std::runtime_error(part + " is not a valid list specification.");
293 }
294 }
295 } else {
296 return false;
297 }
298
299 return true;
300 }
301};
302} // namespace YAML
Definition channellist.hpp:30
bool is_subset(std::vector< std::string > labels_vec) const
is_subset check if the labels in this collection is a subset of the labels list given in input.
Definition channellist.hpp:185
bool all_in_range(T range_min, T range_max) const
all_in_range check if all the column numbers in this collection are contained in the range given in i...
Definition channellist.hpp:156
bool is_subset(std::vector< T > channels_vec) const
is_subset check if the column numbers in this collection is a subset of the column numbers list given...
Definition channellist.hpp:171
std::string to_string() const
to_string print the channel list in a yaml format understood by the options lib.
Definition channellist.hpp:125
bool is_sorted(bool by_label=false) const
is_sorted check without modifying the collection if it is sorted by column numbers or by labels
Definition channellist.hpp:200
bool is_unique() const
is_unique check without modifying the collection if there is an unique set of column numbers.
Definition channellist.hpp:215
void sort(bool by_label=false)
sort the collection of pair (column index, label)
Definition channellist.hpp:232
void unique()
unique - Remove duplicates to keep only an unique set of channel numbers. Because of the way sort wor...
Definition channellist.hpp:249