Belle II Software  release-08-01-10
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 
19 namespace py = boost::python;
20 typedef const py::tuple& Nodetuple;
21 
22 namespace 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 
64  class NodeFactory {
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.