Belle II Software  release-06-00-14
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  B2ERROR("Number of collected paths to large: skipping the event and not processing it.");
83  return false;
84  }
85  }
86  paths = allNodePaths;
87  return true;
88  }
89 
90 
92  static std::string printPaths(std::vector<Path>& allPaths)
93  {
94  std::stringstream out;
95  unsigned int longestPath = 0, longesPathIndex = 0, index = 0;
96  out << "Print " << allPaths.size() << " paths:";
97  for (Path const& aPath : allPaths) {
98  if (longestPath < aPath.size()) {
99  longestPath = aPath.size();
100  longesPathIndex = index;
101  }
102  out << "\n" << "path " << index << ": length " << aPath.size() << ", entries:\n";
103  for (auto* entry : aPath) {
104  out << entry->getEntry() << "| ";
105  }
106  index++;
107  }
108  out << "\n" << "longest path was " << longesPathIndex << " with length of " << longestPath << "\n";
109 
110  return out.str();
111  }
112 
113 
114  protected:
116  Path clone(const Path& aPath) const
117  {
118  Path newPath = Path();
119  for (auto* entry : aPath) {
120  newPath.push_back(entry);
121  }
122  return newPath;
123  }
124 
125 
127  void storeAcceptedPath(Path newPath, std::vector<Path>& allNodePaths) const
128  {
129  if (newPath.size() >= minPathLength) {
130  allNodePaths.push_back(newPath);
131  }
132  }
133 
134 
136  void findPathsRecursive(std::vector<Path >& allNodePaths, Path& currentPath, NeighbourContainerType& innerNeighbours)
137  {
138  nRecursiveCalls++;
139 
140  if (currentPath.size() > 30) {
141  B2WARNING("findPathsRecursive reached a path length of over 30. Stopping Path here!");
142  return;
143  }
144 
145  // Test if there are viable neighbours to current node
146  NeighbourContainerType viableNeighbours;
147  for (size_t iNeighbour = 0; iNeighbour < innerNeighbours.size(); ++iNeighbour) {
148  if (m_compatibilityChecker.areCompatible(currentPath.back(), innerNeighbours[iNeighbour])) {
149  viableNeighbours.push_back(innerNeighbours[iNeighbour]);
150  }
151  }
152 
153  // If current path will continue, optionally store the subpath up to current node
154  if (m_storeSubsets && viableNeighbours.size() > 0) {
155  Path newPath = clone(currentPath);
156  storeAcceptedPath(newPath, allNodePaths);
157  }
158 
159  for (size_t iNeighbour = 0; iNeighbour < viableNeighbours.size(); ++iNeighbour) {
160  // the last alternative is assigned to the existing path.
161  if (iNeighbour == viableNeighbours.size() - 1) {
162  currentPath.push_back(viableNeighbours[iNeighbour]);
163  NeighbourContainerType& newNeighbours = viableNeighbours[iNeighbour]->getInnerNodes();
164 
165  findPathsRecursive(allNodePaths, currentPath, newNeighbours);
166  } else {
167  Path newPath = clone(currentPath);
168 
169  newPath.push_back(viableNeighbours[iNeighbour]);
170  NeighbourContainerType& newNeighbours = viableNeighbours[iNeighbour]->getInnerNodes();
171 
172  findPathsRecursive(allNodePaths, newPath, newNeighbours);
173  storeAcceptedPath(newPath, allNodePaths);
174  }
175  }
176  }
177 
178  public:
180 
182  unsigned int minPathLength = 2;
183 
185  unsigned int nTrees = 0;
186 
188  unsigned int nRecursiveCalls = 0;
189 
191  bool m_storeSubsets = false;
192 
193  protected:
195 
196  NodeCompatibilityCheckerType m_compatibilityChecker;
197  };
199 }
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.
static std::string printPaths(std::vector< Path > &allPaths)
Prints information about all paths provided in a vector of paths.
unsigned int minPathLength
public Data members:
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.
Abstract base class for different kinds of events.