The Gaudi Framework  v36r1 (3e2fb5a8)
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
75  return self._fullname
76 
77 
79  '''
80  Class used to identify a note without sub-nodes.
81  '''
82  pass
83 
84 
85 class ControlFlowBool(ControlFlowLeaf):
86  def __init__(self, value):
87  self.value = value
88 
89  def __and__(self, rhs):
90  return rhs if self.value else self
91 
92  def __or__(self, rhs):
93  return self if self.value else rhs
94 
95  def __invert__(self):
96  return CFFalse if self.value else CFTrue
97 
98  def __repr__(self):
99  return 'CFTrue' if self.value else 'CFFalse'
100 
101 
102 CFTrue = ControlFlowBool(True)
103 CFFalse = ControlFlowBool(False)
104 del ControlFlowBool
105 
106 
108  '''
109  Represent order of execution of nodes.
110  '''
111 
112  def __init__(self, lhs, rhs):
113  self.lhs = lhs
114  self.rhs = rhs
115 
116  def __repr__(self):
117  return "(%r >> %r)" % (self.lhs, self.rhs)
118 
119  def _visitSubNodes(self, visitor):
120  self.lhs.visitNode(visitor)
121  self.rhs.visitNode(visitor)
122 
123 
125  '''
126  And operation between control flow nodes.
127  '''
128 
129  def __init__(self, lhs, rhs):
130  self.lhs = lhs
131  self.rhs = rhs
132 
133  def __repr__(self):
134  return "(%r & %r)" % (self.lhs, self.rhs)
135 
136  def _visitSubNodes(self, visitor):
137  self.lhs.visitNode(visitor)
138  self.rhs.visitNode(visitor)
139 
140 
142  '''
143  Or operation between control flow nodes.
144  '''
145 
146  def __init__(self, lhs, rhs):
147  self.lhs = lhs
148  self.rhs = rhs
149 
150  def __repr__(self):
151  return "(%r | %r)" % (self.lhs, self.rhs)
152 
153  def _visitSubNodes(self, visitor):
154  self.lhs.visitNode(visitor)
155  self.rhs.visitNode(visitor)
156 
157 
159  '''
160  Invert logic (negation) of a control flow node.
161  '''
162 
163  def __init__(self, item):
164  self.item = item
165 
166  def __repr__(self):
167  return "~%r" % self.item
168 
169  def _visitSubNodes(self, visitor):
170  self.item.visitNode(visitor)
171 
172 
174  '''
175  Treat a control flow node as always successful, equivalent to (a | ~ a).
176  '''
177 
178  def __init__(self, item):
179  self.item = item
180 
181  def __repr__(self):
182  return "ignore(%r)" % self.item
183 
184  def _visitSubNodes(self, visitor):
185  self.item.visitNode(visitor)
186 
187 
189  def __init__(self, item):
190  self.item = item
191 
192  def __repr__(self):
193  return "par(%r)" % self.item
194 
195  def _visitSubNodes(self, visitor):
196  self.item.visitNode(visitor)
197 
198 
200  def __init__(self, item):
201  self.item = item
202 
203  def __repr__(self):
204  return "seq(%r)" % self.item
205 
206  def _visitSubNodes(self, visitor):
207  self.item.visitNode(visitor)
208 
209 
210 class line(object):
211  def __init__(self, name, item):
212  self.name = name
213  self.item = item
214 
215  def __repr__(self):
216  return "line(%r, %r)" % (self.name, self.item)
217 
218  def _visitSubNodes(self, visitor):
219  self.item.visitNode(visitor)
220 
221 
222 class _TestVisitor(object):
223  def __init__(self):
224  self.depths = 0
225 
226  def enter(self, visitee):
227  self.depths += 1
228  print("%sEntering %s" % (self.depths * " ", type(visitee)))
229  if isinstance(visitee, ControlFlowLeaf):
230  print("%s Algorithm name: %s" % (" " * self.depths, visitee))
231 
232  def leave(self, visitee):
233  print("%sLeaving %s" % (self.depths * " ", type(visitee)))
234  self.depths -= 1
235 
236 
238  def __init__(self, name):
239  self._name = name
240 
241  def __repr__(self):
242  return self._name
243 
244  def name(self):
245  return self._name
246 
247 
248 class DotVisitor(object):
249  def __init__(self):
250  self.nodes = []
251  self.edges = []
252  self.number = 0
253  self.stack = []
254  self.ids = {}
255 
256  def enter(self, visitee):
257  if visitee not in self.ids:
258  self.number += 1
259  dot_id = self.ids[visitee] = 'T%s' % self.number
260  dot_id = self.ids[visitee]
261  mother = None
262  if self.is_needed(visitee):
263  if isinstance(visitee, ControlFlowLeaf):
264  entry = '%s [label="%s", shape=box]' % (dot_id, visitee.name())
265  elif isinstance(visitee, OrNode):
266  entry = '%s [label="OR", shape=invhouse]' % dot_id
267  elif isinstance(visitee, AndNode):
268  entry = '%s [label="AND", shape=invhouse]' % dot_id
269  elif isinstance(visitee, OrderedNode):
270  entry = '%s [label=">>", shape=point]' % dot_id
271  elif isinstance(visitee, InvertNode):
272  entry = '%s [label="NOT", shape=circle, color=red]' % dot_id
273  elif isinstance(visitee, par):
274  entry = '%s [label="PAR", shape=circle]' % dot_id
275  elif isinstance(visitee, seq):
276  entry = '%s [label="SEQ", shape=circle]' % dot_id
277  else:
278  entry = '%s [label="%s", shape=circle]' % (dot_id,
279  type(visitee))
280  self.nodes.append(entry)
281  if len(self.stack) != 0:
282  mother = self.collapse_identical_ancestors(
283  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 """ % ("\n".join(self.nodes), "\n".join(self.edges))
327 
328  with open(filename, "w") as outfile:
329  outfile.write(output)
330 
331 
332 def test():
333  Algorithm = _TestAlgorithm
334 
335  a = Algorithm("a")
336  b = Algorithm("b")
337  c = Algorithm("c")
338  d = Algorithm("d")
339  e = Algorithm("e")
340  f = Algorithm("f")
341  g = Algorithm("g")
342  sequence = seq(b >> a >> f)
343  expression = sequence | ~c & par(d & e & g)
344  a = (expression == expression)
345  aLine = line("MyTriggerPath", expression)
346  visitor = _TestVisitor()
347  visitor2 = DotVisitor()
348  print("\nPrinting trigger line:")
349  print(aLine)
350  print("\nPrinting expression:")
351  print(expression)
352  print("\nTraversing through expression:\n")
353  expression.visitNode(visitor)
354  expression.visitNode(visitor2)
355  visitor2.write("out.dot")
GaudiConfig.ControlFlow.AndNode.__repr__
def __repr__(self)
Definition: ControlFlow.py:133
GaudiConfig.ControlFlow.seq.__repr__
def __repr__(self)
Definition: ControlFlow.py:203
GaudiConfig.ControlFlow.line.name
name
Definition: ControlFlow.py:212
GaudiConfig.ControlFlow.ControlFlowBool.value
value
Definition: ControlFlow.py:87
GaudiConfig.ControlFlow.ControlFlowNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:49
GaudiConfig.ControlFlow._TestVisitor.depths
depths
Definition: ControlFlow.py:224
GaudiConfig.ControlFlow.par._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:195
GaudiConfig.ControlFlow.OrderedNode
Definition: ControlFlow.py:107
GaudiConfig.ControlFlow.ControlFlowNode.__or__
def __or__(self, rhs)
Definition: ControlFlow.py:31
GaudiConfig.ControlFlow._TestVisitor.__init__
def __init__(self)
Definition: ControlFlow.py:223
GaudiConfig.ControlFlow._TestAlgorithm.name
def name(self)
Definition: ControlFlow.py:244
GaudiConfig.ControlFlow.ignore
Definition: ControlFlow.py:173
GaudiConfig.ControlFlow.ControlFlowBool.__and__
def __and__(self, rhs)
Definition: ControlFlow.py:89
GaudiConfig.ControlFlow.par.item
item
Definition: ControlFlow.py:190
GaudiConfig.ControlFlow.InvertNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:169
GaudiConfig.ControlFlow.ControlFlowNode.__hash__
def __hash__(self)
Definition: ControlFlow.py:55
GaudiConfig.ControlFlow.OrNode.rhs
rhs
Definition: ControlFlow.py:148
Algorithm
Alias for backward compatibility.
Definition: Algorithm.h:58
GaudiConfig.ControlFlow.DotVisitor.number
number
Definition: ControlFlow.py:252
GaudiConfig.ControlFlow.DotVisitor.__init__
def __init__(self)
Definition: ControlFlow.py:249
GaudiConfig.ControlFlow.seq.item
item
Definition: ControlFlow.py:201
GaudiConfig.ControlFlow.test
def test()
Definition: ControlFlow.py:332
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:213
GaudiConfig.ControlFlow.ignore.__repr__
def __repr__(self)
Definition: ControlFlow.py:181
GaudiConfig.ControlFlow.ignore.__init__
def __init__(self, item)
Definition: ControlFlow.py:178
GaudiConfig.ControlFlow.seq
Definition: ControlFlow.py:199
GaudiConfig.ControlFlow.OrderedNode.__repr__
def __repr__(self)
Definition: ControlFlow.py:116
GaudiConfig.ControlFlow.par
Definition: ControlFlow.py:188
GaudiConfig.ControlFlow.OrderedNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:119
GaudiConfig.ControlFlow.OrNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:153
GaudiConfig.ControlFlow.ControlFlowNode.__and__
def __and__(self, rhs)
Definition: ControlFlow.py:24
GaudiConfig.ControlFlow.OrNode
Definition: ControlFlow.py:141
GaudiConfig.ControlFlow.InvertNode.__repr__
def __repr__(self)
Definition: ControlFlow.py:166
GaudiConfig.ControlFlow.OrderedNode.rhs
rhs
Definition: ControlFlow.py:114
GaudiConfig.ControlFlow.DotVisitor
Definition: ControlFlow.py:248
GaudiKernel.Configurable.makeSequences
def makeSequences(expression)
Definition: Configurable.py:1765
GaudiConfig.ControlFlow.ControlFlowNode.getFullName
def getFullName(self)
Definition: ControlFlow.py:64
GaudiConfig.ControlFlow.line._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:218
GaudiConfig.ControlFlow._TestVisitor
Definition: ControlFlow.py:222
GaudiConfig.ControlFlow._TestAlgorithm
Definition: ControlFlow.py:237
GaudiConfig.ControlFlow.AndNode.lhs
lhs
Definition: ControlFlow.py:130
GaudiConfig.ControlFlow.DotVisitor.is_needed
def is_needed(self, visitee)
Definition: ControlFlow.py:308
GaudiConfig.ControlFlow.DotVisitor.nodes
nodes
Definition: ControlFlow.py:250
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:184
GaudiConfig.ControlFlow.DotVisitor.stack
stack
Definition: ControlFlow.py:253
GaudiConfig.ControlFlow.line.__init__
def __init__(self, name, item)
Definition: ControlFlow.py:211
GaudiConfig.ControlFlow._TestAlgorithm.__repr__
def __repr__(self)
Definition: ControlFlow.py:241
GaudiConfig.ControlFlow._TestVisitor.enter
def enter(self, visitee)
Definition: ControlFlow.py:226
GaudiConfig.ControlFlow.par.__repr__
def __repr__(self)
Definition: ControlFlow.py:192
GaudiConfig.ControlFlow.line.__repr__
def __repr__(self)
Definition: ControlFlow.py:215
GaudiConfig.ControlFlow.ControlFlowLeaf
Definition: ControlFlow.py:78
GaudiConfig.ControlFlow.DotVisitor.edges
edges
Definition: ControlFlow.py:251
GaudiConfig.ControlFlow.AndNode.rhs
rhs
Definition: ControlFlow.py:131
GaudiConfig.ControlFlow.ControlFlowNode._fullname
_fullname
Definition: ControlFlow.py:74
GaudiConfig.ControlFlow.ControlFlowBool.__or__
def __or__(self, rhs)
Definition: ControlFlow.py:92
GaudiConfig.ControlFlow.OrderedNode.lhs
lhs
Definition: ControlFlow.py:113
GaudiConfig.ControlFlow.OrNode.__init__
def __init__(self, lhs, rhs)
Definition: ControlFlow.py:146
GaudiConfig.ControlFlow.ControlFlowNode.visitNode
def visitNode(self, visitor)
Definition: ControlFlow.py:44
GaudiConfig.ControlFlow._TestAlgorithm.__init__
def __init__(self, name)
Definition: ControlFlow.py:238
GaudiConfig.ControlFlow.InvertNode
Definition: ControlFlow.py:158
gaudirun.type
type
Definition: gaudirun.py:154
GaudiConfig.ControlFlow.seq.__init__
def __init__(self, item)
Definition: ControlFlow.py:200
GaudiConfig.ControlFlow.ControlFlowBool.__repr__
def __repr__(self)
Definition: ControlFlow.py:98
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:85
GaudiConfig.ControlFlow.ControlFlowNode
Definition: ControlFlow.py:19
GaudiConfig.ControlFlow.AndNode.__init__
def __init__(self, lhs, rhs)
Definition: ControlFlow.py:129
GaudiConfig.ControlFlow.InvertNode.item
item
Definition: ControlFlow.py:164
GaudiConfig.ControlFlow._TestAlgorithm._name
_name
Definition: ControlFlow.py:239
GaudiConfig.ControlFlow._TestVisitor.leave
def leave(self, visitee)
Definition: ControlFlow.py:232
GaudiConfig.ControlFlow.AndNode._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:136
GaudiConfig.ControlFlow.InvertNode.__init__
def __init__(self, item)
Definition: ControlFlow.py:163
GaudiConfig.ControlFlow.line
Definition: ControlFlow.py:210
GaudiConfig.ControlFlow.OrderedNode.__init__
def __init__(self, lhs, rhs)
Definition: ControlFlow.py:112
GaudiConfig.ControlFlow.seq._visitSubNodes
def _visitSubNodes(self, visitor)
Definition: ControlFlow.py:206
GaudiConfig.ControlFlow.ControlFlowBool.__invert__
def __invert__(self)
Definition: ControlFlow.py:95
GaudiConfig.ControlFlow.DotVisitor.enter
def enter(self, visitee)
Definition: ControlFlow.py:256
GaudiConfig.ControlFlow.ignore.item
item
Definition: ControlFlow.py:179
GaudiConfig.ControlFlow.ControlFlowNode.__eq__
def __eq__(self, other)
Definition: ControlFlow.py:52
GaudiConfig.ControlFlow.ControlFlowBool.__init__
def __init__(self, value)
Definition: ControlFlow.py:86
GaudiConfig.ControlFlow.DotVisitor.ids
ids
Definition: ControlFlow.py:254
GaudiConfig.ControlFlow.OrNode.lhs
lhs
Definition: ControlFlow.py:147
GaudiConfig.ControlFlow.par.__init__
def __init__(self, item)
Definition: ControlFlow.py:189
GaudiConfig.ControlFlow.OrNode.__repr__
def __repr__(self)
Definition: ControlFlow.py:150
GaudiConfig.ControlFlow.AndNode
Definition: ControlFlow.py:124