Files
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

89 lines
3.0 KiB
Python

#!/usr/bin/env python3
"""
Generator for the Binary Counter (BC) benchmark.
Produces a reaction system modelling an N-bit binary counter
with increment and decrement operations controlled via context
entities. Generates one of four RSCTL properties.
NOTE: generates old-syntax input (context-entities, initial-contexts,
rsctl-property) which is not compatible with the current parser.
"""
import argparse
K = 8 # constant used by property 3
def generate(n, prop):
out = "reactions {\n"
# (1) no dec, no inc: bits persist
out += "\t# (1) no decrement, no increment\n"
for j in range(n):
out += "\t{{{{p{j}}},{{dec,inc}} -> {{p{j}}}}};\n".format(j=j)
# (2) increment operation
out += "\n\t# (2) increment operation\n"
out += "\t{{inc},{dec,p0} -> {p0}};\n"
for j in range(1, n):
bits = ",".join("p" + str(k) for k in range(j))
out += "\t{{{{inc,{bits}}},{{dec,p{j}}} -> {{p{j}}}}};\n".format(bits=bits, j=j)
out += "\n\t# the more significant bits remain (inc)\n"
for j in range(n):
for k in range(j + 1, n):
out += "\t{{{{inc,p{k}}},{{dec,p{j}}} -> {{p{k}}}}};\n".format(j=j, k=k)
# (3) decrement operation
out += "\n\t# (3) decrement operation\n"
for j in range(n):
bits = ",".join("p" + str(k) for k in range(j + 1))
out += "\t{{{{dec}},{{inc,{bits}}} -> {{p{j}}}}};\n".format(bits=bits, j=j)
out += "\n\t# the more significant bits remain (dec)\n"
for j in range(n):
for k in range(j + 1, n):
out += "\t{{{{dec,p{j},p{k}}},{{inc}} -> {{p{k}}}}};\n".format(j=j, k=k)
out += "}\n\n"
out += "context-entities { inc,dec }\n"
out += "initial-contexts { {} }\n"
if prop == 1:
all_neg = " AND ".join("~p" + str(i) for i in range(n))
all_pos = " AND ".join("p" + str(i) for i in range(n))
out += "rsctl-property {{ AG(({}) IMPLIES E[{{inc}},{{dec}}]F({})) }}\n".format(
all_neg, all_pos)
elif prop == 2:
all_pos = " AND ".join("p" + str(i) for i in range(n))
all_neg = " AND ".join("~p" + str(i) for i in range(n))
out += "rsctl-property {{ AG(({}) IMPLIES A[{{inc}}]X({})) }}\n".format(
all_pos, all_neg)
elif prop == 3:
parts = ["p" + str(i) for i in range(n - K)]
parts += ["~p" + str(i) for i in range(n - K, n)]
out += "rsctl-property {{ E[{{inc}}]F({}) }}\n".format(" AND ".join(parts))
elif prop == 4:
out += "rsctl-property {{ AG( p{} IMPLIES EF ~p{} ) }}\n".format(n - 1, n - 1)
return out
def main():
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("n", type=int, help="number of bits")
parser.add_argument("property", type=int, choices=[1, 2, 3, 4],
help="property to generate (1-4)")
args = parser.parse_args()
if args.property == 3 and args.n < K + 1:
parser.error("n must be >= {} for property 3".format(K + 1))
print(generate(args.n, args.property))
if __name__ == "__main__":
main()