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
21using ParsedRationalNumber = boost::fusion::vector<int, boost::optional<int>>;
22
24public:
26 // Fill direction map
27 m_directions.emplace("x", V3R(1, 0, 0));
28 m_directions.emplace("y", V3R(0, 1, 0));
29 m_directions.emplace("z", V3R(0, 0, 1));
30
31 // Initialize all other members correctly and consistently
32 reset();
33 }
34
37 template <typename T> MatrixVectorPair<T, V3R> getMatrixVectorPair() const {
38 if (m_currentRow < 2) {
39 throw std::runtime_error("Less than three rows were processed by MatrixVectorPairBuilder.");
40 }
41
42 std::vector<T> typedMatrixElements;
43 for (const auto &rb : m_matrixRows) {
44 typedMatrixElements.emplace_back(boost::rational_cast<T>((rb).x()));
45 typedMatrixElements.emplace_back(boost::rational_cast<T>((rb).y()));
46 typedMatrixElements.emplace_back(boost::rational_cast<T>((rb).z()));
47 }
48 Kernel::Matrix<T> mat(typedMatrixElements);
49
51 }
52
55 void setCurrentFactor(const ParsedRationalNumber &rationalNumberComponents) {
56 int numerator = boost::fusion::at_c<0>(rationalNumberComponents);
57 boost::optional<int> denominator = boost::fusion::at_c<1>(rationalNumberComponents);
58
59 if (denominator.is_initialized()) {
60 if (denominator.get() == 0) {
61 throw std::runtime_error("Zero denominator is not allowed in MatrixVectorPair-strings.");
62 }
63
64 m_currentFactor = RationalNumber(numerator, denominator.get());
65 } else {
67 }
68 }
69
72 void setCurrentDirection(const std::string &vector) { m_currentDirection = m_directions[vector]; }
73
76
79
97 if (m_currentRow > m_matrixRows.size()) {
98 throw std::runtime_error("MatrixVectorPair can not have more than 3 rows.");
99 }
100
102
103 if (m_currentDirection != V3R(0, 0, 0)) {
105 } else {
107 }
108
109 resetState();
110 }
111
113 void advanceRow() {
114 ++m_currentRow;
115 resetState();
116 }
117
119 void reset() {
120 resetState();
122 }
123
125 void resetState() {
127 m_currentDirection = V3R(0, 0, 0);
128 m_currentSign = 1;
129 }
130
133 m_matrixRows = std::vector<V3R>(3);
134 m_vector = V3R(0, 0, 0);
135 m_currentRow = 0;
136 }
137
138private:
139 std::map<std::string, V3R> m_directions;
140
141 std::vector<V3R> m_matrixRows;
143
147
149};
150
151using boost::spirit::qi::grammar;
152using boost::spirit::qi::rule;
153
172template <typename Iterator> class MatrixVectorPairParser : public grammar<Iterator, boost::spirit::qi::space_type> {
173public:
175
176 using boost::spirit::unused_type;
177
178 namespace qi = boost::spirit::qi;
179
180 using qi::int_;
181 using qi::lit;
182 using qi::uint_;
183
184 /* MSVC currently has some problems using std::bind in connection
185 * with boost::spirit in some circumstances, but they can be circumvented
186 * using lambda-expressions as a sort of call proxy. For consistency,
187 * all semantic parse actions are formulated like that.
188 */
189 auto positiveSignAction = [&builder](unused_type, unused_type, unused_type) { builder.setCurrentSignPositive(); };
190
191 auto negativeSignAction = [&builder](unused_type, unused_type, unused_type) { builder.setCurrentSignNegative(); };
192
193 auto currentFactorAction = [&builder](const ParsedRationalNumber &rationalNumberComponents, unused_type,
194 unused_type) { builder.setCurrentFactor(rationalNumberComponents); };
195
196 auto currentDirectionAction = [&builder](const std::string &s, unused_type, unused_type) {
197 builder.setCurrentDirection(s);
198 };
199
200 auto addCurrentStateToResultAction = [&builder](unused_type, unused_type, unused_type) {
201 builder.addCurrentStateToResult();
202 };
203
204 auto advanceRowAction = [&builder](unused_type, unused_type, unused_type) { builder.advanceRow(); };
205
206 // Switch sign in the builder
207 m_sign = lit('+')[positiveSignAction] | lit('-')[negativeSignAction];
208
209 // This matches a rational number (also things like -1/-2 -> 1/2)
210 m_rational = (int_ >> -('/' >> int_))[currentFactorAction];
211
212 // Matches x, y or z.
213 m_direction = (qi::string("x") | qi::string("y") | qi::string("z"))[currentDirectionAction];
214
215 /* A "component", which is either a rational number possibly followed by a
216 * vector definition. Examples:
217 * 2/3, -2/3, -2/-3, -4, 2, -2x, 3y, 4/5z, ...
218 * Or a vector possibly preceded by a sign:
219 * z, -y, +x
220 */
222
223 // One row of the matrix/vector pair can have many such "components".
224 m_componentSeries = m_component[addCurrentStateToResultAction] >> *(m_component[addCurrentStateToResultAction]);
225
226 // The entire matrix/vector pair is defined by three comma separated of
227 // those component strings.
228 m_parser = (m_componentSeries >> lit(',')[advanceRowAction] >> m_componentSeries >> lit(',')[advanceRowAction] >>
230 }
231
232 rule<Iterator, boost::spirit::qi::space_type> m_sign, m_rational, m_direction, m_component, m_componentSeries,
234};
235
238template <typename T> MatrixVectorPair<T, V3R> parseMatrixVectorPair(const std::string &matrixVectorString) {
239
240 namespace qi = boost::spirit::qi;
241
242 auto strIterator = matrixVectorString.cbegin();
243 auto strEnd = matrixVectorString.cend();
244
247
248 try {
249 qi::phrase_parse(strIterator, strEnd, parser, qi::space);
250
251 if (std::distance(strIterator, strEnd) > 0) {
252 throw std::runtime_error("Additional characters at end of string: '" + std::string(strIterator, strEnd) + "'.");
253 }
254 } catch (std::runtime_error &builderError) {
255 throw Kernel::Exception::ParseError("Parse error: " + std::string(builderError.what()), matrixVectorString, 0);
256 }
257
258 return builder.getMatrixVectorPair<T>();
259}
260
261} // namespace Geometry
262} // 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.