Files
reactics/examples/bdd/generators/gen_asm.py
Artur Meski f0019619b3 Refactor + tests (#6)
- Minor codebase clean-up
- Slight reorganisation of examples + tests so that we don't break stuff by accident
- CI tests
2026-04-10 18:16:49 +01:00

104 lines
2.9 KiB
Python

#!/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()