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"
18#include "MantidKernel/V3D.h"
19
20namespace Mantid {
21namespace DataObjects {
22
46template <class Type> class TableColumn : public API::Column {
52 InconvertibleToDoubleType(const double &) {}
54 operator double() const {
55 throw std::runtime_error(std::string("Cannot convert ") + typeid(Type).name() + " to double.");
56 }
57 operator Type() const {
58 throw std::runtime_error(std::string("Cannot convert double to ") + typeid(Type).name() + ".");
59 }
60 };
61
62public:
64 int length = sizeof(Type);
65 std::string name = std::string(typeid(Type).name());
66 if ((name.find('i') != std::string::npos) || (name.find('l') != std::string::npos) ||
67 (name.find('x') != std::string::npos)) {
68 if (length == 4) {
69 this->m_type = "int";
70 }
71 if (length == 8) {
72 this->m_type = "int64";
73 }
74 }
75 if (name.find('f') != std::string::npos) {
76 this->m_type = "float";
77 }
78 if (name.find('d') != std::string::npos) {
79 this->m_type = "double";
80 }
81 if (name.find('u') != std::string::npos) {
82 if (length == 4) {
83 this->m_type = "uint32_t";
84 }
85 if (length == 8) {
86 this->m_type = "uint64_t";
87 }
88 }
89 if (this->m_type.empty()) {
90 this->m_type = name;
91 }
92 }
93
94 // TableColumn();
96 size_t size() const override { return m_data.size(); }
98 const std::type_info &get_type_info() const override { return typeid(Type); }
100 const std::type_info &get_pointer_type_info() const override { return typeid(Type *); }
102 void print(size_t index, std::ostream &s) const override { s << m_data[index]; }
104 void read(size_t index, const std::string &text) override;
106 void read(const size_t index, std::istringstream &in) override;
108 bool isBool() const override { return typeid(Type) == typeid(API::Boolean); }
109 bool isNumber() const override { return std::is_convertible<Type, double>::value; }
111 long int sizeOfData() const override { return static_cast<long int>(m_data.size() * sizeof(Type)); }
113 TableColumn *clone() const override { return new TableColumn(*this); }
114
123 template <typename T> double convertToDouble(const T &value) const {
124 using DoubleType =
125 typename std::conditional<std::is_convertible<double, T>::value, T, InconvertibleToDoubleType>::type;
126 return boost::numeric_cast<double, DoubleType>(value);
127 }
128
138 double convertToDouble(const std::string &value) const { return std::stod(value); }
139
140 double toDouble(size_t i) const override { return convertToDouble(m_data[i]); }
141
151 void fromDouble(size_t i, double value) override {
152 using DoubleType =
153 typename std::conditional<std::is_convertible<double, Type>::value, Type, InconvertibleToDoubleType>::type;
154 m_data[i] = static_cast<Type>(boost::numeric_cast<DoubleType, double>(value));
155 }
156
158 std::vector<Type> &data() { return m_data; }
160 const std::vector<Type> &data() const { return m_data; }
162 Type *dataArray() { return &m_data[0]; }
163
166 double operator[](size_t i) const override {
167 try {
168 return convertToDouble(m_data[i]);
169 } catch (...) {
170 return std::numeric_limits<double>::quiet_NaN();
171 }
172 }
173
176 void sortIndex(bool ascending, size_t start, size_t end, std::vector<size_t> &indexVec,
177 std::vector<std::pair<size_t, size_t>> &equalRanges) const override;
178
180 void sortValues(const std::vector<size_t> &indexVec) override;
181
182 bool equals(const Column &otherColumn, double tolerance, bool const nanEqual = false) const override {
183 if (!possibleToCompare(otherColumn)) {
184 return false;
185 }
186 const auto &otherColumnTyped = static_cast<const TableColumn<Type> &>(otherColumn);
187 const auto &otherData = otherColumnTyped.data();
188 return compareVectors(otherData, tolerance, nanEqual);
189 }
190
191 bool equalsRelErr(const Column &otherColumn, double tolerance, bool const nanEqual = false) const override {
192 if (!possibleToCompare(otherColumn)) {
193 return false;
194 }
195 const auto &otherColumnTyped = static_cast<const TableColumn<Type> &>(otherColumn);
196 const auto &otherData = otherColumnTyped.data();
197 return compareVectorsRelError(otherData, tolerance, nanEqual);
198 }
199
200protected:
202 void resize(size_t count) override { m_data.resize(count); }
204 void insert(size_t index) override {
205 if (index < m_data.size())
206 m_data.insert(m_data.begin() + index, Type());
207 else
208 m_data.emplace_back();
209 }
211 void remove(size_t index) override { m_data.erase(m_data.begin() + index); }
213 void *void_pointer(size_t index) override { return &m_data.at(index); }
215 const void *void_pointer(size_t index) const override { return &m_data.at(index); }
216
217private:
219 std::vector<Type> m_data;
220 friend class TableWorkspace;
221
222 // helper function template for equality
223 bool compareVectors(const std::vector<Type> &newVector, double tolerance, bool const nanEqual = false) const {
224 return compareVectors(newVector, tolerance, nanEqual, std::is_integral<Type>());
225 }
226
227 bool compareVectors(const std::vector<Type> &newVector, double tolerance, bool const, std::true_type) const {
228 for (size_t i = 0; i < m_data.size(); i++) {
229 if (!Kernel::withinAbsoluteDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
230 return false;
231 }
232 }
233 return true;
234 }
235
236 bool compareVectors(const std::vector<Type> &newVector, double tolerance, bool const nanEqual,
237 std::false_type) const {
238 for (size_t i = 0; i < m_data.size(); i++) {
239 if (nanEqual && std::isnan(m_data[i]) && std::isnan(newVector[i])) {
240 continue;
241 } else if (!Kernel::withinAbsoluteDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
242 return false;
243 }
244 }
245 return true;
246 }
247
248 // helper function template for equality with relative error
249 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance, bool const nanEqual = false) const {
250 return compareVectorsRelError(newVector, tolerance, nanEqual, std::is_integral<Type>());
251 }
252
253 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance, bool const, std::true_type) const {
254 for (size_t i = 0; i < m_data.size(); i++) {
255 if (!Kernel::withinRelativeDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
256 return false;
257 }
258 }
259 return true;
260 }
261
262 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance, bool const nanEqual,
263 std::false_type) const {
264 for (size_t i = 0; i < m_data.size(); i++) {
265 if (nanEqual && std::isnan(m_data[i]) && std::isnan(newVector[i])) {
266 continue;
267 } else if (!Kernel::withinRelativeDifference<Type, double>(m_data[i], newVector[i], tolerance)) {
268 return false;
269 }
270 }
271 return true;
272 }
273};
274
276template <>
277inline bool TableColumn<std::string>::compareVectors(const std::vector<std::string> &newVector, double,
278 bool const) const {
279 for (size_t i = 0; i < m_data.size(); i++) {
280 if (m_data[i] != newVector[i]) {
281 return false;
282 }
283 }
284 return true;
285}
286
288template <>
289inline bool TableColumn<API::Boolean>::compareVectors(const std::vector<API::Boolean> &newVector, double,
290 bool const) const {
291 for (size_t i = 0; i < m_data.size(); i++) {
292 if (!(m_data[i] == newVector[i])) {
293 return false;
294 }
295 }
296 return true;
297}
298
300template <>
301inline bool TableColumn<Kernel::V3D>::compareVectors(const std::vector<Kernel::V3D> &newVector, double tolerance,
302 bool const nanEqual) const {
303 // must specify for it to use pass-by-references
304 for (std::size_t i = 0; i < m_data.size(); i++) {
305 if (nanEqual && Kernel::V3D::isnan(m_data[i]) && Kernel::V3D::isnan(newVector[i])) {
306 continue;
307 } else if (!Kernel::withinAbsoluteDifference(m_data[i], newVector[i], tolerance)) {
308 return false;
309 }
310 }
311 return true;
312}
313
315template <>
316inline bool TableColumn<std::string>::compareVectorsRelError(const std::vector<std::string> &newVector,
317 double tolerance, bool const) const {
318 return compareVectors(newVector, tolerance);
319}
320
322template <>
323inline bool TableColumn<API::Boolean>::compareVectorsRelError(const std::vector<API::Boolean> &newVector,
324 double tolerance, bool const) const {
325 return compareVectors(newVector, tolerance);
326}
327
329template <>
330inline bool TableColumn<Kernel::V3D>::compareVectorsRelError(const std::vector<Kernel::V3D> &newVector,
331 double tolerance, bool const nanEqual) const {
332 // must specify for it to use pass-by-references
333 for (size_t i = 0; i < m_data.size(); i++) {
334 if (nanEqual && Kernel::V3D::isnan(m_data[i]) && Kernel::V3D::isnan(newVector[i])) {
335 continue;
336 } else if (!Kernel::withinRelativeDifference(m_data[i], newVector[i], tolerance)) {
337 return false;
338 }
339 }
340 return true;
341}
342
344template <> inline void TableColumn<std::string>::read(size_t index, const std::string &text) {
345 /* As opposed to other types, assigning strings via a stream does not work if
346 * it contains a whitespace character, so instead the assignment operator is
347 * used.
348 */
349 m_data[index] = text;
350}
351
353template <> inline void TableColumn<std::string>::read(size_t index, std::istringstream &text) {
354 /* As opposed to other types, assigning strings via a stream does not work if
355 * it contains a whitespace character, so instead the assignment operator is
356 * used.
357 */
358 m_data[index] = text.str();
359}
360
362template <typename Type> void TableColumn<Type>::read(size_t index, const std::string &text) {
363 std::istringstream istr(text);
364 istr >> m_data[index];
365}
366
368template <typename Type> void TableColumn<Type>::read(size_t index, std::istringstream &in) {
369 Type t;
370 in >> t;
371 m_data[index] = t;
372}
373
374namespace {
376template <typename Type> class CompareValues {
377 const std::vector<Type> &m_data;
378 const bool m_ascending;
379
380public:
381 CompareValues(const TableColumn<Type> &column, bool ascending) : m_data(column.data()), m_ascending(ascending) {}
382 bool operator()(size_t i, size_t j) {
383 return m_ascending ? m_data[i] < m_data[j] : !(m_data[i] < m_data[j] || m_data[i] == m_data[j]);
384 }
385};
386} // namespace
387
390template <typename Type>
391void TableColumn<Type>::sortIndex(bool ascending, size_t start, size_t end, std::vector<size_t> &indexVec,
392 std::vector<std::pair<size_t, size_t>> &equalRanges) const {
393 equalRanges.clear();
394
395 const size_t n = m_data.size();
396 if (n == 0) {
397 return;
398 }
399
400 auto iBegin = indexVec.begin() + start;
401 auto iEnd = indexVec.begin() + end;
402
403 std::stable_sort(iBegin, iEnd, CompareValues<Type>(*this, ascending));
404
405 bool same = false;
406 size_t eqStart = 0;
407 for (auto i = iBegin + 1; i != iEnd; ++i) {
408 if (!same) {
409 if (m_data[*i] == m_data[*(i - 1)]) {
410 eqStart = static_cast<size_t>(std::distance(indexVec.begin(), i - 1));
411 same = true;
412 }
413 } else {
414 if (m_data[*i] != m_data[*(i - 1)]) {
415 auto p = std::make_pair(eqStart, static_cast<size_t>(std::distance(indexVec.begin(), i)));
416 equalRanges.emplace_back(p);
417 same = false;
418 }
419 }
420 }
421
422 // last elements are equal
423 if (same) {
424 auto p = std::make_pair(eqStart, static_cast<size_t>(std::distance(indexVec.begin(), iEnd)));
425 equalRanges.emplace_back(p);
426 }
427}
428
430template <typename Type> void TableColumn<Type>::sortValues(const std::vector<size_t> &indexVec) {
431 assert(m_data.size() == indexVec.size());
432 std::vector<Type> sortedData(m_data.size());
433
434 auto sortedIt = sortedData.begin();
435 for (auto idx = indexVec.begin(); idx != indexVec.end(); ++idx, ++sortedIt) {
436 *sortedIt = m_data[*idx];
437 }
438
439 std::swap(m_data, sortedData);
440}
441
442template <> inline double TableColumn<API::Boolean>::toDouble(size_t i) const { return m_data[i] ? 1.0 : 0.0; }
443
444template <> inline void TableColumn<API::Boolean>::fromDouble(size_t i, double value) { m_data[i] = value != 0.0; }
445
448template <class T> class TableColumn_ptr : public std::shared_ptr<TableColumn<T>> {
449public:
453 TableColumn_ptr(std::shared_ptr<API::Column> c)
454 : std::shared_ptr<TableColumn<T>>(std::dynamic_pointer_cast<TableColumn<T>>(c)) {
455 if (!this->get()) {
456 std::string str = "Data type of column " + c->name() + " does not match " + typeid(T).name();
457 throw std::runtime_error(str);
458 }
459 }
460};
461
463template <> class TableColumn_ptr<bool> : public TableColumn_ptr<API::Boolean> {
464public:
468 TableColumn_ptr(const std::shared_ptr<API::Column> &c) : TableColumn_ptr<API::Boolean>(c) {
469 if (!this->get()) {
470 std::string str = "Data type of column " + c->name() + " does not match " + typeid(API::Boolean).name();
471 throw std::runtime_error(str);
472 }
473 }
474};
475
476} // namespace DataObjects
477} // Namespace Mantid
478
479/*
480 Macro to declare a type to be used with TableColumn.
481 DataType is the actual C++ type. TypeName is a symbolic name, used in
482 TableWorkspace::createColumn(...)
483 TypeName can contain only letters, numbers and _s.
484*/
485#define DECLARE_TABLECOLUMN(DataType, TypeName) \
486 namespace { \
487 Mantid::Kernel::RegistrationHelper register_column_##TypeName( \
488 (Mantid::API::ColumnFactory::Instance().subscribe<Mantid::DataObjects::TableColumn<DataType>>(#TypeName), 0)); \
489 }
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 & type() const
Type of the column data.
Definition Column.h:46
bool possibleToCompare(const Column &otherColumn) const
Definition Column.h:180
std::string m_type
type
Definition Column.h:190
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:46
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.
Definition TableColumn.h:96
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.
Definition TableColumn.h:98
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:48