Belle II Software  release-08-01-10
PathCollectorRecursive.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 #pragma once
9 
10 #include <string>
11 #include <vector>
12 #include <sstream>
13 
14 #include <framework/logging/Logger.h>
15 
16 namespace Belle2 {
43  template<class ContainerType, class NodeType, class NeighbourContainerType, class NodeCompatibilityCheckerType>
45  public:
47  using Path = std::vector<NodeType*>;
48 
49 
56  // cppcheck-suppress constParameter
57  bool findPaths(ContainerType& aNetwork, std::vector<Path>& paths, unsigned int pathLimit, bool storeSubsets = false)
58  {
59  m_storeSubsets = storeSubsets;
60 
61  std::vector<Path> allNodePaths;
62  for (NodeType* aNode : aNetwork) {
63  if (aNode->getMetaInfo().isSeed() == false) {
64  continue;
65  }
66 
67  NeighbourContainerType& innerNeighbours = aNode->getInnerNodes();
68  if (innerNeighbours.empty()) {
69  continue;
70  }
71  if (aNode->getOuterNodes().empty()) {
72  nTrees++;
73  }
74 
75  // creating unique_ptr of a new path:
76  Path newPath = Path{aNode};
77 
78  findPathsRecursive(allNodePaths, newPath, innerNeighbours);
79  storeAcceptedPath(newPath, allNodePaths);
80 
81  if (allNodePaths.size() > pathLimit) {
82  B2WARNING("Number of collected paths is too large: skipping the event and not processing it."
83  << LogVar("Number of node paths", allNodePaths.size()) << LogVar("Current limit of paths", pathLimit));
84  return false;
85  }
86  }
87  paths = allNodePaths;
88  return true;
89  }
90 
91 
93  static std::string printPaths(const std::vector<Path>& allPaths)
94  {
95  std::stringstream out;
96  unsigned int longestPath = 0, longesPathIndex = 0, index = 0;
97  out << "Print " << allPaths.size() << " paths:";
98  for (Path const& aPath : allPaths) {
99  if (longestPath < aPath.size()) {
100  longestPath = aPath.size();
101  longesPathIndex = index;
102  }
103  out << "\n" << "path " << index << ": length " << aPath.size() << ", entries:\n";
104  for (auto* entry : aPath) {
105  out << entry->getEntry() << "| ";
106  }
107  index++;
108  }
109  out << "\n" << "longest path was " << longesPathIndex << " with length of " << longestPath << "\n";
110 
111  return out.str();
112  }
113 
114 
115  protected:
117  Path clone(const Path& aPath) const
118  {
119  Path newPath = Path();
120  for (auto* entry : aPath) {
121  newPath.push_back(entry);
122  }
123  return newPath;
124  }
125 
126 
128  void storeAcceptedPath(Path newPath, std::vector<Path>& allNodePaths) const
129  {
130  if (newPath.size() >= minPathLength) {
131  allNodePaths.push_back(newPath);
132  }
133  }
134 
135 
137  void findPathsRecursive(std::vector<Path >& allNodePaths, Path& currentPath, NeighbourContainerType& innerNeighbours)
138  {
139  nRecursiveCalls++;
140 
141  if (currentPath.size() > 30) {
142  B2WARNING("findPathsRecursive reached a path length of over 30. Stopping Path here!");
143  return;
144  }
145 
146  // Test if there are viable neighbours to current node
147  NeighbourContainerType viableNeighbours;
148  for (size_t iNeighbour = 0; iNeighbour < innerNeighbours.size(); ++iNeighbour) {
149  if (m_compatibilityChecker.areCompatible(currentPath.back(), innerNeighbours[iNeighbour])) {
150  viableNeighbours.push_back(innerNeighbours[iNeighbour]);
151  }
152  }
153 
154  // If current path will continue, optionally store the subpath up to current node
155  if (m_storeSubsets && viableNeighbours.size() > 0) {
156  Path newPath = clone(currentPath);
157  storeAcceptedPath(newPath, allNodePaths);
158  }
159 
160  for (size_t iNeighbour = 0; iNeighbour < viableNeighbours.size(); ++iNeighbour) {
161  // the last alternative is assigned to the existing path.
162  if (iNeighbour == viableNeighbours.size() - 1) {
163  currentPath.push_back(viableNeighbours[iNeighbour]);
164  NeighbourContainerType& newNeighbours = viableNeighbours[iNeighbour]->getInnerNodes();
165 
166  findPathsRecursive(allNodePaths, currentPath, newNeighbours);
167  } else {
168  Path newPath = clone(currentPath);
169 
170  newPath.push_back(viableNeighbours[iNeighbour]);
171  NeighbourContainerType& newNeighbours = viableNeighbours[iNeighbour]->getInnerNodes();
172 
173  findPathsRecursive(allNodePaths, newPath, newNeighbours);
174  storeAcceptedPath(newPath, allNodePaths);
175  }
176  }
177  }
178 
179  public:
181 
183  unsigned int minPathLength = 2;
184 
186  unsigned int nTrees = 0;
187 
189  unsigned int nRecursiveCalls = 0;
190 
192  bool m_storeSubsets = false;
193 
194  protected:
196 
197  NodeCompatibilityCheckerType m_compatibilityChecker;
198  };
200 }
Path finder for generic ContainerType.
unsigned int nRecursiveCalls
Counter for number of recursive calls.
void storeAcceptedPath(Path newPath, std::vector< Path > &allNodePaths) const
Tests length requirement on a path before adding it to path vector.
NodeCompatibilityCheckerType m_compatibilityChecker
protected Data members:
std::vector< NodeType * > Path
Using Path for vector of pointers to NodeTypes.
Path clone(const Path &aPath) const
Copies path to create an identical one.
unsigned int nTrees
Counter for number of trees found.
unsigned int minPathLength
public Data members:
static std::string printPaths(const std::vector< Path > &allPaths)
Prints information about all paths provided in a vector of paths.
void findPathsRecursive(std::vector< Path > &allNodePaths, Path &currentPath, NeighbourContainerType &innerNeighbours)
Recursive pathFinder: Collects all possible segment combinations to build paths.
bool m_storeSubsets
flag if subsets should be stored or not
bool findPaths(ContainerType &aNetwork, std::vector< Path > &paths, unsigned int pathLimit, bool storeSubsets=false)
Main functionality of this class Evaluates provided network and creates all allowed paths.
Class to store variables with their name which were sent to the logging service.
NodeType
Enum of possible Nodes in parsing tree.
Abstract base class for different kinds of events.