Mantid
Loading...
Searching...
No Matches
MatrixVectorPairParser.h
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2015 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
11#include "MantidGeometry/DllConfig.h"
12
14#include <boost/spirit/include/qi.hpp>
15#include <functional>
16#include <map>
17
18namespace Mantid {
19namespace Geometry {
20
21// TODO moving from boost::optional to std::optoinal in this file is non-trivial
22using ParsedRationalNumber = boost::fusion::vector<int, boost::optional<int>>;
23
25public:
27 // Fill direction map
28 m_directions.emplace("x", V3R(1, 0, 0));
29 m_directions.emplace("y", V3R(0, 1, 0));
30 m_directions.emplace("z", V3R(0, 0, 1));
31
32 // Initialize all other members correctly and consistently
33 reset();
34 }
35
38 template <typename T> MatrixVectorPair<T, V3R> getMatrixVectorPair() const {
39 if (m_currentRow < 2) {
40 throw std::runtime_error("Less than three rows were processed by MatrixVectorPairBuilder.");
41 }
42
43 std::vector<T> typedMatrixElements;
44 for (const auto &rb : m_matrixRows) {
45 typedMatrixElements.emplace_back(boost::rational_cast<T>((rb).x()));
46 typedMatrixElements.emplace_back(boost::rational_cast<T>((rb).y()));
47 typedMatrixElements.emplace_back(boost::rational_cast<T>((rb).z()));
48 }
49 Kernel::Matrix<T> mat(typedMatrixElements);
50
52 }
53
56 void setCurrentFactor(const ParsedRationalNumber &rationalNumberComponents) {
57 int numerator = boost::fusion::at_c<0>(rationalNumberComponents);
58 boost::optional<int> denominator = boost::fusion::at_c<1>(rationalNumberComponents);
59
60 if (denominator.is_initialized()) {
61 if (denominator.get() == 0) {
62 throw std::runtime_error("Zero denominator is not allowed in MatrixVectorPair-strings.");
63 }
64
65 m_currentFactor = RationalNumber(numerator, denominator.get());
66 } else {
68 }
69 }
70
73 void setCurrentDirection(const std::string &vector) { m_currentDirection = m_directions[vector]; }
74
77
80
98 if (m_currentRow > m_matrixRows.size()) {
99 throw std::runtime_error("MatrixVectorPair can not have more than 3 rows.");
100 }
101
103
104 if (m_currentDirection != V3R(0, 0, 0)) {
106 } else {
108 }
109
110 resetState();
111 }
112
114 void advanceRow() {
115 ++m_currentRow;
116 resetState();
117 }
118
120 void reset() {
121 resetState();
123 }
124
126 void resetState() {
128 m_currentDirection = V3R(0, 0, 0);
129 m_currentSign = 1;
130 }
131
134 m_matrixRows = std::vector<V3R>(3);
135 m_vector = V3R(0, 0, 0);
136 m_currentRow = 0;
137 }
138
139private:
140 std::map<std::string, V3R> m_directions;
141
142 std::vector<V3R> m_matrixRows;
144
148
150};
151
152using boost::spirit::qi::grammar;
153using boost::spirit::qi::rule;
154
173template <typename Iterator> class MatrixVectorPairParser : public grammar<Iterator, boost::spirit::qi::space_type> {
174public:
176
177 using boost::spirit::unused_type;
178
179 namespace qi = boost::spirit::qi;
180
181 using qi::int_;
182 using qi::lit;
183 using qi::uint_;
184
185 /* MSVC currently has some problems using std::bind in connection
186 * with boost::spirit in some circumstances, but they can be circumvented
187 * using lambda-expressions as a sort of call proxy. For consistency,
188 * all semantic parse actions are formulated like that.
189 */
190 auto positiveSignAction = [&builder](unused_type, unused_type, unused_type) { builder.setCurrentSignPositive(); };
191
192 auto negativeSignAction = [&builder](unused_type, unused_type, unused_type) { builder.setCurrentSignNegative(); };
193
194 auto currentFactorAction = [&builder](const ParsedRationalNumber &rationalNumberComponents, unused_type,
195 unused_type) { builder.setCurrentFactor(rationalNumberComponents); };
196
197 auto currentDirectionAction = [&builder](const std::string &s, unused_type, unused_type) {
198 builder.setCurrentDirection(s);
199 };
200
201 auto addCurrentStateToResultAction = [&builder](unused_type, unused_type, unused_type) {
202 builder.addCurrentStateToResult();
203 };
204
205 auto advanceRowAction = [&builder](unused_type, unused_type, unused_type) { builder.advanceRow(); };
206
207 // Switch sign in the builder
208 m_sign = lit('+')[positiveSignAction] | lit('-')[negativeSignAction];
209
210 // This matches a rational number (also things like -1/-2 -> 1/2)
211 m_rational = (int_ >> -('/' >> int_))[currentFactorAction];
212
213 // Matches x, y or z.
214 m_direction = (qi::string("x") | qi::string("y") | qi::string("z"))[currentDirectionAction];
215
216 /* A "component", which is either a rational number possibly followed by a
217 * vector definition. Examples:
218 * 2/3, -2/3, -2/-3, -4, 2, -2x, 3y, 4/5z, ...
219 * Or a vector possibly preceded by a sign:
220 * z, -y, +x
221 */
223
224 // One row of the matrix/vector pair can have many such "components".
225 m_componentSeries = m_component[addCurrentStateToResultAction] >> *(m_component[addCurrentStateToResultAction]);
226
227 // The entire matrix/vector pair is defined by three comma separated of
228 // those component strings.
229 m_parser = (m_componentSeries >> lit(',')[advanceRowAction] >> m_componentSeries >> lit(',')[advanceRowAction] >>
231 }
232
233 rule<Iterator, boost::spirit::qi::space_type> m_sign, m_rational, m_direction, m_component, m_componentSeries,
235};
236
239template <typename T> MatrixVectorPair<T, V3R> parseMatrixVectorPair(const std::string &matrixVectorString) {
240
241 namespace qi = boost::spirit::qi;
242
243 auto strIterator = matrixVectorString.cbegin();
244 auto strEnd = matrixVectorString.cend();
245
248
249 try {
250 qi::phrase_parse(strIterator, strEnd, parser, qi::space);
251
252 if (std::distance(strIterator, strEnd) > 0) {
253 throw std::runtime_error("Additional characters at end of string: '" + std::string(strIterator, strEnd) + "'.");
254 }
255 } catch (std::runtime_error &builderError) {
256 throw Kernel::Exception::ParseError("Parse error: " + std::string(builderError.what()), matrixVectorString, 0);
257 }
258
259 return builder.getMatrixVectorPair<T>();
260}
261
262} // namespace Geometry
263} // namespace Mantid
void setCurrentDirection(const std::string &vector)
Set the direction vector to one of the stored values that correspond to x, y or z.
MatrixVectorPair< T, V3R > getMatrixVectorPair() const
Construct and return the actual matrix/vector pair, the rational matrix components are castd to T.
void setCurrentSignNegative()
Make the current sign negative.
void reset()
Completely reset the builder, including stored preliminary results.
void advanceRow()
Advance to the next row of the matrix/vector pair.
void resetState()
Reset the current state, i.e. the state representing the current row.
void addCurrentStateToResult()
Adds currently stored state to the parse result.
void setCurrentSignPositive()
Make the current sign positive.
void setCurrentFactor(const ParsedRationalNumber &rationalNumberComponents)
Set the current factor, which is a rational number.
void resetAccumulatedResults()
Reset all accumulated results.
rule< Iterator, boost::spirit::qi::space_type > m_component
rule< Iterator, boost::spirit::qi::space_type > m_rational
MatrixVectorPairParser(MatrixVectorPairBuilder &builder)
rule< Iterator, boost::spirit::qi::space_type > m_sign
rule< Iterator, boost::spirit::qi::space_type > m_direction
rule< Iterator, boost::spirit::qi::space_type > m_parser
rule< Iterator, boost::spirit::qi::space_type > m_componentSeries
Records the filename, the description of failure and the line on which it happened.
Definition Exception.h:115
Numerical Matrix class.
Definition Matrix.h:42
boost::rational< int > RationalNumber
V3R :
Definition V3R.h:35
boost::fusion::vector< int, boost::optional< int > > ParsedRationalNumber
MatrixVectorPair< T, V3R > parseMatrixVectorPair(const std::string &matrixVectorString)
Tries to parse the given string.
Helper class which provides the Collimation Length for SANS instruments.