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 "MantidKernel/V3D.h"
18
19namespace Mantid {
20namespace DataObjects {
21
45template <class Type> class TableColumn : public API::Column {
51 InconvertibleToDoubleType(const double &) {}
53 operator double() const {
54 throw std::runtime_error(std::string("Cannot convert ") + typeid(Type).name() + " to double.");
55 }
56 operator Type() const {
57 throw std::runtime_error(std::string("Cannot convert double to ") + typeid(Type).name() + ".");
58 }
59 };
60
61public:
63 int length = sizeof(Type);
64 std::string name = std::string(typeid(Type).name());
65 if ((name.find('i') != std::string::npos) || (name.find('l') != std::string::npos) ||
66 (name.find('x') != std::string::npos)) {
67 if (length == 4) {
68 this->m_type = "int";
69 }
70 if (length == 8) {
71 this->m_type = "int64";
72 }
73 }
74 if (name.find('f') != std::string::npos) {
75 this->m_type = "float";
76 }
77 if (name.find('d') != std::string::npos) {
78 this->m_type = "double";
79 }
80 if (name.find('u') != std::string::npos) {
81 if (length == 4) {
82 this->m_type = "uint32_t";
83 }
84 if (length == 8) {
85 this->m_type = "uint64_t";
86 }
87 }
88 if (this->m_type.empty()) {
89 this->m_type = name;
90 }
91 }
92
93 // TableColumn();
95 size_t size() const override { return m_data.size(); }
97 const std::type_info &get_type_info() const override { return typeid(Type); }
99 const std::type_info &get_pointer_type_info() const override { return typeid(Type *); }
101 void print(size_t index, std::ostream &s) const override { s << m_data[index]; }
103 void read(size_t index, const std::string &text) override;
105 void read(const size_t index, std::istringstream &in) override;
107 bool isBool() const override { return typeid(Type) == typeid(API::Boolean); }
108 bool isNumber() const override { return std::is_convertible<Type, double>::value; }
110 long int sizeOfData() const override { return static_cast<long int>(m_data.size() * sizeof(Type)); }
112 TableColumn *clone() const override { return new TableColumn(*this); }
113
122 template <typename T> double convertToDouble(const T &value) const {
123 using DoubleType =
124 typename std::conditional<std::is_convertible<double, T>::value, T, InconvertibleToDoubleType>::type;
125 return boost::numeric_cast<double, DoubleType>(value);
126 }
127
137 double convertToDouble(const std::string &value) const { return std::stod(value); }
138
139 double toDouble(size_t i) const override { return convertToDouble(m_data[i]); }
140
150 void fromDouble(size_t i, double value) override {
151 using DoubleType =
152 typename std::conditional<std::is_convertible<double, Type>::value, Type, InconvertibleToDoubleType>::type;
153 m_data[i] = static_cast<Type>(boost::numeric_cast<DoubleType, double>(value));
154 }
155
157 std::vector<Type> &data() { return m_data; }
159 const std::vector<Type> &data() const { return m_data; }
161 Type *dataArray() { return &m_data[0]; }
162
165 double operator[](size_t i) const override {
166 try {
167 return convertToDouble(m_data[i]);
168 } catch (...) {
169 return std::numeric_limits<double>::quiet_NaN();
170 }
171 }
172
175 void sortIndex(bool ascending, size_t start, size_t end, std::vector<size_t> &indexVec,
176 std::vector<std::pair<size_t, size_t>> &equalRanges) const override;
177
179 void sortValues(const std::vector<size_t> &indexVec) override;
180
181 bool equals(const Column &otherColumn, double tolerance) const override {
182 if (!possibleToCompare(otherColumn)) {
183 return false;
184 }
185 const auto &otherColumnTyped = static_cast<const TableColumn<Type> &>(otherColumn);
186 const auto &otherData = otherColumnTyped.data();
187 return compareVectors(otherData, tolerance);
188 }
189
190 bool equalsRelErr(const Column &otherColumn, double tolerance) const override {
191 if (!possibleToCompare(otherColumn)) {
192 return false;
193 }
194 const auto &otherColumnTyped = static_cast<const TableColumn<Type> &>(otherColumn);
195 const auto &otherData = otherColumnTyped.data();
196 return compareVectorsRelError(otherData, tolerance);
197 }
198
199protected:
201 void resize(size_t count) override { m_data.resize(count); }
203 void insert(size_t index) override {
204 if (index < m_data.size())
205 m_data.insert(m_data.begin() + index, Type());
206 else
207 m_data.emplace_back();
208 }
210 void remove(size_t index) override { m_data.erase(m_data.begin() + index); }
212 void *void_pointer(size_t index) override { return &m_data.at(index); }
214 const void *void_pointer(size_t index) const override { return &m_data.at(index); }
215
216private:
218 std::vector<Type> m_data;
219 friend class TableWorkspace;
220
221 // helper function template for equality
222 bool compareVectors(const std::vector<Type> &newVector, double tolerance) const {
223 for (size_t i = 0; i < m_data.size(); i++) {
224 if (fabs((double)m_data[i] - (double)newVector[i]) > tolerance) {
225 return false;
226 }
227 }
228 return true;
229 }
230
231 // helper function template for equality with relative error
232 bool compareVectorsRelError(const std::vector<Type> &newVector, double tolerance) const {
233 for (size_t i = 0; i < m_data.size(); i++) {
234 double num = fabs((double)m_data[i] - (double)newVector[i]);
235 double den = (fabs((double)m_data[i]) + fabs((double)newVector[i])) / 2;
236 if (den < tolerance && num > tolerance) {
237 return false;
238 } else if (num / den > tolerance) {
239 return false;
240 }
241 }
242 return true;
243 }
244};
246template <>
247inline bool TableColumn<int64_t>::compareVectors(const std::vector<int64_t> &newVector, double tolerance) const {
248 int64_t roundedTol = llround(tolerance);
249 for (size_t i = 0; i < m_data.size(); i++) {
250 if (std::llabs(m_data[i] - newVector[i]) > roundedTol) {
251 return false;
252 }
253 }
254 return true;
255}
256
258template <>
259inline bool TableColumn<unsigned long>::compareVectors(const std::vector<unsigned long> &newVector,
260 double tolerance) const {
261 long long roundedTol = llround(tolerance);
262 for (size_t i = 0; i < m_data.size(); i++) {
263 if (std::llabs((long long)m_data[i] - (long long)newVector[i]) > roundedTol) {
264 return false;
265 }
266 }
267 return true;
268}
269
271template <>
272inline bool TableColumn<std::string>::compareVectors(const std::vector<std::string> &newVector,
273 double tolerance) const {
274 (void)tolerance;
275 for (size_t i = 0; i < m_data.size(); i++) {
276 if (m_data[i] != newVector[i]) {
277 return false;
278 }
279 }
280 return true;
281}
282
284template <>
285inline bool TableColumn<API::Boolean>::compareVectors(const std::vector<API::Boolean> &newVector,
286 double tolerance) const {
287 (void)tolerance;
288 for (size_t i = 0; i < m_data.size(); i++) {
289 if (!(m_data[i] == newVector[i])) {
290 return false;
291 }
292 }
293 return true;
294}
295
297template <>
298inline bool TableColumn<Kernel::V3D>::compareVectors(const std::vector<Kernel::V3D> &newVector,
299 double tolerance) const {
300 for (size_t i = 0; i < m_data.size(); i++) {
301 double dif_x = fabs(m_data[i].X() - newVector[i].X());
302 double dif_y = fabs(m_data[i].Y() - newVector[i].Y());
303 double dif_z = fabs(m_data[i].Z() - newVector[i].Z());
304 if (dif_x > tolerance || dif_y > tolerance || dif_z > tolerance) {
305 return false;
306 }
307 }
308 return true;
309}
310
312template <>
313inline bool TableColumn<int64_t>::compareVectorsRelError(const std::vector<int64_t> &newVector,
314 double tolerance) const {
315 int64_t roundedTol = llround(tolerance);
316 for (size_t i = 0; i < m_data.size(); i++) {
317 int64_t num = llabs(m_data[i] - newVector[i]);
318 int64_t den = (llabs(m_data[i]) + llabs(newVector[i])) / 2;
319 if (den < roundedTol && num > roundedTol) {
320 return false;
321 } else if (num / den > roundedTol) {
322 return false;
323 }
324 }
325 return true;
326}
327
329template <>
330inline bool TableColumn<unsigned long>::compareVectorsRelError(const std::vector<unsigned long> &newVector,
331 double tolerance) const {
332 long long roundedTol = lround(tolerance);
333 for (size_t i = 0; i < m_data.size(); i++) {
334 long long num = labs((long long)m_data[i] - (long long)newVector[i]);
335 long long den = (m_data[i] + newVector[i]) / 2;
336 if (den < roundedTol && num > roundedTol) {
337 return false;
338 } else if (num / den > roundedTol) {
339 return false;
340 }
341 }
342 return true;
343}
344
346template <>
347inline bool TableColumn<std::string>::compareVectorsRelError(const std::vector<std::string> &newVector,
348 double tolerance) const {
349 return compareVectors(newVector, tolerance);
350}
351
353template <>
354inline bool TableColumn<API::Boolean>::compareVectorsRelError(const std::vector<API::Boolean> &newVector,
355 double tolerance) const {
356 return compareVectors(newVector, tolerance);
357}
358
360template <>
361inline bool TableColumn<Kernel::V3D>::compareVectorsRelError(const std::vector<Kernel::V3D> &newVector,
362 double tolerance) const {
363 for (size_t i = 0; i < m_data.size(); i++) {
364 double dif_x = fabs(m_data[i].X() - newVector[i].X());
365 double dif_y = fabs(m_data[i].Y() - newVector[i].Y());
366 double dif_z = fabs(m_data[i].Z() - newVector[i].Z());
367 double den_x = 0.5 * (fabs(m_data[i].X()) + fabs(newVector[i].X()));
368 double den_y = 0.5 * (fabs(m_data[i].X()) + fabs(newVector[i].X()));
369 double den_z = 0.5 * (fabs(m_data[i].X()) + fabs(newVector[i].X()));
370 if (den_x > tolerance || den_y > tolerance || den_z > tolerance) {
371 if (dif_x / den_x > tolerance || dif_y / den_y > tolerance || dif_z / den_z > tolerance) {
372 return false;
373 }
374 } else {
375 if (dif_x > tolerance || dif_y > tolerance || dif_z > tolerance) {
376 return false;
377 }
378 }
379 }
380 return true;
381}
382
384template <> inline void TableColumn<std::string>::read(size_t index, const std::string &text) {
385 /* As opposed to other types, assigning strings via a stream does not work if
386 * it contains a whitespace character, so instead the assignment operator is
387 * used.
388 */
389 m_data[index] = text;
390}
391
393template <> inline void TableColumn<std::string>::read(size_t index, std::istringstream &text) {
394 /* As opposed to other types, assigning strings via a stream does not work if
395 * it contains a whitespace character, so instead the assignment operator is
396 * used.
397 */
398 m_data[index] = text.str();
399}
400
402template <typename Type> void TableColumn<Type>::read(size_t index, const std::string &text) {
403 std::istringstream istr(text);
404 istr >> m_data[index];
405}
406
408template <typename Type> void TableColumn<Type>::read(size_t index, std::istringstream &in) {
409 Type t;
410 in >> t;
411 m_data[index] = t;
412}
413
414namespace {
416template <typename Type> class CompareValues {
417 const std::vector<Type> &m_data;
418 const bool m_ascending;
419
420public:
421 CompareValues(const TableColumn<Type> &column, bool ascending) : m_data(column.data()), m_ascending(ascending) {}
422 bool operator()(size_t i, size_t j) {
423 return m_ascending ? m_data[i] < m_data[j] : !(m_data[i] < m_data[j] || m_data[i] == m_data[j]);
424 }
425};
426} // namespace
427
430template <typename Type>
431void TableColumn<Type>::sortIndex(bool ascending, size_t start, size_t end, std::vector<size_t> &indexVec,
432 std::vector<std::pair<size_t, size_t>> &equalRanges) const {
433 equalRanges.clear();
434
435 const size_t n = m_data.size();
436 if (n == 0) {
437 return;
438 }
439
440 auto iBegin = indexVec.begin() + start;
441 auto iEnd = indexVec.begin() + end;
442
443 std::stable_sort(iBegin, iEnd, CompareValues<Type>(*this, ascending));
444
445 bool same = false;
446 size_t eqStart = 0;
447 for (auto i = iBegin + 1; i != iEnd; ++i) {
448 if (!same) {
449 if (m_data[*i] == m_data[*(i - 1)]) {
450 eqStart = static_cast<size_t>(std::distance(indexVec.begin(), i - 1));
451 same = true;
452 }
453 } else {
454 if (m_data[*i] != m_data[*(i - 1)]) {
455 auto p = std::make_pair(eqStart, static_cast<size_t>(std::distance(indexVec.begin(), i)));
456 equalRanges.emplace_back(p);
457 same = false;
458 }
459 }
460 }
461
462 // last elements are equal
463 if (same) {
464 auto p = std::make_pair(eqStart, static_cast<size_t>(std::distance(indexVec.begin(), iEnd)));
465 equalRanges.emplace_back(p);
466 }
467}
468
470template <typename Type> void TableColumn<Type>::sortValues(const std::vector<size_t> &indexVec) {
471 assert(m_data.size() == indexVec.size());
472 std::vector<Type> sortedData(m_data.size());
473
474 auto sortedIt = sortedData.begin();
475 for (auto idx = indexVec.begin(); idx != indexVec.end(); ++idx, ++sortedIt) {
476 *sortedIt = m_data[*idx];
477 }
478
479 std::swap(m_data, sortedData);
480}
481
482template <> inline double TableColumn<API::Boolean>::toDouble(size_t i) const { return m_data[i] ? 1.0 : 0.0; }
483
484template <> inline void TableColumn<API::Boolean>::fromDouble(size_t i, double value) { m_data[i] = value != 0.0; }
485
488template <class T> class TableColumn_ptr : public std::shared_ptr<TableColumn<T>> {
489public:
493 TableColumn_ptr(std::shared_ptr<API::Column> c)
494 : std::shared_ptr<TableColumn<T>>(std::dynamic_pointer_cast<TableColumn<T>>(c)) {
495 if (!this->get()) {
496 std::string str = "Data type of column " + c->name() + " does not match " + typeid(T).name();
497 throw std::runtime_error(str);
498 }
499 }
500};
501
503template <> class TableColumn_ptr<bool> : public TableColumn_ptr<API::Boolean> {
504public:
508 TableColumn_ptr(const std::shared_ptr<API::Column> &c) : TableColumn_ptr<API::Boolean>(c) {
509 if (!this->get()) {
510 std::string str = "Data type of column " + c->name() + " does not match " + typeid(API::Boolean).name();
511 throw std::runtime_error(str);
512 }
513 }
514};
515
516} // namespace DataObjects
517} // Namespace Mantid
518
519/*
520 Macro to declare a type to be used with TableColumn.
521 DataType is the actual C++ type. TypeName is a symbolic name, used in
522 TableWorkspace::createColumn(...)
523 TypeName can contain only letters, numbers and _s.
524*/
525#define DECLARE_TABLECOLUMN(DataType, TypeName) \
526 namespace { \
527 Mantid::Kernel::RegistrationHelper register_column_##TypeName( \
528 (Mantid::API::ColumnFactory::Instance().subscribe<Mantid::DataObjects::TableColumn<DataType>>(#TypeName), 0)); \
529 }
double value
The value of the point.
Definition: FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define fabs(x)
Definition: Matrix.cpp:22
int count
counter
Definition: Matrix.cpp:37
double tolerance
const std::vector< Type > & m_data
Definition: TableColumn.h:417
const bool m_ascending
Definition: TableColumn.h:418
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:176
std::string m_type
type
Definition: Column.h:186
const std::string & name() const
Name (caption) of the column.
Definition: Column.h:43
TableColumn_ptr(const std::shared_ptr< API::Column > &c)
Constructor.
Definition: TableColumn.h:508
Shared pointer to a column with automatic type cast and data type check.
Definition: TableColumn.h:488
TableColumn_ptr(std::shared_ptr< API::Column > c)
Constructor.
Definition: TableColumn.h:493
Class TableColumn implements abstract class Column for any copyable data type.
Definition: TableColumn.h:45
long int sizeOfData() const override
Memory used by the column.
Definition: TableColumn.h:110
void read(const size_t index, std::istringstream &in) override
Read in from stream and set the value at the given index.
Definition: TableColumn.h:408
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
Definition: TableColumn.h:165
void remove(size_t index) override
Removes an item at index.
Definition: TableColumn.h:210
void resize(size_t count) override
Resize.
Definition: TableColumn.h:201
bool isNumber() const override
Are elements of the column interpretable as a number?
Definition: TableColumn.h:108
void sortValues(const std::vector< size_t > &indexVec) override
Re-arrange values in this column according to indices in indexVec.
Definition: TableColumn.h:470
const std::vector< Type > & data() const
Const reference to the data.
Definition: TableColumn.h:159
size_t size() const override
Number of individual elements in the column.
Definition: TableColumn.h:95
bool compareVectors(const std::vector< Type > &newVector, double tolerance) const
Definition: TableColumn.h:222
void print(size_t index, std::ostream &s) const override
Output to an ostream.
Definition: TableColumn.h:101
bool isBool() const override
Type check.
Definition: TableColumn.h:107
void read(size_t index, const std::string &text) override
Read in a string and set the value at the given index.
Definition: TableColumn.h:402
void * void_pointer(size_t index) override
Returns a pointer to the data element.
Definition: TableColumn.h:212
void insert(size_t index) override
Inserts default value at position index.
Definition: TableColumn.h:203
Type * dataArray()
Pointer to the data array.
Definition: TableColumn.h:161
TableColumn * clone() const override
Clone.
Definition: TableColumn.h:112
std::vector< Type > & data()
Reference to the data.
Definition: TableColumn.h:157
void fromDouble(size_t i, double value) override
Cast an element to double if possible.
Definition: TableColumn.h:150
bool equals(const Column &otherColumn, double tolerance) const override
Definition: TableColumn.h:181
const void * void_pointer(size_t index) const override
Returns a pointer to the data element.
Definition: TableColumn.h:214
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.
Definition: TableColumn.h:431
const std::type_info & get_pointer_type_info() const override
Type id of the pointer to data in the column.
Definition: TableColumn.h:99
bool compareVectorsRelError(const std::vector< Type > &newVector, double tolerance) const
Definition: TableColumn.h:232
double convertToDouble(const std::string &value) const
Cast an string to double if possible.
Definition: TableColumn.h:137
bool equalsRelErr(const Column &otherColumn, double tolerance) const override
Definition: TableColumn.h:190
const std::type_info & get_type_info() const override
Type id of the data in the column.
Definition: TableColumn.h:97
double convertToDouble(const T &value) const
Cast an element to double if possible.
Definition: TableColumn.h:122
std::vector< Type > m_data
Column data.
Definition: TableColumn.h:218
double toDouble(size_t i) const override
Cast an element to double if possible.
Definition: TableColumn.h:139
TableWorkspace is an implementation of Workspace in which the data are organised in columns of same s...
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:209
Helper struct helping to write a generic casting to double.
Definition: TableColumn.h:47