Belle II Software development
CellularAutomaton.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 <tracking/trackFindingCDC/ca/AutomatonCell.h>
11#include <tracking/trackFindingCDC/numerics/Weight.h>
12
13#include <tracking/trackFindingCDC/utilities/WeightedRelation.h>
14
15#include <framework/logging/Logger.h>
16
17#include <cmath>
18
19namespace Belle2 {
25 namespace TrackFindingCDC {
29 template<class ACellHolder>
31
32 private:
35
36 public:
43 ACellHolder* applyTo(const std::vector<ACellHolder*>& cellHolders,
44 const std::vector<WeightedRelation<ACellHolder>>& cellHolderRelations) const
45 {
46 B2ASSERT("Expected the relations to be sorted",
47 std::is_sorted(cellHolderRelations.begin(), cellHolderRelations.end()));
48
49 // Set all cell states to -inf and the non permanent flags to unset.
50 prepareCellFlags(cellHolders);
51
52 for (ACellHolder* cellHolder : cellHolders) {
53 AutomatonCell& cell = cellHolder->getAutomatonCell();
54 if (cell.hasMaskedFlag()) continue;
55 if (cell.hasCycleFlag()) continue;
56
57 if (not cell.hasAssignedFlag()) {
58 // Mark this cell as a start point of a long path since we encountered it in
59 // at the top level of the recursion.
60 cell.setStartFlag();
61 // The flag will be unset when it appears on the _to_ side of a relation.
62 }
63
64 try {
65 // Assigns flags and the cell state
66 getFinalCellState(cellHolder, cellHolderRelations);
67 } catch (CycleException) {
68 // TODO: Come up with some handling for cycles.
69 // For now we continue to look for long paths in the graph
70 // hoping to find a part that does not enter the cycle.
71
72 // Thoughts:
73 // If there is a single cycle in the graph we might be able to break it at some point.
74 // However, if there are multiple cycles intertwined things get very tricky.
75 // But can we actually distinguish the two situations?
76 }
77 }
78
79 auto lessStartCellState = [](ACellHolder * lhs, ACellHolder * rhs) {
80 const AutomatonCell& lhsCell = lhs->getAutomatonCell();
81 const AutomatonCell& rhsCell = rhs->getAutomatonCell();
82 return (std::make_pair(lhsCell.hasStartFlag(), lhsCell.getCellState()) <
83 std::make_pair(rhsCell.hasStartFlag(), rhsCell.getCellState()));
84 };
85
86 auto itStartCellHolder =
87 std::max_element(cellHolders.begin(), cellHolders.end(), lessStartCellState);
88 if (itStartCellHolder == cellHolders.end()) return nullptr;
89 if (not(*itStartCellHolder)->getAutomatonCell().hasStartFlag()) return nullptr;
90 return *itStartCellHolder;
91 }
92
93 private:
99 Weight getFinalCellState(ACellHolder* cellHolder,
100 const std::vector<WeightedRelation<ACellHolder>>& cellHolderRelations) const
101 {
102 AutomatonCell& cell = cellHolder->getAutomatonCell();
103
104 // Throw if this cell has already been traversed in this recursion cycle
105 if (cell.hasCycleFlag()) {
106 B2DEBUG(25, "Cycle detected");
107 throw (CycleException());
108 }
109
110 if (cell.hasAssignedFlag()) {
111 return cell.getCellState();
112
113 } else {
114 // Mark cell in order to detect if it was already traversed in this recursion cycle
115 cell.setCycleFlag();
116
117 Weight finalCellState = updateState(cellHolder, cellHolderRelations);
118
119 // Unmark the cell
120 cell.unsetCycleFlag();
121 return finalCellState;
122 }
123 }
124
126 Weight updateState(ACellHolder* cellHolder,
127 const std::vector<WeightedRelation<ACellHolder>>& cellHolderRelations) const
128 {
129 AutomatonCell& cell = cellHolder->getAutomatonCell();
130
131 // --- blocked cells do not contribute a continuation ---
132 // Redundant check.
133 if (cell.hasMaskedFlag()) {
134 cell.setAssignedFlag();
135 return NAN;
136 }
137
138 //--- Search for neighbors ---
139 Weight maxStateWithContinuation = NAN;
140
141 // Flag to keep track whether the best continuation lies on a prioriy path
142 bool isPriorityPath = false;
143
144 auto continuations = asRange(
145 std::equal_range(cellHolderRelations.begin(), cellHolderRelations.end(), cellHolder));
146
147 // Check neighbors now
148 for (const WeightedRelation<ACellHolder>& relation : continuations) {
149 // Advance to valid neighbor
150 ACellHolder* neighborCellHolder = relation.getTo();
151
152 // Skip dead ends (should not happen)
153 if (not neighborCellHolder) continue;
154
155 AutomatonCell& neighborCell = neighborCellHolder->getAutomatonCell();
156 // Skip masked continuations
157 if (neighborCell.hasMaskedFlag()) continue;
158
159 // Invalidate a possible start flag since the neighbor has an ancestors
160 neighborCell.unsetStartFlag();
161
162 // Get the value of the neighbor
163 Weight neighborCellState = getFinalCellState(neighborCellHolder, cellHolderRelations);
164
165 // Add the value of the connection to the gain value
166 Weight stateWithContinuation = neighborCellState + relation.getWeight();
167
168 // Remember only the maximum value of all neighbors
169 if (std::isnan(maxStateWithContinuation) or maxStateWithContinuation < stateWithContinuation) {
170 maxStateWithContinuation = stateWithContinuation;
171 // Remember whether the best continuation marks a priority path
172 // construction ensures that priority paths have at least two elements
173 isPriorityPath = neighborCell.hasPriorityFlag() or neighborCell.hasPriorityPathFlag();
174 }
175 } // end for relations
176
177 if (std::isnan(maxStateWithContinuation)) {
178 // No valid neighbor contributed a connection to the cell
179 maxStateWithContinuation = 0;
180 }
181
182 // The value of this cell is only its own weight
183 maxStateWithContinuation += cell.getCellWeight();
184
185 // Set the value
186 cell.setCellState(maxStateWithContinuation);
187 cell.setPriorityPathFlag(isPriorityPath);
188
189 // Mark this cell as having its final value
190 cell.setAssignedFlag();
191
192 // Return the just determined value
193 return cell.getCellState();
194 }
195
196 private:
201 void prepareCellFlags(const std::vector<ACellHolder*>& cellHolders) const
202 {
203 for (ACellHolder* cellHolder : cellHolders) {
204 AutomatonCell& cell = cellHolder->getAutomatonCell();
205 cell.unsetTemporaryFlags();
206 if (cell.hasMaskedFlag()) continue;
207 cell.setCellState(NAN);
208 }
209 }
210 };
211 }
213}
Cell used by the cellular automata.
Definition: AutomatonCell.h:29
bool hasAssignedFlag() const
Gets the current state of the already assigned marker flag.
bool hasCycleFlag() const
Gets the current state of the cycle marker flag.
void setCycleFlag(bool setTo=true)
Sets the cycle marker flag to the given value. Default value true.
bool hasStartFlag() const
Gets the current state of the start marker flag.
void unsetStartFlag()
Resets the start marker flag to false.
void unsetTemporaryFlags()
Resets the assigned, start and cycle marker flag.
bool hasMaskedFlag() const
Gets the current state of the masked marker flag.
Weight getCellWeight() const
Getter for the cell weight.
Weight getCellState() const
Getter for the cell state.
Definition: AutomatonCell.h:96
void setAssignedFlag(bool setTo=true)
Sets the already assigned marker flag to the given value. Default value true.
void unsetCycleFlag()
Resets the cycle marker flag to false.
void setCellState(Weight state)
Setter for the cell state.
bool hasPriorityPathFlag() const
Gets the current state of the priority path marker flag.
void setStartFlag(bool setTo=true)
Sets the start marker flag to the given value. Default value true.
bool hasPriorityFlag() const
Gets the current state of the do not use flag marker flag.
void setPriorityPathFlag(bool setTo=true)
Sets the priority path marker flag to the given value. Default value true.
Type for the very basic exception signal used in the detection of cycles.
Implements the weighted cellular automaton algorithm.
Weight updateState(ACellHolder *cellHolder, const std::vector< WeightedRelation< ACellHolder > > &cellHolderRelations) const
Updates the state of a cell considering all continuations recursively.
Weight getFinalCellState(ACellHolder *cellHolder, const std::vector< WeightedRelation< ACellHolder > > &cellHolderRelations) const
Gets the cell state of the cell holder.
ACellHolder * applyTo(const std::vector< ACellHolder * > &cellHolders, const std::vector< WeightedRelation< ACellHolder > > &cellHolderRelations) const
Applies the cellular automaton to the collection of cells and its neighborhood.
void prepareCellFlags(const std::vector< ACellHolder * > &cellHolders) const
Helper function to prepare the stats.
Type for two related objects with a weight.
Abstract base class for different kinds of events.