Belle II Software  release-08-01-10
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 
19 namespace Belle2 {
25  namespace TrackFindingCDC {
29  template<class ACellHolder>
31 
32  private:
34  class CycleException {};
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  // Assignes flags and the cell state
66  getFinalCellState(cellHolder, cellHolderRelations);
67  } catch (CycleException) {
68  // TODO: Come up with some handeling 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 connetion 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 priorty 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 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.
Weight updateState(ACellHolder *cellHolder, const std::vector< WeightedRelation< ACellHolder >> &cellHolderRelations) const
Updates the state of a cell considering all continuations recursively.
Type for two related objects with a weight.
Abstract base class for different kinds of events.