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 {
21
43 template<class ContainerType, class NodeType, class NeighbourContainerType, class NodeCompatibilityCheckerType>
45 public:
47 using Path = std::vector<NodeType*>;
48
49
56 bool findPaths(ContainerType& aNetwork, std::vector<Path>& paths, unsigned int pathLimit, bool storeSubsets = false)
57 {
58 m_storeSubsets = storeSubsets;
59
60 std::vector<Path> allNodePaths;
61 for (NodeType* aNode : aNetwork) {
62 if (aNode->getMetaInfo().isSeed() == false) {
63 continue;
64 }
65
66 NeighbourContainerType& innerNeighbours = aNode->getInnerNodes();
67 if (innerNeighbours.empty()) {
68 continue;
69 }
70 if (aNode->getOuterNodes().empty()) {
71 nTrees++;
72 }
73
74 // creating unique_ptr of a new path:
75 Path newPath = Path{aNode};
76
77 findPathsRecursive(allNodePaths, newPath, innerNeighbours);
78 storeAcceptedPath(newPath, allNodePaths);
79
80 if (allNodePaths.size() > pathLimit) {
81 B2WARNING("Number of collected paths is too large: skipping the event and not processing it."
82 << LogVar("Number of node paths", allNodePaths.size()) << LogVar("Current limit of paths", pathLimit));
83 return false;
84 }
85 }
86 paths = allNodePaths;
87 return true;
88 }
89
90
92 static std::string printPaths(const 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(const 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 {
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 };
198
199}
Path finder for generic ContainerType.
unsigned int nRecursiveCalls
Counter for number of recursive calls.
NodeCompatibilityCheckerType m_compatibilityChecker
protected Data members:
void storeAcceptedPath(const Path &newPath, std::vector< Path > &allNodePaths) const
Tests length requirement on a path before adding it to path vector.
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.