12 Classes for the implementation of the Control Flow Structure Syntax.
14 @see: https://github.com/lhcb/scheduling-event-model/tree/master/controlflow_syntax
16 from __future__
import print_function
21 Basic entry in the control flow graph.
53 return repr(self) == repr(other)
56 """Return a unique identifier for this object.
58 As we use the `repr` of this object to check for equality, we use it
59 here to define uniqueness.
62 return hash((repr(self),))
66 Allow use of an expression as an algorihtm/sequence in a Gaudi job
69 Convert the expression in nested sequencers and return the full name of
72 if not hasattr(self,
"_fullname"):
81 Class used to identify a note without sub-nodes.
87 class ControlFlowBool(ControlFlowLeaf):
92 return rhs
if self.
value else self
95 return self
if self.
value else rhs
98 return CFFalse
if self.
value else CFTrue
101 return "CFTrue" if self.
value else "CFFalse"
111 Represent order of execution of nodes.
119 return "(%r >> %r)" % (self.
lhs, self.
rhs)
128 And operation between control flow nodes.
136 return "(%r & %r)" % (self.
lhs, self.
rhs)
145 Or operation between control flow nodes.
153 return "(%r | %r)" % (self.
lhs, self.
rhs)
162 Invert logic (negation) of a control flow node.
169 return "~%r" % self.
item
177 Treat a control flow node as always successful, equivalent to (a | ~ a).
184 return "ignore(%r)" % self.
item
195 return "par(%r)" % self.
item
206 return "seq(%r)" % self.
item
218 return "line(%r, %r)" % (self.
name, self.
item)
221 self.
item.visitNode(visitor)
230 print(
"%sEntering %s" % (self.
depths *
" ",
type(visitee)))
231 if isinstance(visitee, ControlFlowLeaf):
232 print(
"%s Algorithm name: %s" % (
" " * self.
depths, visitee))
235 print(
"%sLeaving %s" % (self.
depths *
" ",
type(visitee)))
259 if visitee
not in self.
ids:
261 dot_id = self.
ids[visitee] =
"T%s" % self.
number
262 dot_id = self.
ids[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
280 entry =
'%s [label="%s", shape=circle]' % (dot_id,
type(visitee))
281 self.
nodes.append(entry)
282 if len(self.
stack) != 0:
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))
295 If AND nodes are inside AND nodes, the graph could be simplified
296 to not contain those (same true for OR and ordered)
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:
310 Check whether this node is actually needed
312 if len(self.
stack) != 0:
313 return not isinstance(visitee,
type(self.
stack[-1][0]))
327 "\n".join(self.
nodes),
328 "\n".join(self.
edges),
331 with open(filename,
"w")
as outfile:
332 outfile.write(output)
336 Algorithm = _TestAlgorithm
345 sequence =
seq(b >> a >> f)
346 expression = sequence | ~c &
par(d & e & g)
347 a = expression == expression
348 aLine =
line(
"MyTriggerPath", expression)
351 print(
"\nPrinting trigger line:")
353 print(
"\nPrinting expression:")
355 print(
"\nTraversing through expression:\n")
356 expression.visitNode(visitor)
357 expression.visitNode(visitor2)
358 visitor2.write(
"out.dot")