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'):
80 Class used to identify a note without sub-nodes.
85 class ControlFlowBool(ControlFlowLeaf):
90 return rhs
if self.
value else self
93 return self
if self.
value else rhs
96 return CFFalse
if self.
value else CFTrue
99 return 'CFTrue' if self.
value else 'CFFalse'
109 Represent order of execution of nodes.
117 return "(%r >> %r)" % (self.
lhs, self.
rhs)
126 And operation between control flow nodes.
134 return "(%r & %r)" % (self.
lhs, self.
rhs)
143 Or operation between control flow nodes.
151 return "(%r | %r)" % (self.
lhs, self.
rhs)
160 Invert logic (negation) of a control flow node.
167 return "~%r" % self.
item
175 Treat a control flow node as always successful, equivalent to (a | ~ a).
182 return "ignore(%r)" % self.
item
193 return "par(%r)" % self.
item
204 return "seq(%r)" % self.
item
216 return "line(%r, %r)" % (self.
name, self.
item)
219 self.
item.visitNode(visitor)
228 print(
"%sEntering %s" % (self.
depths *
" ",
type(visitee)))
229 if isinstance(visitee, ControlFlowLeaf):
230 print(
"%s Algorithm name: %s" % (
" " * self.
depths, visitee))
233 print(
"%sLeaving %s" % (self.
depths *
" ",
type(visitee)))
257 if visitee
not in self.
ids:
259 dot_id = self.
ids[visitee] =
'T%s' % self.
number
260 dot_id = self.
ids[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
278 entry =
'%s [label="%s", shape=circle]' % (dot_id,
280 self.
nodes.append(entry)
281 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]))
326 """ % (
"\n".join(self.
nodes),
"\n".join(self.
edges))
328 with open(filename,
"w")
as outfile:
329 outfile.write(output)
333 Algorithm = _TestAlgorithm
342 sequence =
seq(b >> a >> f)
343 expression = sequence | ~c &
par(d & e & g)
344 a = (expression == expression)
345 aLine =
line(
"MyTriggerPath", expression)
348 print(
"\nPrinting trigger line:")
350 print(
"\nPrinting expression:")
352 print(
"\nTraversing through expression:\n")
353 expression.visitNode(visitor)
354 expression.visitNode(visitor2)
355 visitor2.write(
"out.dot")