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