DetectorGraph  2.0
counterwithreset.cpp File Reference

Basic Counter with a FuturePublisher-based loop. More...

Go to the source code of this file.

Detailed Description

Basic Counter with a FuturePublisher-based loop.

Introduction

This examples cover the most basic way to close a loop in a graph - using a DetectorGraph::FuturePublisher. Unmarked loops are forbidden by the Framework as a Topographical sort is only possible in Directed Acyclic Graphs.

Intuitively, if there were cycles in a graph it would be impossible for the Framework to provide it's dependency guarantee:

For any Detector, all its dependencies will be evaluated before its own evaluation.

To construct closed loops the graph designer must explicitly define, per cycle/loop, which dependency (i.e. Topic) the above restriction will be waived.

Architecture

The example is composed of two Detectors. The first counts EventHappened and the second detects the condition at which the counter should be reset.

CounterWithReset

FuturePublisher vs. Lag<T>

The framework offers two ways of closing loops in a graph, DetectorGraph::FuturePublisher and DetectorGraph::Lag - this example employs the former.

In this graph it is clear that the TopicState used as a graph output is EventCount and that Reset is produced purely for the feedback path. It is also clear to the the designer of ResetDetecor that the published Reset TopicState should be evaluated in the next Evaluation pass and not in the current one. In such cases it is reasonable to put the responsibility for closing the loop on the writer of ResetDetector:

210 class ResetDetector : public DetectorGraph::Detector
211 , public DetectorGraph::SubscriberInterface<EventCount>
212 , public DetectorGraph::FuturePublisher<Reset>
213 {
214 public:
215  ResetDetector(DetectorGraph::Graph* graph) : DetectorGraph::Detector(graph)
216  {
217  Subscribe<EventCount>(this);
218  SetupFuturePublishing<Reset>(this);
219  }
220 
221  void Evaluate(const EventCount& aEventCount)
222  {
223  if (aEventCount.count >= kMaxCount)
224  {
225  PublishOnFutureEvaluation(Reset());
226  }
227  }
228 
229  static const int kMaxCount = 5;
230 };
Implements a graph of Topics & Detectors with Input/Output APIs.
Definition: graph.hpp:127
Publish data to the graph for future evaluation.
virtual void Evaluate(const T &)=0
Pure-virtual method that should Evaluate a piece of input data.
A unit of logic in a DetectorGraph.
Definition: detector.hpp:68
A Pure interface that declares the Subscriber behavior.
void PublishOnFutureEvaluation(const T &aData)
Publish a new version of T to the Graph for future evaluation.

In cases where downstream parts of the graph also subscribe to the TopicState used in the feedback loop, DetectorGraph::Lag should be used instead. For more info on that see other Feedback Loop examples (e.g. Robot Localization)

Graph

The graph instantiated and evaluation code is unaffected. Both

271 class CounterWithResetGraph : public DetectorGraph::ProcessorContainer
272 {
273 public:
274  CounterWithResetGraph()
275  : mEventCountDetector(&mGraph)
276  , mResetDetector(&mGraph)
277  , mEventCountTopic(mGraph.ResolveTopic<EventCount>())
278  {
279  }
280 
281  EventCountDetector mEventCountDetector;
282  ResetDetector mResetDetector;
283  DetectorGraph::Topic<EventCount>* mEventCountTopic;
284 
285  virtual void ProcessOutput()
286  {
287  if (mEventCountTopic->HasNewValue())
288  {
289  const EventCount& eventCount = mEventCountTopic->GetNewValue();
290  cout << "EventCount.count = " << eventCount.count << endl;
291  }
292  }
293 };
bool HasNewValue() const
Returns true if the new Data is available.
Definition: topic.hpp:166
A Base class for a basic Graph container.
Manage data and its handler.
Definition: topic.hpp:84
virtual void ProcessOutput()=0
Called after each Graph Evaluation.
const T & GetNewValue() const
Returns reference to the new/latest value in the topic.
Definition: topic.hpp:179

and

322 int main()
323 {
324  CounterWithResetGraph counterGraph;
325  for (int i = 0; i < 7; ++i)
326  {
327  counterGraph.ProcessData(EventHappened());
328  }
329 
330  Test_Count();
331  Test_ResetCount();
332  Test_ResetDetected();
333  Test_NoResetDetected();
334  Test_CounterResetIntegration();
335 }

work in the same way as with simple graphs.

Running the program produces:

DetectorGraph: Graph Initialized
EventCount.count = 1
EventCount.count = 2
EventCount.count = 3
EventCount.count = 4
EventCount.count = 5
EventCount.count = 0
EventCount.count = 1
EventCount.count = 2

One important thing to note in this case is that ProcessOutput is called 8 times even though main only pushes 7 TopicStates into the graph - this is by design and allows all graph outputs to continue to be inspected exactly once per-evaluation. This is the case for all graphs with closed loops.

Definition in file counterwithreset.cpp.