Belle II Software  release-05-02-19
GeneralCut.h
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Thomas Keck, Nils Braun *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 #pragma once
11 
12 #include <framework/utilities/Conversion.h>
13 
14 #include <string>
15 #include <vector>
16 #include <memory>
17 
18 #include <boost/algorithm/string.hpp>
19 #include <sstream>
20 
21 #include <iostream>
22 #include <stdexcept>
23 
24 
25 namespace Belle2 {
35  unsigned long int findMatchedParenthesis(std::string str, char open = '[', char close = ']');
36 
40  std::vector<std::string> splitOnDelimiterAndConserveParenthesis(std::string str, char delimiter, char open, char close);
41 
45  unsigned long int findIgnoringParenthesis(std::string str, std::string pattern, unsigned int begin = 0);
46 
50  bool almostEqualFloat(const float& a, const float& b);
51 
55  bool almostEqualDouble(const double& a, const double& b);
56 
92  template <class AVariableManager>
93  class GeneralCut {
95  typedef typename AVariableManager::Object Object;
97  typedef typename AVariableManager::Var Var;
98 
99  public:
106  static std::unique_ptr<GeneralCut> compile(const std::string& cut)
107  {
108  return std::unique_ptr<GeneralCut>(new GeneralCut(cut));
109  }
115  bool check(const Object* p) const
116  {
117  switch (m_operation) {
118  case EMPTY:
119  return true;
120  case NONE:
121  return this->get(p);
122  case AND:
123  return m_left->check(p) and m_right->check(p);
124  case OR:
125  return m_left->check(p) or m_right->check(p);
126  case LT:
127  return m_left->get(p) < m_right->get(p);
128  case LE:
129  return m_left->get(p) <= m_right->get(p);
130  case GT:
131  return m_left->get(p) > m_right->get(p);
132  case GE:
133  return m_left->get(p) >= m_right->get(p);
134  case EQ:
135  return almostEqualDouble(m_left->get(p), m_right->get(p));
136  case NE:
137  return not almostEqualDouble(m_left->get(p), m_right->get(p));
138  }
139  throw std::runtime_error("Cut string has an invalid format: Invalid operation");
140  return false;
141  }
142 
146  void print() const
147  {
148  switch (m_operation) {
149  case EMPTY: std::cout << "EMPTY" << std::endl; break;
150  case NONE: std::cout << "NONE" << std::endl; break;
151  case AND: std::cout << "AND" << std::endl; break;
152  case OR: std::cout << "OR" << std::endl; break;
153  case LT: std::cout << "LT" << std::endl; break;
154  case LE: std::cout << "LE" << std::endl; break;
155  case GT: std::cout << "GT" << std::endl; break;
156  case GE: std::cout << "GE" << std::endl; break;
157  case EQ: std::cout << "EQ" << std::endl; break;
158  case NE: std::cout << "NE" << std::endl; break;
159  }
160  if (m_left != nullptr) {
161  std::cout << "Left " << std::endl;
162  m_left->print();
163  std::cout << "End Left" << std::endl;
164  }
165  if (m_right != nullptr) {
166  std::cout << "Right " << std::endl;
167  m_right->print();
168  std::cout << "End Right" << std::endl;
169  }
170  }
171 
175  std::string decompile() const
176  {
177  std::stringstream stringstream;
178  if (m_operation == EMPTY) {
179  return "";
180  } else if (m_left != nullptr and m_right != nullptr) {
181 
182  stringstream << "[";
183  stringstream << m_left->decompile();
184 
185  switch (m_operation) {
186  case AND: stringstream << " and "; break;
187  case OR: stringstream << " or "; break;
188  case LT: stringstream << " < "; break;
189  case LE: stringstream << " <= "; break;
190  case GT: stringstream << " > "; break;
191  case GE: stringstream << " >= "; break;
192  case EQ: stringstream << " == "; break;
193  case NE: stringstream << " != "; break;
194  default: throw std::runtime_error("Cut string has an invalid format: Operator does not support left and right!"); break;
195  }
196 
197  stringstream << m_right->decompile();
198  stringstream << "]";
199 
200  } else if (m_left == nullptr and m_right == nullptr) {
201  switch (m_operation) {
202  case NONE:
203  if (m_isNumeric) {
204  stringstream << m_number;
205  } else if (m_var != nullptr) {
206  stringstream << m_var->name;
207  } else {
208  throw std::runtime_error("Cut string has an invalid format: Variable is empty!");
209  }
210  break;
211  default: throw std::runtime_error("Cut string has an invalid format: Invalid operator without left and right!"); break;
212  }
213  } else {
214  throw std::runtime_error("Cut string has an invalid format: invalid combination of left and right!");
215  }
216 
217  return stringstream.str();
218  }
219 
220 
221  private:
226  explicit GeneralCut(std::string str)
227  {
228  str = preprocess(str);
229  if (str.empty()) {
230  m_operation = EMPTY;
231  return;
232  }
233 
234  if (not processLogicConditions(str)) {
235  if (not processTernaryNumericConditions(str)) {
236  if (not processBinaryNumericConditions(str)) {
237  m_operation = NONE;
238  try {
239  m_number = Belle2::convertString<double>(str);
240  m_isNumeric = true;
241  } catch (std::invalid_argument&) {
242  m_isNumeric = false;
243  processVariable(str);
244  }
245  }
246  }
247  }
248  }
249 
253  GeneralCut(const GeneralCut&) = delete;
254 
258  GeneralCut& operator=(const GeneralCut&) = delete;
259 
263  std::string preprocess(std::string str) const
264  {
265  boost::algorithm::trim(str);
266 
267  while (str.size() > 1 and findMatchedParenthesis(str) == str.size() - 1) {
268  str = str.substr(1, str.size() - 2);
269  boost::algorithm::trim(str);
270  }
271 
272  return str;
273  }
274 
278  bool processLogicConditions(std::string str)
279  {
280  unsigned long int begin = findMatchedParenthesis(str);
281  unsigned long int pos = 0;
282 
283  if ((pos = findIgnoringParenthesis(str, " or ", begin)) != std::string::npos) {
284  m_operation = OR;
285  m_left = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(0, pos)));
286  m_right = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(pos + 4)));
287  return true;
288  }
289 
290  if ((pos = findIgnoringParenthesis(str, " and ", begin)) != std::string::npos) {
291  m_operation = AND;
292  m_left = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(0, pos)));
293  m_right = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(pos + 5)));
294  return true;
295  }
296 
297  return false;
298  }
299 
303  bool processBinaryNumericConditions(std::string str)
304  {
305  unsigned long int pos = 0;
306  if ((pos = findIgnoringParenthesis(str, "<=")) != std::string::npos) {
307  m_operation = LE;
308  m_left = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(0, pos)));
309  m_right = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(pos + 2)));
310  return true;
311  }
312  if ((pos = findIgnoringParenthesis(str, "<")) != std::string::npos) {
313  m_operation = LT;
314  m_left = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(0, pos)));
315  m_right = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(pos + 1)));
316  return true;
317  }
318  if ((pos = findIgnoringParenthesis(str, ">=")) != std::string::npos) {
319  m_operation = GE;
320  m_left = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(0, pos)));
321  m_right = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(pos + 2)));
322  return true;
323  }
324  if ((pos = findIgnoringParenthesis(str, ">")) != std::string::npos) {
325  m_operation = GT;
326  m_left = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(0, pos)));
327  m_right = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(pos + 1)));
328  return true;
329  }
330  if ((pos = findIgnoringParenthesis(str, "==")) != std::string::npos) {
331  m_operation = EQ;
332  m_left = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(0, pos)));
333  m_right = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(pos + 2)));
334  return true;
335  }
336  if ((pos = findIgnoringParenthesis(str, "!=")) != std::string::npos) {
337  m_operation = NE;
338  m_left = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(0, pos)));
339  m_right = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(pos + 2)));
340  return true;
341  }
342 
343  return false;
344  }
345 
349  bool processTernaryNumericConditions(std::string str)
350  {
351  for (auto& c : {"<", ">", "!", "="}) {
352 
353  unsigned long int pos1 = 0;
354  unsigned long int pos2 = 0;
355 
356  if (((pos1 = findIgnoringParenthesis(str, c)) != std::string::npos) and
357  ((pos2 = findIgnoringParenthesis(str, "<", pos1 + 2)) != std::string::npos
358  or (pos2 = findIgnoringParenthesis(str, ">", pos1 + 2)) != std::string::npos
359  or (pos2 = findIgnoringParenthesis(str, "!", pos1 + 2)) != std::string::npos
360  or (pos2 = findIgnoringParenthesis(str, "=", pos1 + 2)) != std::string::npos)) {
361  m_operation = AND;
362  m_left = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(0, pos2)));
363  if (str[pos1 + 1] == '=')
364  pos1++;
365  m_right = std::unique_ptr<GeneralCut>(new GeneralCut(str.substr(pos1 + 1)));
366  return true;
367  }
368  }
369 
370  return false;
371  }
372 
377  void processVariable(const std::string& str)
378  {
379  AVariableManager& manager = AVariableManager::Instance();
380  m_var = manager.getVariable(str);
381  if (m_var == nullptr) {
382  throw std::runtime_error(
383  "Cut string has an invalid format: Variable not found: " + str);
384  }
385  }
386 
390  double get(const Object* p) const
391  {
392  if (m_isNumeric) {
393  return m_number;
394  } else if (m_var != nullptr) {
395  return m_var->function(p);
396  } else {
397  throw std::runtime_error("Cut string has an invalid format: Neither number nor variable name");
398  }
399  }
400 
404  enum Operation {
405  EMPTY = 0,
406  NONE,
407  AND,
408  OR,
409  LT,
410  LE,
411  GT,
412  GE,
413  EQ,
414  NE,
415  } m_operation;
416  const Var* m_var;
417  double m_number;
418  bool m_isNumeric;
419  std::unique_ptr<GeneralCut> m_left;
420  std::unique_ptr<GeneralCut> m_right;
421  };
423 }
Belle2::GeneralCut::Object
AVariableManager::Object Object
Object, that can be checked. This depends on the VariableManager, as the returned variables from the ...
Definition: GeneralCut.h:103
Belle2::GeneralCut::compile
static std::unique_ptr< GeneralCut > compile(const std::string &cut)
Creates an instance of a cut and returns a unique_ptr to it, if you need a copy-able object instead y...
Definition: GeneralCut.h:114
Belle2::splitOnDelimiterAndConserveParenthesis
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: GeneralCut.cc:72
Belle2::GeneralCut::m_operation
enum Belle2::GeneralCut::Operation m_operation
Operation which connects left and right cut.
Belle2::GeneralCut::get
double get(const Object *p) const
Returns stored number or Variable value for the given object.
Definition: GeneralCut.h:398
Belle2::GeneralCut::check
bool check(const Object *p) const
Check if the current cuts are passed by the given object.
Definition: GeneralCut.h:123
Belle2::GeneralCut::m_isNumeric
bool m_isNumeric
if there was a literal number in this cut
Definition: GeneralCut.h:426
Belle2::GeneralCut::m_var
const Var * m_var
set if there was a valid variable in this cut
Definition: GeneralCut.h:424
Belle2::GeneralCut::m_number
double m_number
literal number contained in the cut
Definition: GeneralCut.h:425
Belle2::GeneralCut::processLogicConditions
bool processLogicConditions(std::string str)
Look for logical conditions in the given cut string.
Definition: GeneralCut.h:286
Belle2::GeneralCut::Operation
Operation
Enum with the allowed operations of the Cut Tree.
Definition: GeneralCut.h:412
Belle2::GeneralCut::preprocess
std::string preprocess(std::string str) const
Preprocess cut string.
Definition: GeneralCut.h:271
Belle2::findIgnoringParenthesis
unsigned long int findIgnoringParenthesis(std::string str, std::string pattern, unsigned int begin=0)
Returns the position of a pattern in a string ignoring everything that is in parenthesis.
Definition: GeneralCut.cc:40
Belle2::GeneralCut::Var
AVariableManager::Var Var
Variable returned by the variable manager.
Definition: GeneralCut.h:105
Belle2::almostEqualFloat
bool almostEqualFloat(const float &a, const float &b)
Helper function to test if two floats are almost equal.
Definition: GeneralCut.cc:10
Belle2::GeneralCut::processTernaryNumericConditions
bool processTernaryNumericConditions(std::string str)
Look for numeric ternary conditions (e.g.
Definition: GeneralCut.h:357
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::GeneralCut::print
void print() const
Print cut tree.
Definition: GeneralCut.h:154
Belle2::almostEqualDouble
bool almostEqualDouble(const double &a, const double &b)
Helper function to test if two doubles are almost equal.
Definition: GeneralCut.cc:17
Belle2::GeneralCut::m_left
std::unique_ptr< GeneralCut > m_left
Left-side cut.
Definition: GeneralCut.h:427
Belle2::GeneralCut::decompile
std::string decompile() const
Do the compilation from a string in return.
Definition: GeneralCut.h:183
Belle2::GeneralCut::m_right
std::unique_ptr< GeneralCut > m_right
Right-side cut.
Definition: GeneralCut.h:428
Belle2::GeneralCut::operator=
GeneralCut & operator=(const GeneralCut &)=delete
Delete assign operator.
Belle2::findMatchedParenthesis
unsigned long int findMatchedParenthesis(std::string str, char open='[', char close=']')
Returns position of the matched closing parenthesis if the first character in the given string contai...
Definition: GeneralCut.cc:24
Belle2::GeneralCut::processVariable
void processVariable(const std::string &str)
Get a variable with the given name from the variable manager using its getVariable(name) function.
Definition: GeneralCut.h:385
Belle2::GeneralCut::processBinaryNumericConditions
bool processBinaryNumericConditions(std::string str)
Look for numeric binary conditions (e.g.
Definition: GeneralCut.h:311
Belle2::GeneralCut::GeneralCut
GeneralCut(std::string str)
Constructor of the cut.
Definition: GeneralCut.h:234