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)
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:
309 Check whether this node is actually needed
311 if len(self.
stack) != 0:
312 return not isinstance(visitee,
type(self.
stack[-1][0]))
326 "\n".join(self.
nodes),
327 "\n".join(self.
edges),
330 with open(filename,
"w")
as outfile:
331 outfile.write(output)
335 Algorithm = _TestAlgorithm
344 sequence =
seq(b >> a >> f)
345 expression = sequence | ~c &
par(d & e & g)
346 a = expression == expression
347 aLine =
line(
"MyTriggerPath", expression)
350 print(
"\nPrinting trigger line:")
352 print(
"\nPrinting expression:")
354 print(
"\nTraversing through expression:\n")
355 expression.visitNode(visitor)
356 expression.visitNode(visitor2)
357 visitor2.write(
"out.dot")