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 int length = sizeof(Type);
71 std::string name = std::string(typeid(Type).name());
72 if ((name.find('i') != std::string::npos) || (name.find('l') != std::string::npos) ||
73 (name.find('x') != std::string::npos)) {
74 if (length == 4) {
75 this->m_type = "int";
76 }
77 if (length == 8) {
78 this->m_type = "int64";
79 }
80 }
81 if (name.find('f') != std::string::npos) {
82 this->m_type = "float";
83 }
84 if (name.find('d') != std::string::npos) {
85 this->m_type = "double";
86 }
87 if (name.find('u') != std::string::npos) {
88 if (length == 4) {
89 this->m_type = "uint32_t";
90 }
91 if (length == 8) {
92 this->m_type = "uint64_t";
93 }
94 }
95 if (this->m_type.empty()) {
96 this->m_type = name;
97 }
98 }
99
100 // TableColumn();
102 size_t size() const override { return m_data.size(); }
104 const std::type_info &get_type_info() const override { return typeid(Type); }
106 const std::type_info &get_pointer_type_info() const override { return typeid(Type *); }
108 void print(size_t index, std::ostream &s) const override { s << m_data[index]; }
110 void read(size_t index, const std::string &text) override;
112 void read(const size_t index, std::istringstream &in) override;
114 bool isBool() const override { return typeid(Type) == typeid(API::Boolean); }
115 bool isNumber() const override { return std::is_convertible<Type, double>::value; }
117 long int sizeOfData() const override { return static_cast<long int>(m_data.size() * sizeof(Type)); }
119 TableColumn *clone() const override { return new TableColumn(*this); }
120
129 template <typename T> double convertToDouble(const T &value) const {
130 using DoubleType =
131 typename std::conditional<std::is_convertible<double, T>::value, T, InconvertibleToDoubleType>::type;
132 return boost::numeric_cast<double, DoubleType>(value);
133 }
134
144 double convertToDouble(const std::string &value) const { return std::stod(value); }
145
146 double toDouble(size_t i) const override { return convertToDouble(m_data[i]); }
147
157 void fromDouble(size_t i, double value) override {
158 using DoubleType =
159 typename std::conditional<std::is_convertible<double, Type>::value, Type, InconvertibleToDoubleType>::type;
160 m_data[i] = static_cast<Type>(boost::numeric_cast<DoubleType, double>(value));
161 }
162
164 std::vector<Type> &data() { return m_data; }
166 const std::vector<Type> &data() const { return m_data; }
168 Type *dataArray() { return &m_data[0]; }
169
172 double operator[](size_t i) const override {
173 try {
174 return convertToDouble(m_data[i]);
175 } catch (...) {
176 return std::numeric_limits<double>::quiet_NaN();
177 }
178 }
179
182 void sortIndex(bool ascending, size_t start, size_t end, std::vector<size_t> &indexVec,
183 std::vector<std::pair<size_t, size_t>> &equalRanges) const override;
184
186 void sortValues(const std::vector<size_t> &indexVec) override;
187
188 bool equals(const Column &otherColumn, double tolerance, bool const nanEqual = false) const override {
189 if (!possibleToCompare(otherColumn)) {
190 return false;
191 }
192 const auto &otherColumnTyped = static_cast<const TableColumn<Type> &>(otherColumn);
193 const auto &otherData = otherColumnTyped.data();
194 return compareVectors(otherData, tolerance, nanEqual);
195 }
196
197 bool equalsRelErr(const Column &otherColumn, double tolerance, bool const nanEqual = false) const override {
198 if (!possibleToCompare(otherColumn)) {
199 return false;
200 }
201 const auto &otherColumnTyped = static_cast<const TableColumn<Type> &>(otherColumn);
202 const auto &otherData = otherColumnTyped.data();
203 return compareVectorsRelError(otherData, tolerance, nanEqual);
204 }
205
206protected:
208 void resize(size_t count) override { m_data.resize(count); }
210 void insert(size_t index) override {
211 if (index < m_data.size())
212 m_data.insert(m_data.begin() + index, Type());
213 else
214 m_data.emplace_back();
215 }
217 void remove(size_t index) override { m_data.erase(m_data.begin() + index); }
219 void *void_pointer(size_t index) override { return &m_data.at(index); }
221 const void *void_pointer(size_t index) const override { return &m_data.at(index); }
222
223private:
225 std::vector<Type> m_data;
226 friend class TableWorkspace;
227
228 // helper function template for equality
229 bool compareVectors(const std::vector<Type> &newVector, double tolerance, bool const nanEqual = false) const {
230 return compareVectors(newVector, tolerance, nanEqual, std::is_integral<Type>());
231 }
232
233 bool compareVectors(const std::vector<Type> &newVector, double tolerance, bool const, std::true_type) const {
234 for (size_t i = 0; i < m_data.size(); i++) {
235 if (!Kernel::withinAbsoluteDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
236 return false;
237 }
238 }
239 return true;
240 }
241
242 bool compareVectors(const std::vector<Type> &newVector, double tolerance, bool const nanEqual,
243 std::false_type) const {
244 for (size_t i = 0; i < m_data.size(); i++) {
245 if (nanEqual && std::isnan(m_data[i]) && std::isnan(newVector[i])) {
246 continue;
247 } else if (!Kernel::withinAbsoluteDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
248 return false;
249 }
250 }
251 return true;
252 }
253
254 // helper function template for equality with relative error
255 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance, bool const nanEqual = false) const {
256 return compareVectorsRelError(newVector, tolerance, nanEqual, std::is_integral<Type>());
257 }
258
259 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance, bool const, std::true_type) const {
260 for (size_t i = 0; i < m_data.size(); i++) {
261 if (!Kernel::withinRelativeDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
262 return false;
263 }
264 }
265 return true;
266 }
267
268 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance, bool const nanEqual,
269 std::false_type) const {
270 for (size_t i = 0; i < m_data.size(); i++) {
271 if (nanEqual && std::isnan(m_data[i]) && std::isnan(newVector[i])) {
272 continue;
273 } else if (!Kernel::withinRelativeDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
274 return false;
275 }
276 }
277 return true;
278 }
279};
280
282template <>
283inline bool TableColumn<std::string>::compareVectors(const std::vector<std::string> &newVector, double,
284 bool const) const {
285 for (size_t i = 0; i < m_data.size(); i++) {
286 if (m_data[i] != newVector[i]) {
287 return false;
288 }
289 }
290 return true;
291}
292
294template <>
295inline bool TableColumn<API::Boolean>::compareVectors(const std::vector<API::Boolean> &newVector, double,
296 bool const) const {
297 for (size_t i = 0; i < m_data.size(); i++) {
298 if (!(m_data[i] == newVector[i])) {
299 return false;
300 }
301 }
302 return true;
303}
304
306template <>
307inline bool TableColumn<Kernel::V3D>::compareVectors(const std::vector<Kernel::V3D> &newVector, double tolerance,
308 bool const nanEqual) const {
309 // must specify for it to use pass-by-references
310 for (std::size_t i = 0; i < m_data.size(); i++) {
311 if (nanEqual && Kernel::V3D::isnan(m_data[i]) && Kernel::V3D::isnan(newVector[i])) {
312 continue;
313 } else if (!Kernel::withinAbsoluteDifference(m_data[i], newVector[i], tolerance)) {
314 return false;
315 }
316 }
317 return true;
318}
319
321template <>
322inline bool TableColumn<std::string>::compareVectorsRelError(const std::vector<std::string> &newVector,
323 double tolerance, bool const) const {
324 return compareVectors(newVector, tolerance);
325}
326
328template <>
329inline bool TableColumn<API::Boolean>::compareVectorsRelError(const std::vector<API::Boolean> &newVector,
330 double tolerance, bool const) const {
331 return compareVectors(newVector, tolerance);
332}
333
335template <>
336inline bool TableColumn<Kernel::V3D>::compareVectorsRelError(const std::vector<Kernel::V3D> &newVector,
337 double tolerance, bool const nanEqual) const {
338 // must specify for it to use pass-by-references
339 for (size_t i = 0; i < m_data.size(); i++) {
340 if (nanEqual && Kernel::V3D::isnan(m_data[i]) && Kernel::V3D::isnan(newVector[i])) {
341 continue;
342 } else if (!Kernel::withinRelativeDifference(m_data[i], newVector[i], tolerance)) {
343 return false;
344 }
345 }
346 return true;
347}
348
350template <> inline void TableColumn<std::string>::read(size_t index, const std::string &text) {
351 /* As opposed to other types, assigning strings via a stream does not work if
352 * it contains a whitespace character, so instead the assignment operator is
353 * used.
354 */
355 m_data[index] = text;
356}
357
359template <> inline void TableColumn<std::string>::read(size_t index, std::istringstream &text) {
360 /* As opposed to other types, assigning strings via a stream does not work if
361 * it contains a whitespace character, so instead the assignment operator is
362 * used.
363 */
364 m_data[index] = text.str();
365}
366
368template <typename Type> void TableColumn<Type>::read(size_t index, const std::string &text) {
369 std::istringstream istr(text);
370 istr >> m_data[index];
371}
372
374template <typename Type> void TableColumn<Type>::read(size_t index, std::istringstream &in) {
375 Type t;
376 in >> t;
377 m_data[index] = t;
378}
379
380namespace {
382template <typename Type> class CompareValues {
383 const std::vector<Type> &m_data;
384 const bool m_ascending;
385
386public:
387 CompareValues(const TableColumn<Type> &column, bool ascending) : m_data(column.data()), m_ascending(ascending) {}
388 bool operator()(size_t i, size_t j) {
389 return m_ascending ? m_data[i] < m_data[j] : !(m_data[i] < m_data[j] || m_data[i] == m_data[j]);
390 }
391};
392} // namespace
393
396template <typename Type>
397void TableColumn<Type>::sortIndex(bool ascending, size_t start, size_t end, std::vector<size_t> &indexVec,
398 std::vector<std::pair<size_t, size_t>> &equalRanges) const {
399 equalRanges.clear();
400
401 const size_t n = m_data.size();
402 if (n == 0) {
403 return;
404 }
405
406 auto iBegin = indexVec.begin() + start;
407 auto iEnd = indexVec.begin() + end;
408
409 std::stable_sort(iBegin, iEnd, CompareValues<Type>(*this, ascending));
410
411 bool same = false;
412 size_t eqStart = 0;
413 for (auto i = iBegin + 1; i != iEnd; ++i) {
414 if (!same) {
415 if (m_data[*i] == m_data[*(i - 1)]) {
416 eqStart = static_cast<size_t>(std::distance(indexVec.begin(), i - 1));
417 same = true;
418 }
419 } else {
420 if (m_data[*i] != m_data[*(i - 1)]) {
421 auto p = std::make_pair(eqStart, static_cast<size_t>(std::distance(indexVec.begin(), i)));
422 equalRanges.emplace_back(p);
423 same = false;
424 }
425 }
426 }
427
428 // last elements are equal
429 if (same) {
430 auto p = std::make_pair(eqStart, static_cast<size_t>(std::distance(indexVec.begin(), iEnd)));
431 equalRanges.emplace_back(p);
432 }
433}
434
436template <typename Type> void TableColumn<Type>::sortValues(const std::vector<size_t> &indexVec) {
437 assert(m_data.size() == indexVec.size());
438 std::vector<Type> sortedData(m_data.size());
439
440 auto sortedIt = sortedData.begin();
441 for (auto idx = indexVec.begin(); idx != indexVec.end(); ++idx, ++sortedIt) {
442 *sortedIt = m_data[*idx];
443 }
444
445 std::swap(m_data, sortedData);
446}
447
448template <> inline double TableColumn<API::Boolean>::toDouble(size_t i) const { return m_data[i] ? 1.0 : 0.0; }
449
450template <> inline void TableColumn<API::Boolean>::fromDouble(size_t i, double value) { m_data[i] = value != 0.0; }
451
454template <class T> class TableColumn_ptr : public std::shared_ptr<TableColumn<T>> {
455public:
459 TableColumn_ptr(std::shared_ptr<API::Column> c)
460 : std::shared_ptr<TableColumn<T>>(std::dynamic_pointer_cast<TableColumn<T>>(c)) {
461 if (!this->get()) {
462 std::string str = "Data type of column " + c->name() + " does not match " + typeid(T).name();
463 throw std::runtime_error(str);
464 }
465 }
466};
467
469template <> class TableColumn_ptr<bool> : public TableColumn_ptr<API::Boolean> {
470public:
474 TableColumn_ptr(const std::shared_ptr<API::Column> &c) : TableColumn_ptr<API::Boolean>(c) {
475 if (!this->get()) {
476 std::string str = "Data type of column " + c->name() + " does not match " + typeid(API::Boolean).name();
477 throw std::runtime_error(str);
478 }
479 }
480};
481
482} // namespace DataObjects
483} // Namespace Mantid
484
485/*
486 Macro to declare a type to be used with TableColumn.
487 DataType is the actual C++ type. TypeName is a symbolic name, used in
488 TableWorkspace::createColumn(...)
489 TypeName can contain only letters, numbers and _s.
490*/
491#define DECLARE_TABLECOLUMN(DataType, TypeName) \
492 namespace { \
493 Mantid::Kernel::RegistrationHelper register_column_##TypeName( \
494 (Mantid::API::ColumnFactory::Instance().subscribe<Mantid::DataObjects::TableColumn<DataType>>(#TypeName), 0)); \
495 }
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