Belle II Software development
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
16namespace 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 {
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.