Refactor + tests (#6)
- Minor codebase clean-up - Slight reorganisation of examples + tests so that we don't break stuff by accident - CI tests
This commit was merged in pull request #6.
This commit is contained in:
103
examples/bdd/generators/gen_asm.py
Normal file
103
examples/bdd/generators/gen_asm.py
Normal file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generator for the Assembly-line (ASM) benchmark.
|
||||
|
||||
Produces a distributed reaction system modelling an assembly line
|
||||
where N sequential processes pass activation tokens. Each process
|
||||
cycles through entities a -> y,b -> c -> d, and the final process
|
||||
signals 'done'. Uses a context automaton for scheduling.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
OPTIONS = "options { use-context-automaton; make-progressive; };\n"
|
||||
|
||||
PROC_TEMPLATE = """
|
||||
proc{i} {{
|
||||
{{{{a}}, {{s}} -> {{y}}}};
|
||||
{{{{y}}, {{s}} -> {{y}}}};
|
||||
{{{{a}}, {{s}} -> {{b}}}};
|
||||
{{{{b}}, {{s}} -> {{c}}}};
|
||||
{{{{c}}, {{s}} -> {{d}}}};
|
||||
{{{{d,y}}, {{s}} -> {{dy}}}};
|
||||
}};
|
||||
"""
|
||||
|
||||
FINAL_PROC = """
|
||||
procFinal {
|
||||
{{done}, {s} -> {done}};
|
||||
};
|
||||
"""
|
||||
|
||||
CA_TEMPLATE = """
|
||||
context-automaton {{
|
||||
states {{ init, act }};
|
||||
init-state {{ init }};
|
||||
transitions {{
|
||||
{transitions}
|
||||
}};
|
||||
}};
|
||||
"""
|
||||
|
||||
PROPERTY_TEMPLATE = '\nrsctlk-property {{ {name} : {formula} }};\n'
|
||||
|
||||
|
||||
def generate(n):
|
||||
out = OPTIONS
|
||||
out += "\nreactions {\n"
|
||||
for i in range(1, n + 1):
|
||||
out += PROC_TEMPLATE.format(i=i)
|
||||
out += FINAL_PROC
|
||||
out += "};\n"
|
||||
|
||||
indent = 8 * " "
|
||||
transitions = ""
|
||||
|
||||
# init -> act: first process gets activated
|
||||
transitions += "{indent}{{ proc1={{a}} }}: init -> act;\n".format(indent=indent)
|
||||
|
||||
# act -> act: process stays idle (dy not produced)
|
||||
for i in range(1, n + 1):
|
||||
transitions += "{indent}{{ proc{i}={{}} }}: act -> act : ~proc{i}.dy;\n".format(
|
||||
indent=indent, i=i)
|
||||
|
||||
# act -> act: next process gets activated when previous produces 'dy'
|
||||
for i in range(2, n + 1):
|
||||
transitions += "{indent}{{ proc{i}={{a}} }}: act -> act : proc{prev}.dy;\n".format(
|
||||
indent=indent, i=i, prev=i - 1)
|
||||
|
||||
# act -> act: final process signals done when all have produced 'dy'
|
||||
all_dy = " AND ".join("proc{}.dy".format(i) for i in range(1, n + 1))
|
||||
transitions += "{indent}{{ procFinal={{done}} }}: act -> act : {guard};\n".format(
|
||||
indent=indent, guard=all_dy)
|
||||
|
||||
out += CA_TEMPLATE.format(transitions=transitions)
|
||||
|
||||
# f1: the assembly line eventually completes
|
||||
out += PROPERTY_TEMPLATE.format(name="f1", formula="EF( procFinal.done )")
|
||||
|
||||
# f2: last process knows its predecessor has produced 'y'
|
||||
f2 = "AG( proc{n}.d IMPLIES K[proc{n}]( proc{prev}.y ) )".format(n=n, prev=n - 1)
|
||||
out += PROPERTY_TEMPLATE.format(name="f2", formula=f2)
|
||||
|
||||
# x1: negation of f1 (sanity check -- should also hold)
|
||||
out += PROPERTY_TEMPLATE.format(name="x1", formula="EF( ~procFinal.done )")
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument("n", type=int, help="number of processes (must be > 1)")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.n < 2:
|
||||
parser.error("number of processes must be > 1")
|
||||
|
||||
print(generate(args.n))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user