The Gaudi Framework  v36r7 (7f57a304)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
ControlFlow.py
Go to the documentation of this file.
1 
11 """
12 Classes for the implementation of the Control Flow Structure Syntax.
13 
14 @see: https://github.com/lhcb/scheduling-event-model/tree/master/controlflow_syntax
15 """
16 from __future__ import print_function
17 
18 
19 class ControlFlowNode(object):
20  """
21  Basic entry in the control flow graph.
22  """
23 
24  def __and__(self, rhs):
25  if rhs is CFTrue:
26  return self
27  elif rhs is CFFalse:
28  return CFFalse
29  return AndNode(self, rhs)
30 
31  def __or__(self, rhs):
32  if rhs is CFFalse:
33  return self
34  elif rhs is CFTrue:
35  return CFTrue
36  return OrNode(self, rhs)
37 
38  def __invert__(self):
39  return InvertNode(self)
40 
41  def __rshift__(self, rhs):
42  return OrderedNode(self, rhs)
43 
44  def visitNode(self, visitor):
45  visitor.enter(self)
46  self._visitSubNodes(visitor)
47  visitor.leave(self)
48 
49  def _visitSubNodes(self, visitor):
50  pass
51 
52  def __eq__(self, other):
53  return repr(self) == repr(other)
54 
55  def __hash__(self):
56  """Return a unique identifier for this object.
57 
58  As we use the `repr` of this object to check for equality, we use it
59  here to define uniqueness.
60  """
61  # The hash of the 1-tuple containing the repr of this object
62  return hash((repr(self),))
63 
64  def getFullName(self):
65  """
66  Allow use of an expression as an algorihtm/sequence in a Gaudi job
67  configuration.
68 
69  Convert the expression in nested sequencers and return the full name of
70  the top one.
71  """
72  if not hasattr(self, "_fullname"):
73  from GaudiKernel.Configurable import makeSequences
74 
76  return self._fullname
77 
78 
80  """
81  Class used to identify a note without sub-nodes.
82  """
83 
84  pass
85 
86 
87 class ControlFlowBool(ControlFlowLeaf):
88  def __init__(self, value):
89  self.value = value
90 
91  def __and__(self, rhs):
92  return rhs if self.value else self
93 
94  def __or__(self, rhs):
95  return self if self.value else rhs
96 
97  def __invert__(self):
98  return CFFalse if self.value else CFTrue
99 
100  def __repr__(self):
101  return "CFTrue" if self.value else "CFFalse"
102 
103 
104 CFTrue = ControlFlowBool(True)
105 CFFalse = ControlFlowBool(False)
106 del ControlFlowBool
107 
108 
110  """
111  Represent order of execution of nodes.
112  """
113 
114  def __init__(self, lhs, rhs):
115  self.lhs = lhs
116  self.rhs = rhs
117 
118  def __repr__(self):
119  return "(%r >> %r)" % (self.lhs, self.rhs)
120 
121  def _visitSubNodes(self, visitor):
122  self.lhs.visitNode(visitor)
123  self.rhs.visitNode(visitor)
124 
125 
127  """
128  And operation between control flow nodes.
129  """
130 
131  def __init__(self, lhs, rhs):
132  self.lhs = lhs
133  self.rhs = rhs
134 
135  def __repr__(self):
136  return "(%r & %r)" % (self.lhs, self.rhs)
137 
138  def _visitSubNodes(self, visitor):
139  self.lhs.visitNode(visitor)
140  self.rhs.visitNode(visitor)
141 
142 
144  """
145  Or operation between control flow nodes.
146  """
147 
148  def __init__(self, lhs, rhs):
149  self.lhs = lhs
150  self.rhs = rhs
151 
152  def __repr__(self):
153  return "(%r | %r)" % (self.lhs, self.rhs)
154 
155  def _visitSubNodes(self, visitor):
156  self.lhs.visitNode(visitor)
157  self.rhs.visitNode(visitor)
158 
159 
161  """
162  Invert logic (negation) of a control flow node.
163  """
164 
165  def __init__(self, item):
166  self.item = item
167 
168  def __repr__(self):
169  return "~%r" % self.item
170 
171  def _visitSubNodes(self, visitor):
172  self.item.visitNode(visitor)
173 
174 
176  """
177  Treat a control flow node as always successful, equivalent to (a | ~ a).
178  """
179 
180  def __init__(self, item):
181  self.item = item
182 
183  def __repr__(self):
184  return "ignore(%r)" % self.item
185 
186  def _visitSubNodes(self, visitor):
187  self.item.visitNode(visitor)
188 
189 
191  def __init__(self, item):
192  self.item = item
193 
194  def __repr__(self):
195  return "par(%r)" % self.item
196 
197  def _visitSubNodes(self, visitor):
198  self.item.visitNode(visitor)
199 
200 
202  def __init__(self, item):
203  self.item = item
204 
205  def __repr__(self):
206  return "seq(%r)" % self.item
207 
208  def _visitSubNodes(self, visitor):
209  self.item.visitNode(visitor)
210 
211 
212 class line(object):
213  def __init__(self, name, item):
214  self.name = name
215  self.item = item
216 
217  def __repr__(self):
218  return "line(%r, %r)" % (self.name, self.item)
219 
220  def _visitSubNodes(self, visitor):
221  self.item.visitNode(visitor)
222 
223 
224 class _TestVisitor(object):
225  def __init__(self):
226  self.depths = 0
227 
228  def enter(self, visitee):
229  self.depths += 1
230  print("%sEntering %s" % (self.depths * " ", type(visitee)))
231  if isinstance(visitee, ControlFlowLeaf):
232  print("%s Algorithm name: %s" % (" " * self.depths, visitee))
233 
234  def leave(self, visitee):
235  print("%sLeaving %s" % (self.depths * " ", type(visitee)))
236  self.depths -= 1
237 
238 
240  def __init__(self, name):
241  self._name = name
242 
243  def __repr__(self):
244  return self._name
245 
246  def name(self):
247  return self._name
248 
249 
250 class DotVisitor(object):
251  def __init__(self):
252  self.nodes = []
253  self.edges = []
254  self.number = 0
255  self.stack = []
256  self.ids = {}
257 
258  def enter(self, visitee):
259  if visitee not in self.ids:
260  self.number += 1
261  dot_id = self.ids[visitee] = "T%s" % self.number
262  dot_id = self.ids[visitee]
263  mother = None
264  if self.is_needed(visitee):
265  if isinstance(visitee, ControlFlowLeaf):
266  entry = '%s [label="%s", shape=box]' % (dot_id, visitee.name())
267  elif isinstance(visitee, OrNode):
268  entry = '%s [label="OR", shape=invhouse]' % dot_id
269  elif isinstance(visitee, AndNode):
270  entry = '%s [label="AND", shape=invhouse]' % dot_id
271  elif isinstance(visitee, OrderedNode):
272  entry = '%s [label=">>", shape=point]' % dot_id
273  elif isinstance(visitee, InvertNode):
274  entry = '%s [label="NOT", shape=circle, color=red]' % dot_id
275  elif isinstance(visitee, par):
276  entry = '%s [label="PAR", shape=circle]' % dot_id
277  elif isinstance(visitee, seq):
278  entry = '%s [label="SEQ", shape=circle]' % dot_id
279  else:
280  entry = '%s [label="%s", shape=circle]' % (dot_id, type(visitee))
281  self.nodes.append(entry)
282  if len(self.stack) != 0:
283  mother = self.collapse_identical_ancestors(type(self.stack[-1][0]))
284  if not mother:
285  mother = self.stack[-1][1]
286  edge = "%s->%s" % (dot_id, mother)
287  self.edges.append(edge)
288  self.stack.append((visitee, dot_id))
289 
290  def leave(self, visitee):
291  self.stack.pop()
292 
293  def collapse_identical_ancestors(self, thetype):
294  """
295  If AND nodes are inside AND nodes, the graph could be simplified
296  to not contain those (same true for OR and ordered)
297  """
298  counter = 0
299  if len(self.stack) != 0:
300  mother = self.stack[-1][1]
301  for entry in self.stack[::-1]:
302  if type(entry[0]) != thetype:
303  break
304  mother = entry[1]
305  return mother
306  return None
307 
308  def is_needed(self, visitee):
309  """
310  Check whether this node is actually needed
311  """
312  if len(self.stack) != 0:
313  return not isinstance(visitee, type(self.stack[-1][0]))
314  return True
315 
316  def write(self, filename):
317  output = """
318 digraph graphname {
319 rankdir=LR
320 
321 %s
322 
323 %s
324 
325 }
326 """ % (
327  "\n".join(self.nodes),
328  "\n".join(self.edges),
329  )
330 
331  with open(filename, "w") as outfile:
332  outfile.write(output)
333 
334 
335 def test():
336  Algorithm = _TestAlgorithm
337 
338  a = Algorithm("a")
339  b = Algorithm("b")
340  c = Algorithm("c")
341  d = Algorithm("d")
342  e = Algorithm("e")
343  f = Algorithm("f")
344  g = Algorithm("g")
345  sequence = seq(b >> a >> f)
346  expression = sequence | ~c & par(d & e & g)
347  a = expression == expression
348  aLine = line("MyTriggerPath", expression)
349  visitor = _TestVisitor()
350  visitor2 = DotVisitor()
351  print("\nPrinting trigger line:")
352  print(aLine)
353  print("\nPrinting expression:")
354  print(expression)
355  print("\nTraversing through expression:\n")
356  expression.visitNode(visitor)
357  expression.visitNode(visitor2)
358  visitor2.write("out.dot")
GaudiConfig.ControlFlow.AndNode.__repr__
def __repr__(self)
Definition: ControlFlow.py:135
GaudiConfig.ControlFlow.seq.__repr__
def __repr__(self)
Definition: ControlFlow.py:205
GaudiConfig.ControlFlow.line.name
name
Definition: ControlFlow.py:214
GaudiConfig.ControlFlow.ControlFlowBool.value
value
Definition: ControlFlow.py:89
GaudiConfig.ControlFlow.ControlFlowNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:49
GaudiConfig.ControlFlow._TestVisitor.depths
depths
Definition: ControlFlow.py:226
GaudiConfig.ControlFlow.par._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:197
GaudiConfig.ControlFlow.OrderedNode
Definition: ControlFlow.py:109
GaudiConfig.ControlFlow.ControlFlowNode.__or__
def __or__(self, rhs)
Definition: ControlFlow.py:31
GaudiConfig.ControlFlow._TestVisitor.__init__
def __init__(self)
Definition: ControlFlow.py:225
GaudiConfig.ControlFlow._TestAlgorithm.name
def name(self)
Definition: ControlFlow.py:246
GaudiConfig.ControlFlow.ignore
Definition: ControlFlow.py:175
GaudiConfig.ControlFlow.ControlFlowBool.__and__
def __and__(self, rhs)
Definition: ControlFlow.py:91
GaudiConfig.ControlFlow.par.item
item
Definition: ControlFlow.py:192
GaudiConfig.ControlFlow.InvertNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:171
GaudiConfig.ControlFlow.ControlFlowNode.__hash__
def __hash__(self)
Definition: ControlFlow.py:55
GaudiConfig.ControlFlow.OrNode.rhs
rhs
Definition: ControlFlow.py:150
Algorithm
Alias for backward compatibility.
Definition: Algorithm.h:58
GaudiConfig.ControlFlow.DotVisitor.number
number
Definition: ControlFlow.py:254
GaudiConfig.ControlFlow.DotVisitor.__init__
def __init__(self)
Definition: ControlFlow.py:251
GaudiConfig.ControlFlow.seq.item
item
Definition: ControlFlow.py:203
GaudiConfig.ControlFlow.test
def test()
Definition: ControlFlow.py:335
GaudiConfig.ControlFlow.ControlFlowNode.__invert__
def __invert__(self)
Definition: ControlFlow.py:38
GaudiConfig.ControlFlow.DotVisitor.write
def write(self, filename)
Definition: ControlFlow.py:316
GaudiConfig.ControlFlow.line.item
item
Definition: ControlFlow.py:215
GaudiConfig.ControlFlow.ignore.__repr__
def __repr__(self)
Definition: ControlFlow.py:183
GaudiConfig.ControlFlow.ignore.__init__
def __init__(self, item)
Definition: ControlFlow.py:180
GaudiConfig.ControlFlow.seq
Definition: ControlFlow.py:201
GaudiConfig.ControlFlow.OrderedNode.__repr__
def __repr__(self)
Definition: ControlFlow.py:118
GaudiConfig.ControlFlow.par
Definition: ControlFlow.py:190
GaudiConfig.ControlFlow.OrderedNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:121
GaudiConfig.ControlFlow.OrNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:155
GaudiConfig.ControlFlow.ControlFlowNode.__and__
def __and__(self, rhs)
Definition: ControlFlow.py:24
GaudiConfig.ControlFlow.OrNode
Definition: ControlFlow.py:143
GaudiConfig.ControlFlow.InvertNode.__repr__
def __repr__(self)
Definition: ControlFlow.py:168
GaudiConfig.ControlFlow.OrderedNode.rhs
rhs
Definition: ControlFlow.py:116
GaudiConfig.ControlFlow.DotVisitor
Definition: ControlFlow.py:250
GaudiKernel.Configurable.makeSequences
def makeSequences(expression)
Definition: Configurable.py:1829
GaudiConfig.ControlFlow.ControlFlowNode.getFullName
def getFullName(self)
Definition: ControlFlow.py:64
GaudiConfig.ControlFlow.line._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:220
GaudiConfig.ControlFlow._TestVisitor
Definition: ControlFlow.py:224
GaudiConfig.ControlFlow._TestAlgorithm
Definition: ControlFlow.py:239
GaudiConfig.ControlFlow.AndNode.lhs
lhs
Definition: ControlFlow.py:132
GaudiConfig.ControlFlow.DotVisitor.is_needed
def is_needed(self, visitee)
Definition: ControlFlow.py:308
GaudiConfig.ControlFlow.DotVisitor.nodes
nodes
Definition: ControlFlow.py:252
GaudiConfig.ControlFlow.DotVisitor.leave
def leave(self, visitee)
Definition: ControlFlow.py:290
GaudiKernel.Configurable
Definition: Configurable.py:1
GaudiConfig.ControlFlow.ignore._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:186
GaudiConfig.ControlFlow.DotVisitor.stack
stack
Definition: ControlFlow.py:255
GaudiConfig.ControlFlow.line.__init__
def __init__(self, name, item)
Definition: ControlFlow.py:213
GaudiConfig.ControlFlow._TestAlgorithm.__repr__
def __repr__(self)
Definition: ControlFlow.py:243
GaudiConfig.ControlFlow._TestVisitor.enter
def enter(self, visitee)
Definition: ControlFlow.py:228
GaudiConfig.ControlFlow.par.__repr__
def __repr__(self)
Definition: ControlFlow.py:194
GaudiConfig.ControlFlow.line.__repr__
def __repr__(self)
Definition: ControlFlow.py:217
GaudiConfig.ControlFlow.ControlFlowLeaf
Definition: ControlFlow.py:79
GaudiConfig.ControlFlow.DotVisitor.edges
edges
Definition: ControlFlow.py:253
GaudiConfig.ControlFlow.AndNode.rhs
rhs
Definition: ControlFlow.py:133
GaudiConfig.ControlFlow.ControlFlowNode._fullname
_fullname
Definition: ControlFlow.py:75
GaudiConfig.ControlFlow.ControlFlowBool.__or__
def __or__(self, rhs)
Definition: ControlFlow.py:94
GaudiConfig.ControlFlow.OrderedNode.lhs
lhs
Definition: ControlFlow.py:115
GaudiConfig.ControlFlow.OrNode.__init__
def __init__(self, lhs, rhs)
Definition: ControlFlow.py:148
GaudiConfig.ControlFlow.ControlFlowNode.visitNode
def visitNode(self, visitor)
Definition: ControlFlow.py:44
GaudiConfig.ControlFlow._TestAlgorithm.__init__
def __init__(self, name)
Definition: ControlFlow.py:240
GaudiConfig.ControlFlow.InvertNode
Definition: ControlFlow.py:160
gaudirun.type
type
Definition: gaudirun.py:160
GaudiConfig.ControlFlow.seq.__init__
def __init__(self, item)
Definition: ControlFlow.py:202
GaudiConfig.ControlFlow.ControlFlowBool.__repr__
def __repr__(self)
Definition: ControlFlow.py:100
GaudiConfig.ControlFlow.ControlFlowNode.__rshift__
def __rshift__(self, rhs)
Definition: ControlFlow.py:41
GaudiConfig.ControlFlow.DotVisitor.collapse_identical_ancestors
def collapse_identical_ancestors(self, thetype)
Definition: ControlFlow.py:293
GaudiConfig.ControlFlow.ControlFlowBool
Definition: ControlFlow.py:87
GaudiConfig.ControlFlow.ControlFlowNode
Definition: ControlFlow.py:19
GaudiConfig.ControlFlow.AndNode.__init__
def __init__(self, lhs, rhs)
Definition: ControlFlow.py:131
GaudiConfig.ControlFlow.InvertNode.item
item
Definition: ControlFlow.py:166
GaudiConfig.ControlFlow._TestAlgorithm._name
_name
Definition: ControlFlow.py:241
GaudiConfig.ControlFlow._TestVisitor.leave
def leave(self, visitee)
Definition: ControlFlow.py:234
GaudiConfig.ControlFlow.AndNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:138
GaudiConfig.ControlFlow.InvertNode.__init__
def __init__(self, item)
Definition: ControlFlow.py:165
GaudiConfig.ControlFlow.line
Definition: ControlFlow.py:212
GaudiConfig.ControlFlow.OrderedNode.__init__
def __init__(self, lhs, rhs)
Definition: ControlFlow.py:114
GaudiConfig.ControlFlow.seq._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:208
GaudiConfig.ControlFlow.ControlFlowBool.__invert__
def __invert__(self)
Definition: ControlFlow.py:97
GaudiConfig.ControlFlow.DotVisitor.enter
def enter(self, visitee)
Definition: ControlFlow.py:258
GaudiConfig.ControlFlow.ignore.item
item
Definition: ControlFlow.py:181
GaudiConfig.ControlFlow.ControlFlowNode.__eq__
def __eq__(self, other)
Definition: ControlFlow.py:52
GaudiConfig.ControlFlow.ControlFlowBool.__init__
def __init__(self, value)
Definition: ControlFlow.py:88
GaudiConfig.ControlFlow.DotVisitor.ids
ids
Definition: ControlFlow.py:256
GaudiConfig.ControlFlow.OrNode.lhs
lhs
Definition: ControlFlow.py:149
GaudiConfig.ControlFlow.par.__init__
def __init__(self, item)
Definition: ControlFlow.py:191
GaudiConfig.ControlFlow.OrNode.__repr__
def __repr__(self)
Definition: ControlFlow.py:152
GaudiConfig.ControlFlow.AndNode
Definition: ControlFlow.py:126