The Gaudi Framework  v29r0 (ff2e7097)
ControlFlowGraph.cpp
Go to the documentation of this file.
1 #include "ControlFlowGraph.h"
2 #include <algorithm>
3 
4 namespace concurrency
5 {
6 
7  namespace recursive_CF
8  {
9 
10  //---------------------------------------------------------------------------
11  std::string ControlFlowNode::stateToString( const int& stateId ) const
12  {
13 
14  if ( 0 == stateId )
15  return "FALSE";
16  else if ( 1 == stateId )
17  return "TRUE";
18  else
19  return "UNDEFINED";
20  }
21 
22  //---------------------------------------------------------------------------
24  {
25 
26  for ( auto node : m_children ) delete node;
27  }
28 
29  //---------------------------------------------------------------------------
31  {
32 
33  for ( auto daughter : m_children ) daughter->initialize( algname_index_map );
34  }
35 
36  //--------------------------------------------------------------------------
38  {
39 
40  if ( std::find( m_children.begin(), m_children.end(), node ) == m_children.end() ) m_children.push_back( node );
41  }
42 
43  //---------------------------------------------------------------------------
45  const std::vector<int>& node_decisions, const unsigned int& recursionLevel ) const
46  {
47 
48  output << std::string( recursionLevel, ' ' ) << m_nodeName << " (" << m_nodeIndex << ")"
49  << ", w/ decision: " << stateToString( node_decisions[m_nodeIndex] ) << "(" << node_decisions[m_nodeIndex]
50  << ")" << std::endl;
51  for ( auto daughter : m_children ) {
52  daughter->printState( output, states, node_decisions, recursionLevel + 2 );
53  }
54  }
55 
56  //---------------------------------------------------------------------------
57  int DecisionNode::updateState( AlgsExecutionStates& states, std::vector<int>& node_decisions ) const
58  {
59  // check whether we already had a result earlier
60  // if (-1 != node_decisions[m_nodeIndex] ) { return node_decisions[m_nodeIndex]; }
61  int decision = ( ( m_allPass && m_modePromptDecision ) ? 1 : -1 );
62  bool hasUndecidedChild = false;
63  for ( auto daughter : m_children ) {
64  if ( m_modePromptDecision && ( -1 != decision || hasUndecidedChild ) ) {
65  node_decisions[m_nodeIndex] = decision;
66  return decision;
67  } // if prompt decision, return once result is known already or we can't
68  // fully evaluate right now because one daugther decision is missing still
69  auto res = daughter->updateState( states, node_decisions );
70  if ( -1 == res ) {
71  hasUndecidedChild = true;
72  } else if ( false == m_modeOR && res == 0 ) {
73  decision = 0;
74  } // "and"-mode (once first result false, the overall decision is false)
75  else if ( true == m_modeOR && res == 1 ) {
76  decision = 1;
77  } // "or"-mode (once first result true, the overall decision is true)
78  }
79  // what to do with yet undefined answers depends on whether AND or OR mode applies
80  if ( !hasUndecidedChild && -1 == decision ) {
81  // OR mode: all results known, and none true -> reject
82  if ( true == m_modeOR ) {
83  decision = 0;
84  }
85  // AND mode: all results known, and no false -> accept
86  else {
87  decision = 1;
88  }
89  }
90  // in all other cases I stay with previous decisions
91  node_decisions[m_nodeIndex] = decision;
92  if ( m_allPass ) decision = 1;
93  return decision;
94  }
95 
96  //---------------------------------------------------------------------------
98  {
99 
100  m_algoIndex = algname_index_map.at( m_algoName );
101  }
102 
103  //---------------------------------------------------------------------------
105  const std::vector<int>& node_decisions, const unsigned int& recursionLevel ) const
106  {
107  output << std::string( recursionLevel, ' ' ) << m_nodeName << " (" << m_nodeIndex << ")"
108  << ", w/ decision: " << stateToString( node_decisions[m_nodeIndex] ) << "(" << node_decisions[m_nodeIndex]
109  << ")"
110  << ", in state: " << AlgsExecutionStates::stateNames[states[m_algoIndex]] << std::endl;
111  }
112 
113  //---------------------------------------------------------------------------
115  {
116  // check whether we already had a result earlier
117  // if (-1 != node_decisions[m_nodeIndex] ) { return node_decisions[m_nodeIndex]; }
118  // since we reached this point in the control flow, this algorithm is supposed to run
119  // if it hasn't already
120  const State& state = states[m_algoIndex];
121  unsigned int decision = -1;
122  if ( State::INITIAL == state ) {
123  states.updateState( m_algoIndex, State::CONTROLREADY ).ignore();
124  }
125  // now derive the proper result to pass back
126  if ( true == m_allPass ) {
127  decision = 1;
128  } else if ( State::EVTACCEPTED == state ) {
129  decision = !m_inverted;
130  } else if ( State::EVTREJECTED == state ) {
131  decision = m_inverted;
132  } else {
133  decision = -1; // result not known yet
134  }
135  node_decisions[m_nodeIndex] = decision;
136  return decision;
137  }
138 
139  //---------------------------------------------------------------------------
141  {
142  m_headNode->initialize( algname_index_map );
143  }
144 
145  //---------------------------------------------------------------------------
146  StatusCode ControlFlowGraph::addAlgorithmNode( Algorithm* algo, const std::string& parentName, bool inverted,
147  bool allPass )
148  {
149 
151 
152  auto& algoName = algo->name();
153 
154  auto itP = m_decisionNameToDecisionHubMap.find( parentName );
156  if ( itP != m_decisionNameToDecisionHubMap.end() ) {
157  parentNode = itP->second;
158  auto itA = m_algoNameToAlgoNodeMap.find( algoName );
160  if ( itA != m_algoNameToAlgoNodeMap.end() ) {
161  algoNode = itA->second;
162  } else {
163  algoNode = new concurrency::recursive_CF::AlgorithmNode( *this, algo, m_nodeCounter, m_algoCounter, inverted,
164  allPass );
165  ++m_nodeCounter;
166  ++m_algoCounter;
167  m_algoNameToAlgoNodeMap[algoName] = algoNode;
168  if ( msgLevel( MSG::VERBOSE ) ) verbose() << "AlgoNode " << algoName << " added @ " << algoNode << endmsg;
169  }
170 
171  parentNode->addDaughterNode( algoNode );
172  } else {
173  sc = StatusCode::FAILURE;
174  error() << "Decision hub node " << parentName << ", requested to be parent, is not registered." << endmsg;
175  }
176 
177  return sc;
178  }
179 
180  //---------------------------------------------------------------------------
182  bool modeConcurrent, bool modePromptDecision, bool modeOR,
183  bool allPass )
184  {
185 
187 
188  auto& decisionHubName = decisionHubAlgo->name();
189 
190  auto itP = m_decisionNameToDecisionHubMap.find( parentName );
192  if ( itP != m_decisionNameToDecisionHubMap.end() ) {
193  parentNode = itP->second;
194  auto itA = m_decisionNameToDecisionHubMap.find( decisionHubName );
196  if ( itA != m_decisionNameToDecisionHubMap.end() ) {
197  decisionHubNode = itA->second;
198  } else {
199  decisionHubNode = new concurrency::recursive_CF::DecisionNode(
200  *this, m_nodeCounter, decisionHubName, modeConcurrent, modePromptDecision, modeOR, allPass );
201  ++m_nodeCounter;
202  m_decisionNameToDecisionHubMap[decisionHubName] = decisionHubNode;
203  if ( msgLevel( MSG::VERBOSE ) )
204  verbose() << "Decision hub node " << decisionHubName << " added @ " << decisionHubNode << endmsg;
205  }
206 
207  parentNode->addDaughterNode( decisionHubNode );
208  } else {
209  sc = StatusCode::FAILURE;
210  error() << "Decision hub node " << parentName << ", requested to be parent, is not registered." << endmsg;
211  }
212 
213  return sc;
214  }
215 
216  //---------------------------------------------------------------------------
217  void ControlFlowGraph::addHeadNode( const std::string& headName, bool modeConcurrent, bool modePromptDecision,
218  bool modeOR, bool allPass )
219  {
220 
221  auto itH = m_decisionNameToDecisionHubMap.find( headName );
222  if ( itH != m_decisionNameToDecisionHubMap.end() ) {
223  m_headNode = itH->second;
224  } else {
225  m_headNode = new concurrency::recursive_CF::DecisionNode( *this, m_nodeCounter, headName, modeConcurrent,
226  modePromptDecision, modeOR, allPass );
227  ++m_nodeCounter;
228  m_decisionNameToDecisionHubMap[headName] = m_headNode;
229  }
230  }
231 
232  //---------------------------------------------------------------------------
233  void ControlFlowGraph::updateEventState( AlgsExecutionStates& algo_states, std::vector<int>& node_decisions ) const
234  {
235  m_headNode->updateState( algo_states, node_decisions );
236  }
237 
238  //---------------------------------------------------------------------------
240  {
241  std::ostringstream ost;
242  dumpControlFlow( ost, m_headNode, 0 );
243  return ost.str();
244  }
245 
246  //---------------------------------------------------------------------------
247  void ControlFlowGraph::dumpControlFlow( std::ostringstream& ost, ControlFlowNode* node, const int& indent ) const
248  {
249  ost << std::string( indent * 2, ' ' );
250  DecisionNode* dn = dynamic_cast<DecisionNode*>( node );
251  AlgorithmNode* an = dynamic_cast<AlgorithmNode*>( node );
252  if ( dn != 0 ) {
253  if ( node != m_headNode ) {
254  ost << node->getNodeName() << " [Seq] ";
255  ost << ( ( dn->m_modeConcurrent ) ? " [Concurrent] " : " [Sequential] " );
256  ost << ( ( dn->m_modePromptDecision ) ? " [Prompt] " : "" );
257  ost << ( ( dn->m_modeOR ) ? " [OR] " : "" );
258  ost << ( ( dn->m_allPass ) ? " [PASS] " : "" );
259  ost << "\n";
260  }
261  const std::vector<ControlFlowNode*>& dth = dn->getDaughters();
262  for ( std::vector<ControlFlowNode*>::const_iterator itr = dth.begin(); itr != dth.end(); ++itr ) {
263  dumpControlFlow( ost, *itr, indent + 1 );
264  }
265  } else if ( an != 0 ) {
266  ost << node->getNodeName() << " [Alg] ";
267  if ( an != 0 ) {
268  auto ar = an->getAlgorithm();
269  ost << " [n= " << ar->cardinality() << "]";
270  ost << ( ( !ar->isClonable() ) ? " [unclonable] " : "" );
271  }
272  ost << "\n";
273  }
274  }
275 
276  } // namespace
277 } // namespace
void addDaughterNode(ControlFlowNode *node)
Add a daughter node.
const std::string & name() const override
The identifying name of the algorithm object.
Definition: Algorithm.cpp:731
void addHeadNode(const std::string &headName, bool modeConcurrent, bool modePromptDecision, bool modeOR, bool allPass)
Add a node, which has no parents.
const std::string & getNodeName() const
Get node name.
std::string stateToString(const int &stateId) const
Translation between state id and name.
std::string dumpControlFlow() const
Print out control flow of Algorithms and Sequences.
bool m_modePromptDecision
Whether to evaluate the hub decision ASA its child decisions allow to do that.
StatusCode addDecisionHubNode(Algorithm *daughterAlgo, const std::string &parentName, bool modeConcurrent, bool modePromptDecision, bool modeOR, bool allPass)
Add a node, which aggregates decisions of direct daughter nodes.
T endl(T...args)
bool m_allPass
Whether always passing regardless of daughter results.
void updateEventState(AlgsExecutionStates &states, std::vector< int > &node_decisions) const
Start revision of states and decisions.
Algorithm * getAlgorithm() const
get Algorithm representatives
T end(T...args)
int updateState(AlgsExecutionStates &states, std::vector< int > &node_decisions) const override
Method to set algos to CONTROLREADY, if possible.
void printState(std::stringstream &output, AlgsExecutionStates &states, const std::vector< int > &node_decisions, const unsigned int &recursionLevel) const override
Print a string representing the control flow state.
STL class.
void printState(std::stringstream &output, AlgsExecutionStates &states, const std::vector< int > &node_decisions, const unsigned int &recursionLevel) const override
Print a string representing the control flow state.
int updateState(AlgsExecutionStates &states, std::vector< int > &node_decisions) const override
Method to set algos to CONTROLREADY, if possible.
The AlgsExecutionStates encodes the state machine for the execution of algorithms within a single eve...
const std::vector< ControlFlowNode * > & getDaughters() const
This class is used for returning status codes from appropriate routines.
Definition: StatusCode.h:28
void initialize(const std::unordered_map< std::string, unsigned int > &algname_index_map) override
Initialize.
Base class from which all concrete algorithm classes should be derived.
Definition: Algorithm.h:78
T find(T...args)
void initialize(const std::unordered_map< std::string, unsigned int > &algname_index_map) override
Initialize.
T begin(T...args)
void initialize(const std::unordered_map< std::string, unsigned int > &algname_index_map)
Initialize graph.
void ignore() const
Definition: StatusCode.h:109
State
Execution states of the algorithms.
StatusCode addAlgorithmNode(Algorithm *daughterAlgo, const std::string &parentName, bool inverted, bool allPass)
Add algorithm node.
bool m_modeOR
Whether acting as "and" (false) or "or" node (true)
bool m_modeConcurrent
Whether all daughters will be evaluated concurrently or sequentially.
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition: MsgStream.h:209
static std::map< State, std::string > stateNames
StatusCode updateState(unsigned int iAlgo, State newState)