|
@@
-1,17
+1,56
|
|
1
|
#ifndef SCIQLOP_ARRAYDATA_H
|
|
1
|
#ifndef SCIQLOP_ARRAYDATA_H
|
|
2
|
#define SCIQLOP_ARRAYDATA_H
|
|
2
|
#define SCIQLOP_ARRAYDATA_H
|
|
3
|
|
|
3
|
|
|
|
|
|
4
|
#include <Common/SortUtils.h>
|
|
|
|
|
5
|
|
|
4
|
#include <QReadLocker>
|
|
6
|
#include <QReadLocker>
|
|
5
|
#include <QReadWriteLock>
|
|
7
|
#include <QReadWriteLock>
|
|
6
|
#include <QVector>
|
|
8
|
#include <QVector>
|
|
7
|
|
|
9
|
|
|
8
|
#include <memory>
|
|
10
|
#include <memory>
|
|
9
|
|
|
11
|
|
|
|
|
|
12
|
template <int Dim>
|
|
|
|
|
13
|
class ArrayData;
|
|
|
|
|
14
|
|
|
|
|
|
15
|
using DataContainer = QVector<QVector<double> >;
|
|
|
|
|
16
|
|
|
|
|
|
17
|
namespace arraydata_detail {
|
|
|
|
|
18
|
|
|
|
|
|
19
|
/// Struct used to sort ArrayData
|
|
|
|
|
20
|
template <int Dim>
|
|
|
|
|
21
|
struct Sort {
|
|
|
|
|
22
|
static std::shared_ptr<ArrayData<Dim> > sort(const DataContainer &data,
|
|
|
|
|
23
|
const std::vector<int> &sortPermutation)
|
|
|
|
|
24
|
{
|
|
|
|
|
25
|
auto nbComponents = data.size();
|
|
|
|
|
26
|
auto sortedData = DataContainer(nbComponents);
|
|
|
|
|
27
|
|
|
|
|
|
28
|
for (auto i = 0; i < nbComponents; ++i) {
|
|
|
|
|
29
|
sortedData[i] = SortUtils::sort(data.at(i), sortPermutation);
|
|
|
|
|
30
|
}
|
|
|
|
|
31
|
|
|
|
|
|
32
|
return std::make_shared<ArrayData<Dim> >(std::move(sortedData));
|
|
|
|
|
33
|
}
|
|
|
|
|
34
|
};
|
|
|
|
|
35
|
|
|
|
|
|
36
|
/// Specialization for uni-dimensional ArrayData
|
|
|
|
|
37
|
template <>
|
|
|
|
|
38
|
struct Sort<1> {
|
|
|
|
|
39
|
static std::shared_ptr<ArrayData<1> > sort(const DataContainer &data,
|
|
|
|
|
40
|
const std::vector<int> &sortPermutation)
|
|
|
|
|
41
|
{
|
|
|
|
|
42
|
return std::make_shared<ArrayData<1> >(SortUtils::sort(data.at(0), sortPermutation));
|
|
|
|
|
43
|
}
|
|
|
|
|
44
|
};
|
|
|
|
|
45
|
|
|
|
|
|
46
|
} // namespace arraydata_detail
|
|
|
|
|
47
|
|
|
10
|
/**
|
|
48
|
/**
|
|
11
|
* @brief The ArrayData class represents a dataset for a data series.
|
|
49
|
* @brief The ArrayData class represents a dataset for a data series.
|
|
12
|
*
|
|
50
|
*
|
|
13
|
* A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
|
|
51
|
* A dataset can be unidimensional or two-dimensional. This property is determined by the Dim
|
|
14
|
* template-parameter.
|
|
52
|
* template-parameter. In a case of a two-dimensional dataset, each dataset component has the same
|
|
|
|
|
53
|
* number of values
|
|
15
|
*
|
|
54
|
*
|
|
16
|
* @tparam Dim the dimension of the ArrayData (one or two)
|
|
55
|
* @tparam Dim the dimension of the ArrayData (one or two)
|
|
17
|
* @sa IDataSeries
|
|
56
|
* @sa IDataSeries
|
|
@@
-19,16
+58,9
|
|
19
|
template <int Dim>
|
|
58
|
template <int Dim>
|
|
20
|
class ArrayData {
|
|
59
|
class ArrayData {
|
|
21
|
public:
|
|
60
|
public:
|
|
22
|
/**
|
|
61
|
// ///// //
|
|
23
|
* Ctor for a unidimensional ArrayData
|
|
62
|
// Ctors //
|
|
24
|
* @param nbColumns the number of values the ArrayData will hold
|
|
63
|
// ///// //
|
|
25
|
*/
|
|
|
|
|
26
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
|
|
|
27
|
explicit ArrayData(int nbColumns) : m_Data{1, QVector<double>{}}
|
|
|
|
|
28
|
{
|
|
|
|
|
29
|
QWriteLocker locker{&m_Lock};
|
|
|
|
|
30
|
m_Data[0].resize(nbColumns);
|
|
|
|
|
31
|
}
|
|
|
|
|
32
|
|
|
64
|
|
|
33
|
/**
|
|
65
|
/**
|
|
34
|
* Ctor for a unidimensional ArrayData
|
|
66
|
* Ctor for a unidimensional ArrayData
|
|
@@
-37,86
+69,72
public:
|
|
37
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
69
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
38
|
explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
|
|
70
|
explicit ArrayData(QVector<double> data) : m_Data{1, QVector<double>{}}
|
|
39
|
{
|
|
71
|
{
|
|
40
|
QWriteLocker locker{&m_Lock};
|
|
|
|
|
41
|
m_Data[0] = std::move(data);
|
|
72
|
m_Data[0] = std::move(data);
|
|
42
|
}
|
|
73
|
}
|
|
43
|
|
|
74
|
|
|
44
|
/// Copy ctor
|
|
|
|
|
45
|
explicit ArrayData(const ArrayData &other)
|
|
|
|
|
46
|
{
|
|
|
|
|
47
|
QReadLocker otherLocker{&other.m_Lock};
|
|
|
|
|
48
|
QWriteLocker locker{&m_Lock};
|
|
|
|
|
49
|
m_Data = other.m_Data;
|
|
|
|
|
50
|
}
|
|
|
|
|
51
|
|
|
|
|
|
52
|
/**
|
|
75
|
/**
|
|
53
|
* @return the data at a specified index
|
|
76
|
* Ctor for a two-dimensional ArrayData. The number of components (number of vectors) must be
|
|
54
|
* @remarks index must be a valid position
|
|
77
|
* greater than 2 and each component must have the same number of values
|
|
55
|
* @remarks this method is only available for a unidimensional ArrayData
|
|
78
|
* @param data the data the ArrayData will hold
|
|
|
|
|
79
|
* @throws std::invalid_argument if the number of components is less than 2
|
|
|
|
|
80
|
* @remarks if the number of values is not the same for each component, no value is set
|
|
56
|
*/
|
|
81
|
*/
|
|
57
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
82
|
template <int D = Dim, typename = std::enable_if_t<D == 2> >
|
|
58
|
double at(int index) const noexcept
|
|
83
|
explicit ArrayData(DataContainer data)
|
|
59
|
{
|
|
84
|
{
|
|
60
|
QReadLocker locker{&m_Lock};
|
|
85
|
auto nbComponents = data.size();
|
|
61
|
return m_Data[0].at(index);
|
|
86
|
if (nbComponents < 2) {
|
|
|
|
|
87
|
throw std::invalid_argument{
|
|
|
|
|
88
|
QString{"A multidimensional ArrayData must have at least 2 components (found: %1"}
|
|
|
|
|
89
|
.arg(data.size())
|
|
|
|
|
90
|
.toStdString()};
|
|
62
|
}
|
|
91
|
}
|
|
63
|
|
|
92
|
|
|
64
|
/**
|
|
93
|
auto nbValues = data.front().size();
|
|
65
|
* Sets a data at a specified index. The index has to be valid to be effective
|
|
94
|
if (std::all_of(data.cbegin(), data.cend(), [nbValues](const auto &component) {
|
|
66
|
* @param index the index to which the data will be set
|
|
95
|
return component.size() == nbValues;
|
|
67
|
* @param data the data to set
|
|
96
|
})) {
|
|
68
|
* @remarks this method is only available for a unidimensional ArrayData
|
|
97
|
m_Data = std::move(data);
|
|
69
|
*/
|
|
|
|
|
70
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
|
|
|
71
|
void setData(int index, double data) noexcept
|
|
|
|
|
72
|
{
|
|
|
|
|
73
|
QWriteLocker locker{&m_Lock};
|
|
|
|
|
74
|
if (index >= 0 && index < m_Data.at(0).size()) {
|
|
|
|
|
75
|
m_Data[0].replace(index, data);
|
|
|
|
|
76
|
}
|
|
98
|
}
|
|
|
|
|
99
|
else {
|
|
|
|
|
100
|
m_Data = DataContainer{nbComponents, QVector<double>{}};
|
|
77
|
}
|
|
101
|
}
|
|
78
|
|
|
|
|
|
79
|
/**
|
|
|
|
|
80
|
* @return the data as a vector
|
|
|
|
|
81
|
* @remarks this method is only available for a unidimensional ArrayData
|
|
|
|
|
82
|
*/
|
|
|
|
|
83
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
|
|
|
84
|
QVector<double> data() const noexcept
|
|
|
|
|
85
|
{
|
|
|
|
|
86
|
QReadLocker locker{&m_Lock};
|
|
|
|
|
87
|
return m_Data[0];
|
|
|
|
|
88
|
}
|
|
102
|
}
|
|
89
|
|
|
103
|
|
|
90
|
/**
|
|
104
|
/// Copy ctor
|
|
91
|
* @return the data as a vector, as a const reference
|
|
105
|
explicit ArrayData(const ArrayData &other)
|
|
92
|
* @remarks this method is only available for a unidimensional ArrayData
|
|
|
|
|
93
|
*/
|
|
|
|
|
94
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
|
|
|
95
|
const QVector<double> &cdata() const noexcept
|
|
|
|
|
96
|
{
|
|
106
|
{
|
|
97
|
QReadLocker locker{&m_Lock};
|
|
107
|
QReadLocker otherLocker{&other.m_Lock};
|
|
98
|
return m_Data.at(0);
|
|
108
|
m_Data = other.m_Data;
|
|
99
|
}
|
|
109
|
}
|
|
100
|
|
|
110
|
|
|
|
|
|
111
|
// /////////////// //
|
|
|
|
|
112
|
// General methods //
|
|
|
|
|
113
|
// /////////////// //
|
|
|
|
|
114
|
|
|
101
|
/**
|
|
115
|
/**
|
|
102
|
* Merges into the array data an other array data
|
|
116
|
* Merges into the array data an other array data. The two array datas must have the same number
|
|
|
|
|
117
|
* of components so the merge can be done
|
|
103
|
* @param other the array data to merge with
|
|
118
|
* @param other the array data to merge with
|
|
104
|
* @param prepend if true, the other array data is inserted at the beginning, otherwise it is
|
|
119
|
* @param prepend if true, the other array data is inserted at the beginning, otherwise it is
|
|
105
|
* inserted at the end
|
|
120
|
* inserted at the end
|
|
106
|
* @remarks this method is only available for a unidimensional ArrayData
|
|
|
|
|
107
|
*/
|
|
121
|
*/
|
|
108
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
122
|
void add(const ArrayData<Dim> &other, bool prepend = false)
|
|
109
|
void add(const ArrayData<1> &other, bool prepend = false)
|
|
|
|
|
110
|
{
|
|
123
|
{
|
|
111
|
QWriteLocker locker{&m_Lock};
|
|
124
|
QWriteLocker locker{&m_Lock};
|
|
112
|
if (!m_Data.empty()) {
|
|
|
|
|
113
|
QReadLocker otherLocker{&other.m_Lock};
|
|
125
|
QReadLocker otherLocker{&other.m_Lock};
|
|
114
|
|
|
126
|
|
|
|
|
|
127
|
auto nbComponents = m_Data.size();
|
|
|
|
|
128
|
if (nbComponents != other.m_Data.size()) {
|
|
|
|
|
129
|
return;
|
|
|
|
|
130
|
}
|
|
|
|
|
131
|
|
|
|
|
|
132
|
for (auto componentIndex = 0; componentIndex < nbComponents; ++componentIndex) {
|
|
115
|
if (prepend) {
|
|
133
|
if (prepend) {
|
|
116
|
const auto &otherData = other.data();
|
|
134
|
const auto &otherData = other.data(componentIndex);
|
|
117
|
const auto otherDataSize = otherData.size();
|
|
135
|
const auto otherDataSize = otherData.size();
|
|
118
|
|
|
136
|
|
|
119
|
auto &data = m_Data[0];
|
|
137
|
auto &data = m_Data[componentIndex];
|
|
120
|
data.insert(data.begin(), otherDataSize, 0.);
|
|
138
|
data.insert(data.begin(), otherDataSize, 0.);
|
|
121
|
|
|
139
|
|
|
122
|
for (auto i = 0; i < otherDataSize; ++i) {
|
|
140
|
for (auto i = 0; i < otherDataSize; ++i) {
|
|
@@
-124,45
+142,88
public:
|
|
124
|
}
|
|
142
|
}
|
|
125
|
}
|
|
143
|
}
|
|
126
|
else {
|
|
144
|
else {
|
|
127
|
m_Data[0] += other.data();
|
|
145
|
m_Data[componentIndex] += other.data(componentIndex);
|
|
128
|
}
|
|
146
|
}
|
|
129
|
}
|
|
147
|
}
|
|
130
|
}
|
|
148
|
}
|
|
131
|
|
|
149
|
|
|
132
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
150
|
void clear()
|
|
|
|
|
151
|
{
|
|
|
|
|
152
|
QWriteLocker locker{&m_Lock};
|
|
|
|
|
153
|
|
|
|
|
|
154
|
auto nbComponents = m_Data.size();
|
|
|
|
|
155
|
for (auto i = 0; i < nbComponents; ++i) {
|
|
|
|
|
156
|
m_Data[i].clear();
|
|
|
|
|
157
|
}
|
|
|
|
|
158
|
}
|
|
|
|
|
159
|
|
|
|
|
|
160
|
/**
|
|
|
|
|
161
|
* @return the data of a component
|
|
|
|
|
162
|
* @param componentIndex the index of the component to retrieve the data
|
|
|
|
|
163
|
* @return the component's data, empty vector if the index is invalid
|
|
|
|
|
164
|
*/
|
|
|
|
|
165
|
QVector<double> data(int componentIndex) const noexcept
|
|
|
|
|
166
|
{
|
|
|
|
|
167
|
QReadLocker locker{&m_Lock};
|
|
|
|
|
168
|
|
|
|
|
|
169
|
return (componentIndex >= 0 && componentIndex < m_Data.size()) ? m_Data.at(componentIndex)
|
|
|
|
|
170
|
: QVector<double>{};
|
|
|
|
|
171
|
}
|
|
|
|
|
172
|
|
|
|
|
|
173
|
/// @return the size (i.e. number of values) of a single component
|
|
|
|
|
174
|
/// @remarks in a case of a two-dimensional ArrayData, each component has the same size
|
|
133
|
int size() const
|
|
175
|
int size() const
|
|
134
|
{
|
|
176
|
{
|
|
135
|
QReadLocker locker{&m_Lock};
|
|
177
|
QReadLocker locker{&m_Lock};
|
|
136
|
return m_Data[0].size();
|
|
178
|
return m_Data[0].size();
|
|
137
|
}
|
|
179
|
}
|
|
138
|
|
|
180
|
|
|
139
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
181
|
std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> &sortPermutation)
|
|
140
|
std::shared_ptr<ArrayData<Dim> > sort(const std::vector<int> sortPermutation)
|
|
|
|
|
141
|
{
|
|
182
|
{
|
|
142
|
QReadLocker locker{&m_Lock};
|
|
183
|
QReadLocker locker{&m_Lock};
|
|
|
|
|
184
|
return arraydata_detail::Sort<Dim>::sort(m_Data, sortPermutation);
|
|
|
|
|
185
|
}
|
|
143
|
|
|
186
|
|
|
144
|
const auto &data = m_Data.at(0);
|
|
187
|
// ///////////// //
|
|
145
|
|
|
188
|
// 1-dim methods //
|
|
146
|
// Inits result
|
|
189
|
// ///////////// //
|
|
147
|
auto sortedData = QVector<double>{};
|
|
|
|
|
148
|
sortedData.resize(data.size());
|
|
|
|
|
149
|
|
|
|
|
|
150
|
std::transform(sortPermutation.cbegin(), sortPermutation.cend(), sortedData.begin(),
|
|
|
|
|
151
|
[&data](int i) { return data[i]; });
|
|
|
|
|
152
|
|
|
190
|
|
|
153
|
return std::make_shared<ArrayData<Dim> >(std::move(sortedData));
|
|
191
|
/**
|
|
|
|
|
192
|
* @return the data at a specified index
|
|
|
|
|
193
|
* @remarks index must be a valid position
|
|
|
|
|
194
|
* @remarks this method is only available for a unidimensional ArrayData
|
|
|
|
|
195
|
*/
|
|
|
|
|
196
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
|
|
|
197
|
double at(int index) const noexcept
|
|
|
|
|
198
|
{
|
|
|
|
|
199
|
QReadLocker locker{&m_Lock};
|
|
|
|
|
200
|
return m_Data[0].at(index);
|
|
154
|
}
|
|
201
|
}
|
|
155
|
|
|
202
|
|
|
|
|
|
203
|
/**
|
|
|
|
|
204
|
* @return the data as a vector, as a const reference
|
|
|
|
|
205
|
* @remarks this method is only available for a unidimensional ArrayData
|
|
|
|
|
206
|
*/
|
|
156
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
207
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
157
|
void clear()
|
|
208
|
const QVector<double> &cdata() const noexcept
|
|
158
|
{
|
|
209
|
{
|
|
159
|
QWriteLocker locker{&m_Lock};
|
|
210
|
QReadLocker locker{&m_Lock};
|
|
160
|
m_Data[0].clear();
|
|
211
|
return m_Data.at(0);
|
|
161
|
}
|
|
212
|
}
|
|
162
|
|
|
213
|
|
|
|
|
|
214
|
/**
|
|
|
|
|
215
|
* @return the data as a vector
|
|
|
|
|
216
|
* @remarks this method is only available for a unidimensional ArrayData
|
|
|
|
|
217
|
*/
|
|
|
|
|
218
|
template <int D = Dim, typename = std::enable_if_t<D == 1> >
|
|
|
|
|
219
|
QVector<double> data() const noexcept
|
|
|
|
|
220
|
{
|
|
|
|
|
221
|
QReadLocker locker{&m_Lock};
|
|
|
|
|
222
|
return m_Data[0];
|
|
|
|
|
223
|
}
|
|
163
|
|
|
224
|
|
|
164
|
private:
|
|
225
|
private:
|
|
165
|
QVector<QVector<double> > m_Data;
|
|
226
|
DataContainer m_Data;
|
|
166
|
mutable QReadWriteLock m_Lock;
|
|
227
|
mutable QReadWriteLock m_Lock;
|
|
167
|
};
|
|
228
|
};
|
|
168
|
|
|
229
|
|