Mantid
Loading...
Searching...
No Matches
TableColumn.h
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2007 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7#pragma once
8
9#include <boost/numeric/conversion/cast.hpp>
10#include <cmath>
11#include <limits>
12#include <memory>
13#include <sstream>
14#include <vector>
15
16#include "MantidAPI/Column.h"
17#include "MantidDataObjects/DllConfig.h"
19#include "MantidKernel/V3D.h"
20
21namespace Mantid {
22namespace DataObjects {
23
47// Apply visibility attribute for non-MSVC builds (needed for clang/OSX).
48#if defined(_MSC_VER)
49template <class Type> class TableColumn : public API::Column {
50#else
51template <class Type> class MANTID_DATAOBJECTS_DLL TableColumn : public API::Column {
52#endif
58 InconvertibleToDoubleType(const double &) {}
60 operator double() const {
61 throw std::runtime_error(std::string("Cannot convert ") + typeid(Type).name() + " to double.");
62 }
63 operator Type() const {
64 throw std::runtime_error(std::string("Cannot convert double to ") + typeid(Type).name() + ".");
65 }
66 };
67
68public:
70 std::string name = std::string(typeid(Type).name());
71 if ((name.find('i') != std::string::npos) || (name.find('l') != std::string::npos) ||
72 (name.find('x') != std::string::npos)) {
73 if constexpr (sizeof(Type) == 4) {
74 this->m_type = "int";
75 }
76 if constexpr (sizeof(Type) == 8) {
77 this->m_type = "int64";
78 }
79 }
80 if (name.find('f') != std::string::npos) {
81 this->m_type = "float";
82 }
83 if (name.find('d') != std::string::npos) {
84 this->m_type = "double";
85 }
86 if (name.find('u') != std::string::npos) {
87 if constexpr (sizeof(Type) == 4) {
88 this->m_type = "uint32_t";
89 }
90 if constexpr (sizeof(Type) == 8) {
91 this->m_type = "uint64_t";
92 }
93 }
94 if (this->m_type.empty()) {
95 this->m_type = name;
96 }
97 }
98
99 // TableColumn();
101 size_t size() const override { return m_data.size(); }
103 const std::type_info &get_type_info() const override { return typeid(Type); }
105 const std::type_info &get_pointer_type_info() const override { return typeid(Type *); }
107 void print(size_t index, std::ostream &s) const override { s << m_data[index]; }
109 void read(size_t index, const std::string &text) override;
111 void read(const size_t index, std::istringstream &in) override;
113 bool isBool() const override { return typeid(Type) == typeid(API::Boolean); }
114 bool isNumber() const override { return std::is_convertible<Type, double>::value; }
116 long int sizeOfData() const override { return static_cast<long int>(m_data.size() * sizeof(Type)); }
118 TableColumn *clone() const override { return new TableColumn(*this); }
119
128 template <typename T> double convertToDouble(const T &value) const {
129 using DoubleType =
130 typename std::conditional<std::is_convertible<double, T>::value, T, InconvertibleToDoubleType>::type;
131 return boost::numeric_cast<double, DoubleType>(value);
132 }
133
143 double convertToDouble(const std::string &value) const { return std::stod(value); }
144
145 double toDouble(size_t i) const override { return convertToDouble(m_data[i]); }
146
156 void fromDouble(size_t i, double value) override {
157 using DoubleType =
158 typename std::conditional<std::is_convertible<double, Type>::value, Type, InconvertibleToDoubleType>::type;
159 m_data[i] = static_cast<Type>(boost::numeric_cast<DoubleType, double>(value));
160 }
161
163 std::vector<Type> &data() { return m_data; }
165 const std::vector<Type> &data() const { return m_data; }
167 Type *dataArray() { return &m_data[0]; }
168
171 double operator[](size_t i) const override {
172 try {
173 return convertToDouble(m_data[i]);
174 } catch (...) {
175 return std::numeric_limits<double>::quiet_NaN();
176 }
177 }
178
181 void sortIndex(bool ascending, size_t start, size_t end, std::vector<size_t> &indexVec,
182 std::vector<std::pair<size_t, size_t>> &equalRanges) const override;
183
185 void sortValues(const std::vector<size_t> &indexVec) override;
186
187 bool equals(const Column &otherColumn, double tolerance, bool const nanEqual = false) const override {
188 if (!possibleToCompare(otherColumn)) {
189 return false;
190 }
191 const auto &otherColumnTyped = static_cast<const TableColumn<Type> &>(otherColumn);
192 const auto &otherData = otherColumnTyped.data();
193 return compareVectors(otherData, tolerance, nanEqual);
194 }
195
196 bool equalsRelErr(const Column &otherColumn, double tolerance, bool const nanEqual = false) const override {
197 if (!possibleToCompare(otherColumn)) {
198 return false;
199 }
200 const auto &otherColumnTyped = static_cast<const TableColumn<Type> &>(otherColumn);
201 const auto &otherData = otherColumnTyped.data();
202 return compareVectorsRelError(otherData, tolerance, nanEqual);
203 }
204
205protected:
207 void resize(size_t count) override { m_data.resize(count); }
209 void insert(size_t index) override {
210 if (index < m_data.size())
211 m_data.insert(m_data.begin() + index, Type());
212 else
213 m_data.emplace_back();
214 }
216 void remove(size_t index) override { m_data.erase(m_data.begin() + index); }
218 void *void_pointer(size_t index) override { return &m_data.at(index); }
220 const void *void_pointer(size_t index) const override { return &m_data.at(index); }
221
222private:
224 std::vector<Type> m_data;
225 friend class TableWorkspace;
226
227 // helper function template for equality
228 bool compareVectors(const std::vector<Type> &newVector, double tolerance, bool const nanEqual = false) const {
229 return compareVectors(newVector, tolerance, nanEqual, std::is_integral<Type>());
230 }
231
232 bool compareVectors(const std::vector<Type> &newVector, double tolerance, bool const, std::true_type) const {
233 for (size_t i = 0; i < m_data.size(); i++) {
234 if (!Kernel::withinAbsoluteDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
235 return false;
236 }
237 }
238 return true;
239 }
240
241 bool compareVectors(const std::vector<Type> &newVector, double tolerance, bool const nanEqual,
242 std::false_type) const {
243 for (size_t i = 0; i < m_data.size(); i++) {
244 if (nanEqual && std::isnan(m_data[i]) && std::isnan(newVector[i])) {
245 continue;
246 } else if (!Kernel::withinAbsoluteDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
247 return false;
248 }
249 }
250 return true;
251 }
252
253 // helper function template for equality with relative error
254 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance, bool const nanEqual = false) const {
255 return compareVectorsRelError(newVector, tolerance, nanEqual, std::is_integral<Type>());
256 }
257
258 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance, bool const, std::true_type) const {
259 for (size_t i = 0; i < m_data.size(); i++) {
260 if (!Kernel::withinRelativeDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
261 return false;
262 }
263 }
264 return true;
265 }
266
267 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance, bool const nanEqual,
268 std::false_type) const {
269 for (size_t i = 0; i < m_data.size(); i++) {
270 if (nanEqual && std::isnan(m_data[i]) && std::isnan(newVector[i])) {
271 continue;
272 } else if (!Kernel::withinRelativeDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
273 return false;
274 }
275 }
276 return true;
277 }
278};
279
281template <>
282inline bool TableColumn<std::string>::compareVectors(const std::vector<std::string> &newVector, double,
283 bool const) const {
284 for (size_t i = 0; i < m_data.size(); i++) {
285 if (m_data[i] != newVector[i]) {
286 return false;
287 }
288 }
289 return true;
290}
291
293template <>
294inline bool TableColumn<API::Boolean>::compareVectors(const std::vector<API::Boolean> &newVector, double,
295 bool const) const {
296 for (size_t i = 0; i < m_data.size(); i++) {
297 if (!(m_data[i] == newVector[i])) {
298 return false;
299 }
300 }
301 return true;
302}
303
305template <>
306inline bool TableColumn<Kernel::V3D>::compareVectors(const std::vector<Kernel::V3D> &newVector, double tolerance,
307 bool const nanEqual) const {
308 // must specify for it to use pass-by-references
309 for (std::size_t i = 0; i < m_data.size(); i++) {
310 if (nanEqual && Kernel::V3D::isnan(m_data[i]) && Kernel::V3D::isnan(newVector[i])) {
311 continue;
312 } else if (!Kernel::withinAbsoluteDifference(m_data[i], newVector[i], tolerance)) {
313 return false;
314 }
315 }
316 return true;
317}
318
320template <>
321inline bool TableColumn<std::string>::compareVectorsRelError(const std::vector<std::string> &newVector,
322 double tolerance, bool const) const {
323 return compareVectors(newVector, tolerance);
324}
325
327template <>
328inline bool TableColumn<API::Boolean>::compareVectorsRelError(const std::vector<API::Boolean> &newVector,
329 double tolerance, bool const) const {
330 return compareVectors(newVector, tolerance);
331}
332
334template <>
335inline bool TableColumn<Kernel::V3D>::compareVectorsRelError(const std::vector<Kernel::V3D> &newVector,
336 double tolerance, bool const nanEqual) const {
337 // must specify for it to use pass-by-references
338 for (size_t i = 0; i < m_data.size(); i++) {
339 if (nanEqual && Kernel::V3D::isnan(m_data[i]) && Kernel::V3D::isnan(newVector[i])) {
340 continue;
341 } else if (!Kernel::withinRelativeDifference(m_data[i], newVector[i], tolerance)) {
342 return false;
343 }
344 }
345 return true;
346}
347
349template <> inline void TableColumn<std::string>::read(size_t index, const std::string &text) {
350 /* As opposed to other types, assigning strings via a stream does not work if
351 * it contains a whitespace character, so instead the assignment operator is
352 * used.
353 */
354 m_data[index] = text;
355}
356
358template <> inline void TableColumn<std::string>::read(size_t index, std::istringstream &text) {
359 /* As opposed to other types, assigning strings via a stream does not work if
360 * it contains a whitespace character, so instead the assignment operator is
361 * used.
362 */
363 m_data[index] = text.str();
364}
365
367template <typename Type> void TableColumn<Type>::read(size_t index, const std::string &text) {
368 std::istringstream istr(text);
369 istr >> m_data[index];
370}
371
373template <typename Type> void TableColumn<Type>::read(size_t index, std::istringstream &in) {
374 Type t;
375 in >> t;
376 m_data[index] = t;
377}
378
379namespace {
381template <typename Type> class CompareValues {
382 const std::vector<Type> &m_data;
383 const bool m_ascending;
384
385public:
386 CompareValues(const TableColumn<Type> &column, bool ascending) : m_data(column.data()), m_ascending(ascending) {}
387 bool operator()(size_t i, size_t j) {
388 return m_ascending ? m_data[i] < m_data[j] : !(m_data[i] < m_data[j] || m_data[i] == m_data[j]);
389 }
390};
391} // namespace
392
395template <typename Type>
396void TableColumn<Type>::sortIndex(bool ascending, size_t start, size_t end, std::vector<size_t> &indexVec,
397 std::vector<std::pair<size_t, size_t>> &equalRanges) const {
398 equalRanges.clear();
399
400 const size_t n = m_data.size();
401 if (n == 0) {
402 return;
403 }
404
405 auto iBegin = indexVec.begin() + start;
406 auto iEnd = indexVec.begin() + end;
407
408 std::stable_sort(iBegin, iEnd, CompareValues<Type>(*this, ascending));
409
410 bool same = false;
411 size_t eqStart = 0;
412 for (auto i = iBegin + 1; i != iEnd; ++i) {
413 if (!same) {
414 if (m_data[*i] == m_data[*(i - 1)]) {
415 eqStart = static_cast<size_t>(std::distance(indexVec.begin(), i - 1));
416 same = true;
417 }
418 } else {
419 if (m_data[*i] != m_data[*(i - 1)]) {
420 auto p = std::make_pair(eqStart, static_cast<size_t>(std::distance(indexVec.begin(), i)));
421 equalRanges.emplace_back(p);
422 same = false;
423 }
424 }
425 }
426
427 // last elements are equal
428 if (same) {
429 auto p = std::make_pair(eqStart, static_cast<size_t>(std::distance(indexVec.begin(), iEnd)));
430 equalRanges.emplace_back(p);
431 }
432}
433
435template <typename Type> void TableColumn<Type>::sortValues(const std::vector<size_t> &indexVec) {
436 assert(m_data.size() == indexVec.size());
437 std::vector<Type> sortedData(m_data.size());
438
439 auto sortedIt = sortedData.begin();
440 for (auto idx = indexVec.begin(); idx != indexVec.end(); ++idx, ++sortedIt) {
441 *sortedIt = m_data[*idx];
442 }
443
444 std::swap(m_data, sortedData);
445}
446
447template <> inline double TableColumn<API::Boolean>::toDouble(size_t i) const { return m_data[i] ? 1.0 : 0.0; }
448
449template <> inline void TableColumn<API::Boolean>::fromDouble(size_t i, double value) { m_data[i] = value != 0.0; }
450
453template <class T> class TableColumn_ptr : public std::shared_ptr<TableColumn<T>> {
454public:
458 TableColumn_ptr(std::shared_ptr<API::Column> c)
459 : std::shared_ptr<TableColumn<T>>(std::dynamic_pointer_cast<TableColumn<T>>(c)) {
460 if (!this->get()) {
461 std::string str = "Data type of column " + c->name() + " does not match " + typeid(T).name();
462 throw std::runtime_error(str);
463 }
464 }
465};
466
468template <> class TableColumn_ptr<bool> : public TableColumn_ptr<API::Boolean> {
469public:
473 TableColumn_ptr(const std::shared_ptr<API::Column> &c) : TableColumn_ptr<API::Boolean>(c) {
474 if (!this->get()) {
475 std::string str = "Data type of column " + c->name() + " does not match " + typeid(API::Boolean).name();
476 throw std::runtime_error(str);
477 }
478 }
479};
480
481} // namespace DataObjects
482} // Namespace Mantid
483
484/*
485 Macro to declare a type to be used with TableColumn.
486 DataType is the actual C++ type. TypeName is a symbolic name, used in
487 TableWorkspace::createColumn(...)
488 TypeName can contain only letters, numbers and _s.
489*/
490#define DECLARE_TABLECOLUMN(DataType, TypeName) \
491 namespace { \
492 Mantid::Kernel::RegistrationHelper register_column_##TypeName( \
493 (Mantid::API::ColumnFactory::Instance().subscribe<Mantid::DataObjects::TableColumn<DataType>>(#TypeName), 0)); \
494 }
std::string name
Definition Run.cpp:60
double value
The value of the point.
Definition FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
int count
counter
Definition Matrix.cpp:37
double tolerance
const std::vector< Type > & m_data
const bool m_ascending
size_t iEnd
Column is the base class for columns of TableWorkspace.
Definition Column.h:35
const std::string & name() const
Name (caption) of the column.
Definition Column.h:43
TableColumn_ptr(const std::shared_ptr< API::Column > &c)
Constructor.
Shared pointer to a column with automatic type cast and data type check.
TableColumn_ptr(std::shared_ptr< API::Column > c)
Constructor.
Class TableColumn implements abstract class Column for any copyable data type.
Definition TableColumn.h:51
bool compareVectors(const std::vector< Type > &newVector, double tolerance, bool const nanEqual=false) const
long int sizeOfData() const override
Memory used by the column.
void read(const size_t index, std::istringstream &in) override
Read in from stream and set the value at the given index.
double operator[](size_t i) const override
return a value casted to double; the users responsibility is to be sure, that the casting is possible
void remove(size_t index) override
Removes an item at index.
void resize(size_t count) override
Resize.
bool isNumber() const override
Are elements of the column interpretable as a number?
void sortValues(const std::vector< size_t > &indexVec) override
Re-arrange values in this column according to indices in indexVec.
const std::vector< Type > & data() const
Const reference to the data.
size_t size() const override
Number of individual elements in the column.
bool compareVectors(const std::vector< Type > &newVector, double tolerance, bool const, std::true_type) const
void print(size_t index, std::ostream &s) const override
Output to an ostream.
bool isBool() const override
Type check.
void read(size_t index, const std::string &text) override
Read in a string and set the value at the given index.
void * void_pointer(size_t index) override
Returns a pointer to the data element.
void insert(size_t index) override
Inserts default value at position index.
Type * dataArray()
Pointer to the data array.
bool equals(const Column &otherColumn, double tolerance, bool const nanEqual=false) const override
TableColumn * clone() const override
Clone.
std::vector< Type > & data()
Reference to the data.
bool compareVectorsRelError(const std::vector< Type > &newVector, double tolerance, bool const nanEqual=false) const
bool equalsRelErr(const Column &otherColumn, double tolerance, bool const nanEqual=false) const override
void fromDouble(size_t i, double value) override
Cast an element to double if possible.
bool compareVectorsRelError(const std::vector< Type > &newVector, double tolerance, bool const nanEqual, std::false_type) const
const void * void_pointer(size_t index) const override
Returns a pointer to the data element.
void sortIndex(bool ascending, size_t start, size_t end, std::vector< size_t > &indexVec, std::vector< std::pair< size_t, size_t > > &equalRanges) const override
Sort a vector of indices according to values in corresponding cells of this column.
const std::type_info & get_pointer_type_info() const override
Type id of the pointer to data in the column.
bool compareVectorsRelError(const std::vector< Type > &newVector, double tolerance, bool const, std::true_type) const
bool compareVectors(const std::vector< Type > &newVector, double tolerance, bool const nanEqual, std::false_type) const
double convertToDouble(const std::string &value) const
Cast an string to double if possible.
const std::type_info & get_type_info() const override
Type id of the data in the column.
double convertToDouble(const T &value) const
Cast an element to double if possible.
std::vector< Type > m_data
Column data.
double toDouble(size_t i) const override
Cast an element to double if possible.
TableWorkspace is an implementation of Workspace in which the data are organised in columns of same s...
static bool isnan(V3D const &vec)
Determine if a V3D can be considered nan.
Definition V3D.h:337
MANTID_KERNEL_DLL bool withinRelativeDifference(T const x, T const y, S const tolerance)
Test whether x, y are within relative tolerance tol.
MANTID_KERNEL_DLL bool withinAbsoluteDifference(T const x, T const y, S const tolerance)
Test whether x, y are within absolute tolerance tol.
Helper class which provides the Collimation Length for SANS instruments.
STL namespace.
As TableColumn stores its data in a std::vector bool type cannot be used in the same way as the other...
Definition Column.h:213
Helper struct helping to write a generic casting to double.
Definition TableColumn.h:54