| The Gaudi Framework v32r1 (f65d50dc)

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