12 Classes for the implementation of the Control Flow Structure Syntax.
14 @see: https://github.com/lhcb/scheduling-event-model/tree/master/controlflow_syntax
20 Basic entry in the control flow graph.
52 return repr(self) == repr(other)
55 """Return a unique identifier for this object.
57 As we use the `repr` of this object to check for equality, we use it
58 here to define uniqueness.
61 return hash((repr(self),))
65 Allow use of an expression as an algorihtm/sequence in a Gaudi job
68 Convert the expression in nested sequencers and return the full name of
71 if not hasattr(self,
"_fullname"):
80 Class used to identify a note without sub-nodes.
86 class ControlFlowBool(ControlFlowLeaf):
91 return rhs
if self.
value else self
94 return self
if self.
value else rhs
97 return CFFalse
if self.
value else CFTrue
100 return "CFTrue" if self.
value else "CFFalse"
110 Represent order of execution of nodes.
118 return "(%r >> %r)" % (self.
lhs, self.
rhs)
127 And operation between control flow nodes.
135 return "(%r & %r)" % (self.
lhs, self.
rhs)
144 Or operation between control flow nodes.
152 return "(%r | %r)" % (self.
lhs, self.
rhs)
161 Invert logic (negation) of a control flow node.
168 return "~%r" % self.
item
176 Treat a control flow node as always successful, equivalent to (a | ~ a).
183 return "ignore(%r)" % self.
item
194 return "par(%r)" % self.
item
205 return "seq(%r)" % self.
item
217 return "line(%r, %r)" % (self.
name, self.
item)
220 self.
item.visitNode(visitor)
229 print(
"%sEntering %s" % (self.
depths *
" ",
type(visitee)))
230 if isinstance(visitee, ControlFlowLeaf):
231 print(
"%s Algorithm name: %s" % (
" " * self.
depths, visitee))
234 print(
"%sLeaving %s" % (self.
depths *
" ",
type(visitee)))
258 if visitee
not in self.
ids:
260 dot_id = self.
ids[visitee] =
"T%s" % self.
number
261 dot_id = self.
ids[visitee]
264 if isinstance(visitee, ControlFlowLeaf):
265 entry =
'%s [label="%s", shape=box]' % (dot_id, visitee.name())
266 elif isinstance(visitee, OrNode):
267 entry =
'%s [label="OR", shape=invhouse]' % dot_id
268 elif isinstance(visitee, AndNode):
269 entry =
'%s [label="AND", shape=invhouse]' % dot_id
270 elif isinstance(visitee, OrderedNode):
271 entry =
'%s [label=">>", shape=point]' % dot_id
272 elif isinstance(visitee, InvertNode):
273 entry =
'%s [label="NOT", shape=circle, color=red]' % dot_id
274 elif isinstance(visitee, par):
275 entry =
'%s [label="PAR", shape=circle]' % dot_id
276 elif isinstance(visitee, seq):
277 entry =
'%s [label="SEQ", shape=circle]' % dot_id
279 entry =
'%s [label="%s", shape=circle]' % (dot_id,
type(visitee))
280 self.
nodes.append(entry)
281 if len(self.
stack) != 0:
284 mother = self.
stack[-1][1]
285 edge =
"%s->%s" % (dot_id, mother)
286 self.
edges.append(edge)
287 self.
stack.append((visitee, dot_id))
294 If AND nodes are inside AND nodes, the graph could be simplified
295 to not contain those (same true for OR and ordered)
297 if len(self.
stack) != 0:
298 mother = self.
stack[-1][1]
299 for entry
in self.
stack[::-1]:
300 if not isinstance(entry[0], thetype):
308 Check whether this node is actually needed
310 if len(self.
stack) != 0:
311 return not isinstance(visitee,
type(self.
stack[-1][0]))
325 "\n".join(self.
nodes),
326 "\n".join(self.
edges),
329 with open(filename,
"w")
as outfile:
330 outfile.write(output)
334 Algorithm = _TestAlgorithm
343 sequence =
seq(b >> a >> f)
344 expression = sequence | ~c &
par(d & e & g)
345 a = expression == expression
346 aLine =
line(
"MyTriggerPath", expression)
349 print(
"\nPrinting trigger line:")
351 print(
"\nPrinting expression:")
353 print(
"\nTraversing through expression:\n")
354 expression.visitNode(visitor)
355 expression.visitNode(visitor2)
356 visitor2.write(
"out.dot")