Fesapi 2.14.0.0
This project provides C++ classes which allow an easy access in import and export to the Energistics standards.
Loading...
Searching...
No Matches
NumberArrayStatistics.h
1/*-----------------------------------------------------------------------
2Licensed to the Apache Software Foundation (ASF) under one
3or more contributor license agreements. See the NOTICE file
4distributed with this work for additional information
5regarding copyright ownership. The ASF licenses this file
6to you under the Apache License, Version 2.0 (the
7"License"; you may not use this file except in compliance
8with the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing,
13software distributed under the License is distributed on an
14"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15KIND, either express or implied. See the License for the
16specific language governing permissions and limitations
17under the License.
18-----------------------------------------------------------------------*/
19#pragma once
20
21#if defined(__clang__)
22#elif defined(__GNUG__) && __GNUC__ > 12 // https://stackoverflow.com/questions/31509434/gcc-does-not-honor-pragma-gcc-diagnostic-to-silence-warnings
23#pragma GCC diagnostic push
24#pragma GCC diagnostic ignored "-Wmisleading-indentation"
25#endif
26#include "../proxies/gsoap_eml2_3H.h"
27#if defined(__clang__)
28#elif defined(__GNUG__) && __GNUC__ > 12
29#pragma GCC diagnostic pop
30#endif
31
32#include "../nsDefinitions.h"
33
34#if defined(_WIN32) && !defined(FESAPI_STATIC)
35#if defined(FesapiCpp_EXPORTS) || defined(FesapiCppUnderDev_EXPORTS)
36#define DLL_IMPORT_OR_EXPORT __declspec(dllexport)
37#else
38#define DLL_IMPORT_OR_EXPORT __declspec(dllimport)
39#endif
40#else
41#define DLL_IMPORT_OR_EXPORT
42#endif
43
44#include <map>
45#include <type_traits>
46#include <vector>
47
48namespace COMMON_NS
49{
50 template <typename T> class NumberArrayStatistics
51 {
52 static_assert(std::is_arithmetic_v<T>, "Template parameter T must be an integral or floating-point type.");
53 static_assert(!std::is_same_v<T, bool>, "bool is not allowed");
54 public:
55
56 NumberArrayStatistics() = default;
57
58 /*
59 * Construct statistics by computing them from an array of values
60 *
61 * @param values The array of values which the computation is based on.
62 * @param valueCount The count of values in the array.
63 * @param valueCountPerIndexableElement The number of values per indexable element. It is 1 for a scalar property.
64 * @param nullVal The integer null value. Ignored (fixed to NaN) if it is a floating point value.
65 */
66 NumberArrayStatistics(T const* values, size_t valueCount, size_t valueCountPerIndexableElement = 1, T nullVal = getDefaultNullValue())
67 : nullValue(nullVal)
68 {
69 computeFrom(values, valueCount, valueCountPerIndexableElement);
70 }
71
72 void computeFrom(T const* values, size_t valueCount, size_t valueCountPerIndexableElement) {
73 // clear existing values and set the correct dimensions
74 validValueCount = std::vector<uint64_t>(valueCountPerIndexableElement);
75 minimumValue = std::vector<T>(valueCountPerIndexableElement);
76 maximumValue = std::vector<T>(valueCountPerIndexableElement);
77 valuesMean = std::vector<double>(valueCountPerIndexableElement);
78 valuesMedian = std::vector<double>(valueCountPerIndexableElement);
79 valuesMode = std::vector<T>(valueCountPerIndexableElement);
80 modePercentage = std::vector<double>(valueCountPerIndexableElement);
81 valuesStandardDeviation = std::vector<double>(valueCountPerIndexableElement);
82
83 for (size_t j = 0; j < valueCountPerIndexableElement; ++j) {
84 std::map<T, size_t> mapView;
85 for (size_t i = j; i < valueCount; i += valueCountPerIndexableElement) {
86 if constexpr (std::is_integral_v<T>) {
87 if (values[i] != nullValue) {
88 ++validValueCount[j];
89 ++mapView[values[i]];
90 }
91 }
92 else {
93 if (!std::isnan(values[i])) {
94 ++validValueCount[j];
95 ++mapView[values[i]];
96 }
97 }
98 }
99 if (mapView.empty()) {
100 continue;
101 }
102 minimumValue[j] = mapView.begin()->first;
103 maximumValue[j] = mapView.rbegin()->first;
104
105 size_t maxCount = 0;
106 size_t mid1 = (validValueCount[j] - 1) / 2;
107 size_t mid2 = validValueCount[j] / 2;
108 size_t currentCount = 0;
109 T median1 = 0, median2 = 0;
110 bool found1 = false, found2 = false;
111 for (const auto& pair : mapView) {
112 //mode
113 if (pair.second > maxCount) {
114 maxCount = pair.second;
115 valuesMode[j] = pair.first;
116 }
117
118 //median
119 if (!found2) {
120 currentCount += pair.second;
121 if (!found1 && currentCount > mid1) {
122 median1 = pair.first;
123 found1 = true;
124 }
125 if (currentCount > mid2) {
126 median2 = pair.first;
127 found2 = true;
128 }
129 }
130
131 //mean
132 valuesMean[j] += (pair.second * pair.first) / validValueCount[j];
133 }
134 valuesMedian[j] = (validValueCount[j] % 2 == 0) ? (median1 + median2) / 2.0 : median2;
135 modePercentage[j] = static_cast<double>(maxCount) / validValueCount[j];
136
137
138 // Standard Deviation
139 double variance = 0.0;
140 for (const auto& pair : mapView) {
141 double diff = static_cast<double>(pair.first) - valuesMean[j];
142 variance += pair.second * diff * diff;
143 }
144 valuesStandardDeviation[j] = std::sqrt(variance / validValueCount[j]);
145 }
146 }
147
148 T getNullValue() const {
149 return nullValue;
150 }
151
152 uint64_t getValidValueCount(size_t valueIndex = 0) const {
153 return validValueCount.at(valueIndex);
154 }
155
156 uint64_t getValidValueCountSize() const {
157 return validValueCount.size();
158 }
159
160 T getMinimum(size_t valueIndex = 0) const {
161 return minimumValue.at(valueIndex);
162 }
163
164 uint64_t getMinimumSize() const {
165 return minimumValue.size();
166 }
167
168 T getMaximum(size_t valueIndex = 0) const {
169 return maximumValue.at(valueIndex);
170 }
171
172 uint64_t getMaximumSize() const {
173 return maximumValue.size();
174 }
175
176 double getMean(size_t valueIndex = 0) const {
177 return valuesMean.at(valueIndex);
178 }
179
180 uint64_t getMeanSize() const {
181 return valuesMean.size();
182 }
183
184 double getMedian(size_t valueIndex = 0) const {
185 return valuesMedian.at(valueIndex);
186 }
187
188 uint64_t getMedianSize() const {
189 return valuesMedian.size();
190 }
191
192 T getMode(size_t valueIndex = 0) const {
193 return valuesMode.at(valueIndex);
194 }
195
196 uint64_t getModeSize() const {
197 return valuesMode.size();
198 }
199
200 double getModePercentage(size_t valueIndex = 0) const {
201 return modePercentage.at(valueIndex);
202 }
203
204 uint64_t getModePercentageSize() const {
205 return modePercentage.size();
206 }
207
208 double getStandardDeviation(size_t valueIndex = 0) const {
209 return valuesStandardDeviation.at(valueIndex);
210 }
211
212 uint64_t getStandardDeviationSize() const {
213 return valuesStandardDeviation.size();
214 }
215
216 void setNullValue(T value) {
217 nullValue = value;
218 }
219
220 void setValidValueCount(uint64_t value, size_t valueIndex = 0) {
221 while (validValueCount.size() <= valueIndex) {
222 validValueCount.push_back((std::numeric_limits<size_t>::max)());
223 }
224 validValueCount[valueIndex] = value;
225 }
226
227 void setMinimum(T value, size_t valueIndex = 0) {
228 while (minimumValue.size() <= valueIndex) {
229 minimumValue.push_back(getDefaultNullValue());
230 }
231 minimumValue[valueIndex] = value;
232 }
233
234 void setMaximum(T value, size_t valueIndex = 0) {
235 while (maximumValue.size() <= valueIndex) {
236 maximumValue.push_back(getDefaultNullValue());
237 }
238 maximumValue[valueIndex] = value;
239 }
240
241 void setMean(double value, size_t valueIndex = 0) {
242 while (valuesMean.size() <= valueIndex) {
243 valuesMean.push_back(std::numeric_limits<double>::quiet_NaN());
244 }
245 valuesMean[valueIndex] = value;
246 }
247
248 void setMedian(double value, size_t valueIndex = 0) {
249 while (valuesMedian.size() <= valueIndex) {
250 valuesMedian.push_back(std::numeric_limits<double>::quiet_NaN());
251 }
252 valuesMedian[valueIndex] = value;
253 }
254
255 void setMode(T value, size_t valueIndex = 0) {
256 while (valuesMode.size() <= valueIndex) {
257 valuesMode.push_back(getDefaultNullValue());
258 }
259 valuesMode[valueIndex] = value;
260 }
261
262 void setModePercentage(double value, size_t valueIndex = 0) {
263 while (valuesMean.size() <= valueIndex) {
264 valuesMean.push_back(std::numeric_limits<double>::quiet_NaN());
265 }
266 valuesMean[valueIndex] = value;
267 }
268
269 void setStandardDeviation(double value, size_t valueIndex = 0) {
270 while (valuesStandardDeviation.size() <= valueIndex) {
271 valuesStandardDeviation.push_back(std::numeric_limits<double>::quiet_NaN());
272 }
273 valuesStandardDeviation[valueIndex] = value;
274 }
275
276 private:
277
278 T nullValue = getDefaultNullValue();
279 std::vector<uint64_t> validValueCount;
280 std::vector<T> minimumValue;
281 std::vector<T> maximumValue;
282 std::vector<double> valuesMean;
283 std::vector<double> valuesMedian;
284 std::vector<T> valuesMode;
285 std::vector<double> modePercentage;
286 std::vector<double> valuesStandardDeviation;
287
288 static constexpr T getDefaultNullValue() {
289 if constexpr (std::is_floating_point<T>::value) {
290 return std::numeric_limits<T>::quiet_NaN();
291 }
292 else {
293 return (std::numeric_limits<T>::max)();
294 }
295 }
296 };
297}