Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v36r16 (ea80daf8)
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  if len(self.stack) != 0:
299  mother = self.stack[-1][1]
300  for entry in self.stack[::-1]:
301  if type(entry[0]) != thetype:
302  break
303  mother = entry[1]
304  return mother
305  return None
306 
307  def is_needed(self, visitee):
308  """
309  Check whether this node is actually needed
310  """
311  if len(self.stack) != 0:
312  return not isinstance(visitee, type(self.stack[-1][0]))
313  return True
314 
315  def write(self, filename):
316  output = """
317 digraph graphname {
318 rankdir=LR
319 
320 %s
321 
322 %s
323 
324 }
325 """ % (
326  "\n".join(self.nodes),
327  "\n".join(self.edges),
328  )
329 
330  with open(filename, "w") as outfile:
331  outfile.write(output)
332 
333 
334 def test():
335  Algorithm = _TestAlgorithm
336 
337  a = Algorithm("a")
338  b = Algorithm("b")
339  c = Algorithm("c")
340  d = Algorithm("d")
341  e = Algorithm("e")
342  f = Algorithm("f")
343  g = Algorithm("g")
344  sequence = seq(b >> a >> f)
345  expression = sequence | ~c & par(d & e & g)
346  a = expression == expression
347  aLine = line("MyTriggerPath", expression)
348  visitor = _TestVisitor()
349  visitor2 = DotVisitor()
350  print("\nPrinting trigger line:")
351  print(aLine)
352  print("\nPrinting expression:")
353  print(expression)
354  print("\nTraversing through expression:\n")
355  expression.visitNode(visitor)
356  expression.visitNode(visitor2)
357  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:334
GaudiConfig.ControlFlow.ControlFlowNode.__invert__
def __invert__(self)
Definition: ControlFlow.py:38
GaudiConfig.ControlFlow.DotVisitor.write
def write(self, filename)
Definition: ControlFlow.py:315
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:1841
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:307
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:162
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