Belle II Software development
NodeFactory.h
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#pragma once
10#include <memory>
11#include <framework/utilities/CutHelpers.h>
12#include <framework/utilities/CutNodes.h>
13#include <framework/logging/Logger.h>
14
15#include <boost/python/tuple.hpp>
16#include <boost/python/extract.hpp>
17#include <boost/algorithm/string.hpp>
18
19namespace py = boost::python;
20typedef const py::tuple& Nodetuple;
21
22namespace Belle2 {
31 template<class AVariableManager>
32 class UnaryBooleanNode;
33
34 template<class AVariableManager>
35 class BinaryBooleanNode;
36
37 template<class AVariableManager>
38 class UnaryRelationalNode;
39
40 template<class AVariableManager>
41 class BinaryRelationalNode;
42
43 template<class AVariableManager>
44 class TernaryRelationalNode;
45
46 template<class AVariableManager>
47 class UnaryExpressionNode;
48
49 template<class AVariableManager>
50 class BinaryExpressionNode;
51
52 template<class AVariableManager, typename T>
53 class DataNode;
54
55 template<class AVariableManager>
56 class IdentifierNode;
57
58 template<class AVariableManager>
59 class FunctionNode;
60
65 public:
79 template<class AVariableManager>
80 static std::unique_ptr<const AbstractBooleanNode<AVariableManager>> compile_boolean_node(Nodetuple tuple)
81 {
82 if (py::len(tuple) == 0) B2FATAL("BooleanNode tuple is empty, this is invalid.");
83 // First argument of every NodeTuple is an integer indicating the NodeType
84 NodeType node_type = static_cast<NodeType>(static_cast<int>(py::extract<int>(tuple[0])));
85
86 if (node_type == NodeType::UnaryBooleanNode) {
87 // Extract first child tuple
88 if (py::len(tuple) != 4) B2FATAL("UnaryBooleanNode tuple has to have length 4." << LogVar("actual length", py::len(tuple)));
89 Nodetuple child = static_cast<const py::tuple>(tuple[1]);
90 bool negation = py::extract<bool>(tuple[2]);
91 bool bracketized = py::extract<bool>(tuple[3]);
92 return std::unique_ptr<const AbstractBooleanNode<AVariableManager>>(new UnaryBooleanNode<AVariableManager>(child, negation,
93 bracketized));
94
95 } else if (node_type == NodeType::BinaryBooleanNode) {
96 if (py::len(tuple) != 4) B2FATAL("BinaryBooleanNode tuple has to have length 4." << LogVar("actual length", py::len(tuple)));
97 Nodetuple left_node = static_cast<const py::tuple>(tuple[1]);
98 Nodetuple right_node = static_cast<const py::tuple>(tuple[2]);
99 BooleanOperator boperator = static_cast<BooleanOperator>(static_cast<int>(py::extract<int>(tuple[3])));
100 return std::unique_ptr<const AbstractBooleanNode<AVariableManager>>(new BinaryBooleanNode<AVariableManager>(left_node, right_node,
101 boperator));
102 } else if (node_type == NodeType::UnaryRelationalNode) {
103 if (py::len(tuple) != 2) B2FATAL("UnaryRelationalNode tuple has to have length 2." << LogVar("actual length", py::len(tuple)));
104 Nodetuple node = static_cast<const py::tuple>(tuple[1]);
105 return std::unique_ptr<const AbstractBooleanNode<AVariableManager>>(new UnaryRelationalNode<AVariableManager>(node));
106 } else if (node_type == NodeType::BinaryRelationalNode) {
107 if (py::len(tuple) != 4) B2FATAL("BinaryRelationalNode tuple has to have length 4." << LogVar("actual length", py::len(tuple)));
108 Nodetuple left_node = static_cast<const py::tuple>(tuple[1]);
109 Nodetuple right_node = static_cast<const py::tuple>(tuple[2]);
110 ComparisonOperator coperator = static_cast<ComparisonOperator>(static_cast<int>(py::extract<int>(tuple[3])));
111 return std::unique_ptr<const AbstractBooleanNode<AVariableManager>>(new BinaryRelationalNode<AVariableManager>(left_node,
112 right_node, coperator));
113 } else if (node_type == NodeType::TernaryRelationalNode) {
114 if (py::len(tuple) != 6) B2FATAL("TernaryRelationalNode tuple has to have length 6." << LogVar("actual length", py::len(tuple)));
115 Nodetuple left_node = static_cast<const py::tuple>(tuple[1]);
116 Nodetuple center_node = static_cast<const py::tuple>(tuple[2]);
117 Nodetuple right_node = static_cast<const py::tuple>(tuple[3]);
118 ComparisonOperator lc_coperator = static_cast<ComparisonOperator>(static_cast<int>(py::extract<int>(tuple[4])));
119 ComparisonOperator cr_coperator = static_cast<ComparisonOperator>(static_cast<int>(py::extract<int>(tuple[5])));
120
121 return std::unique_ptr<const AbstractBooleanNode<AVariableManager>>(new TernaryRelationalNode<AVariableManager>(left_node,
122 center_node, right_node,
123 lc_coperator, cr_coperator));
124 } else {
125 throw std::runtime_error("error NodeFactory::compile_boolean_node: got invalid boolean NodeType.");
126 }
127 }
140 template<class AVariableManager>
141 static std::unique_ptr<const AbstractExpressionNode<AVariableManager>> compile_expression_node(Nodetuple tuple)
142 {
143 if (py::len(tuple) == 0) B2FATAL("ExpressionNode tuple is empty, this is invalid.");
144
145 // int is extracted from the py::tuple and cast as NodeTuple enum
146 NodeType node_type = static_cast<NodeType>(static_cast<int>(py::extract<int>(tuple[0])));
147 if (node_type == NodeType::UnaryExpressionNode) {
148 if (py::len(tuple) != 4) B2FATAL("UnaryExpression nodetuple has to have length 4." << LogVar("actual length", py::len(tuple)));
149 Nodetuple node = static_cast<const py::tuple>(tuple[1]);
150 bool unary_minus = py::extract<bool>(tuple[2]);
151 bool parenthesized = py::extract<bool>(tuple[3]);
152 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new UnaryExpressionNode<AVariableManager>(node,
153 unary_minus, parenthesized));
154 } else if (node_type == NodeType::BinaryExpressionNode) {
155 if (py::len(tuple) != 4) B2FATAL("BinaryExpression nodetuple has to have length 4." << LogVar("actual length", py::len(tuple)));
156 Nodetuple left_node = static_cast<const py::tuple>(tuple[1]);
157 Nodetuple right_node = static_cast<const py::tuple>(tuple[2]);
158 ArithmeticOperation aoperation = static_cast<ArithmeticOperation>(static_cast<int>(py::extract<int>(tuple[3])));
159 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new BinaryExpressionNode<AVariableManager>(left_node,
160 right_node,
161 aoperation));
162 } else if (node_type == NodeType::IntegerNode) {
163 if (py::len(tuple) != 2) B2FATAL("IntegerNode nodetuple has to have length 2." << LogVar("actual length", py::len(tuple)));
164 double d = py::extract<double>(tuple[1]);
165 if (std::numeric_limits<int>::min() <= d && d <= std::numeric_limits<int>::max()) {
166 int i = py::extract<int>(tuple[1]);
167 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new DataNode<AVariableManager, int>(i));
168 } else {
169 B2WARNING("Overflow for integer constant in cut detected. Create Double Node instead.");
170 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new DataNode<AVariableManager, double>(d));
171 }
172 } else if (node_type == NodeType::DoubleNode) {
173 if (py::len(tuple) != 2) B2FATAL("DoubleNode nodetuple has to have length 2." << LogVar("actual length", py::len(tuple)));
174 // We have to check for inf and nan values.
175 // use python math functions to check
176 py::object math = py::import("math");
177 // Get tuple item as object
178 py::object data = static_cast<py::object>(tuple[1]);
179 if (py::extract<bool>(math.attr("isinf")(data))) {
180 // Extract sign of inf float object
181 double inf_sign = py::extract<double>(math.attr("copysign")(1.0, data));
182 double inf;
183 if (inf_sign > 0) {
184 inf = std::numeric_limits<double>::infinity();
185 } else {
186 inf = -1 * std::numeric_limits<double>::infinity();
187 }
188 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new DataNode<AVariableManager, double>(inf));
189 }
190 if (py::extract<bool>(math.attr("isnan")(data))) {
191 double nan = std::nan("");
192 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new DataNode<AVariableManager, double>(nan));
193 }
194 double d = py::extract<double>(tuple[1]);
195 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new DataNode<AVariableManager, double>(d));
196 } else if (node_type == NodeType::BooleanNode) {
197 if (py::len(tuple) != 2) B2FATAL("BooleanNode nodetuple has to have length 2." << LogVar("actual length", py::len(tuple)));
198 bool b = py::extract<bool>(tuple[1]);
199 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new DataNode<AVariableManager, bool>(b));
200 } else if (node_type == NodeType::IdentifierNode) {
201 if (py::len(tuple) != 2) B2FATAL("IdentifierNode nodetuple has to have length 2." << LogVar("actual length", py::len(tuple)));
202 std::string identifier = py::extract<std::string>(tuple[1]);
203 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new IdentifierNode<AVariableManager>(identifier));
204 } else if (node_type == NodeType::FunctionNode) {
205 if (py::len(tuple) != 3) B2FATAL("FunctionNode nodetuple has to have length 3." << LogVar("actual length", py::len(tuple)));
206
207 // Extract functionName as second argument of the tuple
208 std::string functionName = py::extract<std::string>(tuple[1]);
209
210 // Extract argument tuple
211 std::string argument = py::extract<std::string>(tuple[2]);
212 boost::algorithm::trim(argument);
213 // Define vector for function arguments
214 std::vector<std::string> functionArguments = splitOnDelimiterAndConserveParenthesis(argument, ',', '(', ')');
215 for (auto& str : functionArguments) {
216 boost::algorithm::trim(str);
217 if (str.empty()) {
218 B2WARNING("Empty parameter for metavariable '" << functionName << "' in cut.");
219 }
220 }
221
222 return std::unique_ptr<const AbstractExpressionNode<AVariableManager>>(new FunctionNode<AVariableManager>(functionName,
223 functionArguments));
224 } else {
225 throw std::runtime_error("error NodeFactory::compile_expression_node: got invalid expression NodeType.");
226 }
227 }
228 };
230}
231
Nodeclass with two AbstractBooleanNode as children and a Boolean Operator (AND, OR) Check() method ev...
Definition: CutNodes.h:274
BinaryExpressionNode Node which connects two expression nodes with an arithemtic operation.
Definition: CutNodes.h:726
BooleanNode which has two AbstractExpressionNodes nodes and a ComparisonOperator.
Definition: CutNodes.h:427
Template class for storing the Constants (int, double, bool) of the Cutstring.
Definition: CutNodes.h:886
FunctionNode Node class for handling MetaVariables in cuts.
Definition: CutNodes.h:1013
Class which stores the name of a variable.
Definition: CutNodes.h:941
Wrapper class for static node compile functions.
Definition: NodeFactory.h:64
static std::unique_ptr< const AbstractExpressionNode< AVariableManager > > compile_expression_node(Nodetuple tuple)
This template function creates a ExpressionNode from a boost::python::tuple The Python Parser encodes...
Definition: NodeFactory.h:141
static std::unique_ptr< const AbstractBooleanNode< AVariableManager > > compile_boolean_node(Nodetuple tuple)
This template function creates a boolean node from a boost::python::tuple The Python Parser encodes t...
Definition: NodeFactory.h:80
BooleanNode which has three AbstractExpressionNodes nodes and two ComparisonOperator.
Definition: CutNodes.h:523
Nodeclass with a single AbstractBooleanNode as child.
Definition: CutNodes.h:198
UnaryExpressionNode Node class with a single expression node as child.
Definition: CutNodes.h:653
Nodeclass with a single AbstractExpressioNode as child.
Definition: CutNodes.h:351
Class to store variables with their name which were sent to the logging service.
NodeType
Enum of possible Nodes in parsing tree.
std::vector< std::string > splitOnDelimiterAndConserveParenthesis(std::string str, char delimiter, char open, char close)
Split into std::vector on delimiter ignoring delimiters between parenthesis.
Definition: CutHelpers.cc:81
ComparisonOperator
Enum for decoding the comparison operator type.
BooleanOperator
Enum for decoding the boolean operator type.
ArithmeticOperation
Enum for decoding the comparison operator type.
Abstract base class for different kinds of events.