18 Commits

Author SHA1 Message Date
ae419e5e0e Failure handling (CI) 2026-04-10 18:27:57 +01:00
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
Marcin Piątkowski
363446821e Released version of GUI (#5)
* The most recent version of ReactICS GUI.

* Small fixes + folder structure update + help file included.

* Added export to XML (for data sharing with GUI)

* Released GUI version.

* Automatic update of the reactants set panel + help content.
2025-06-04 19:21:51 +01:00
Marcin Piątkowski
90c8e4f4c0 Added time and memory measurement for windows. (#4) 2025-05-28 15:21:56 +01:00
fafe8dbe07 Optimisations are now enabled by default 2025-05-08 19:41:27 +01:00
Artur Meski
3237c2eae5 Clean-up 2025-05-05 14:27:07 +01:00
Artur Meski
092fd94b56 README update: website 2025-05-05 14:26:40 +01:00
Artur Meski
f86316cdbd Context Automaton states in transitions (#2) 2025-04-29 13:13:50 +01:00
Marcin Piątkowski
a864329883 Translation into ISPL (for benchmarks with MCMAS) 2025-04-02 20:56:25 +01:00
Artur Meski
48b4f1bb4d Clean-up 2023-11-06 21:10:05 +00:00
Artur Meski
af26ca543b Examples and clean-ups (#1)
- Attempt at implementing an example for DRS
- Complete reactions set
- New automaton
- Formula
- Fixed automaton scaling
- Proc index in the formula
- Benchmark generators
- Scripts to reproduce experiments for reaction mining
2023-11-06 21:09:08 +00:00
Artur Meski
888ed4e68e Update README.md 2023-09-08 15:29:51 +01:00
Artur Meski
a1fb5836a5 black formatting 2023-07-11 19:48:37 +01:00
Artur Meski
8be615b293 Simplified result report 2023-05-11 17:19:53 +01:00
Artur Meski
b4d58b94be Backend mode for easier output parsing 2023-05-10 23:15:44 +01:00
Artur Meski
33ca0fd6e9 build 2022-10-28 21:07:46 +01:00
Artur Meski
632286ec7f Fixed crashes with empty context automaton 2022-03-20 13:22:36 +00:00
Artur Meski
98894fc6e1 Path to bash 2022-03-07 20:29:04 +00:00
121 changed files with 9296 additions and 1921 deletions

112
.github/workflows/tests.yml vendored Normal file
View File

@@ -0,0 +1,112 @@
name: Tests
on:
push:
branches: [master, refactor]
pull_request:
branches: [master]
jobs:
bdd:
name: BDD tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y g++ make bison flex
- name: Build CUDD
working-directory: reactics-bdd
run: ./build_cudd.sh
- name: Build ReactICS BDD module
working-directory: reactics-bdd
run: make
- name: Run BDD tests
run: bash tests/run_tests.sh
smt:
name: SMT tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install Python dependencies
run: pip install z3-solver pytest
- name: Run SMT tests
run: python3 -m pytest tests/test_smt.py -v
generators:
name: Generator tests
runs-on: ubuntu-latest
needs: bdd
steps:
- uses: actions/checkout@v4
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y g++ make bison flex
- name: Build CUDD
working-directory: reactics-bdd
run: ./build_cudd.sh
- name: Build ReactICS BDD module
working-directory: reactics-bdd
run: make
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Run generator tests
shell: bash --noprofile --norc {0}
run: |
set -uo pipefail
REACTICS="$PWD/reactics-bdd/reactics"
GENERATORS="$PWD/examples/bdd/generators"
passed=0
failed=0
check_gen() {
local name="$1" gen_cmd="$2" property="$3" expected="$4"
local tmpfile=$(mktemp /tmp/reactics_gen_XXXXXX.drs)
if ! eval "$gen_cmd" > "$tmpfile" 2>&1; then
echo " FAIL: $name (generator crashed)"
failed=$((failed + 1))
rm -f "$tmpfile"
return
fi
local result=$("$REACTICS" -c "$property" "$tmpfile" 2>&1 | grep -oE "(holds|does not hold)" || true)
rm -f "$tmpfile"
if [ "$result" = "$expected" ]; then
echo " PASS: $name"
passed=$((passed + 1))
else
echo " FAIL: $name (expected '$expected', got '$result')"
failed=$((failed + 1))
fi
}
check_gen "tgc(3) f1" "python3 $GENERATORS/gen_tgc.py 3" f1 "holds"
check_gen "tgc(3) f3" "python3 $GENERATORS/gen_tgc.py 3" f3 "holds"
check_gen "tgc(4) f2" "python3 $GENERATORS/gen_tgc.py 4" f2 "holds"
check_gen "asm(3) f1" "python3 $GENERATORS/gen_asm.py 3" f1 "holds"
check_gen "asm(3) f2" "python3 $GENERATORS/gen_asm.py 3" f2 "holds"
check_gen "drs(2,2,2,a) f0" "python3 $GENERATORS/gen_drs.py 2 2 2 a" f0 "does not hold"
check_gen "drs(2,2,2,b) f0" "python3 $GENERATORS/gen_drs.py 2 2 2 b" f0 "holds"
echo
echo "Generator results: $passed passed, $failed failed"
if [ "$failed" -gt 0 ]; then
exit 1
fi

107
README.md
View File

@@ -3,110 +3,9 @@
Reaction Systems Verification Toolkit
The toolkit consists of two separate modules implementing:
* Methods implemented using binary decision diagrams (BDD) for storing and manipulating the state space of the verified system.
* Methods using binary decision diagrams (BDD) for storing and manipulating the state space of the verified system.
* Methods translating the verification problems into satisfiability modulo theories (SMT).
# Installation
## Installing everything manually
(to be added)
## Virtual Machine
The easiest way to try out ReactICS is to download [the VM where everything is alread installed](http://reactionsystems.org/ReactICS.zip). This a VirtualBox virtual machine. After booting it up, you can log in as `reactics` with the same password. After logging in, ReactICS is available in the `reactics` directory:
```
$ cd reactics
```
An update and setup needs to be performed before running any type of verification:
```
$ ./reactics setup
```
After performing these steps you should be ready to start using ReactICS.
## Examples
The `examples` directory contains sample input files.
### Multi-agent reaction systems (rsCTLK verification)
To quickly test the BDD module you can perform verification of the TGC controller consiting of three trains:
```
$ ./reactics bdd -c f1 examples/bdd/tgc.rs
```
The above command tests the formula labelled `f1` in the input file.
### Reachability
To test the SMT module you can perform reachability verification of the scalable chain system:
Running the benchmark without any arguments tells us what parameters are available:
```
$ ./reactics smt examples/smt/scalable_chain.py
------------------------------------------------
-- ReactICS -- Reaction Systems Model Checker --
------------------------------------------------
arguments: <chainLen> <maxConc> <formulaNumber>
```
We may execute the benchmark for `chainLen=2`, `maxConc=3`, and `formulaNumber=1` using the following command:
```
$ ./reactics smt examples/smt/chain_reaction.py 2 3 1
```
### rsLTL verification
To test the SMT module for rsLTL verification the scalable chain system benchmark may be used.
```
$ ./reactics smt examples/smt/scalable_chain.py 2 5 1
```
### Reaction synthesis
To test the reaction synthesis approach on a mutual exclution protocol modelling three processes, run the following command (three processes, parametric verification, result optimised with OptSMT):
```
$ ./reactics smt examples/smt/mutex_param.py 3 p -o
```
To check the available parameters for the benchmark, we run it with `-h`:
```
$ ./reactics smt examples/smt/mutex_param.py -h
------------------------------------------------
-- ReactICS -- Reaction Systems Model Checker --
------------------------------------------------
usage: mutex_param.py [-h] [-v] [-o] scaling {p,np-p,np-np}
positional arguments:
scaling scaling parameter value
{p,np-p,np-np} Selects the mode: p - parameter synthesis (parametric
implementation), np-p - non-parametric with parametric
implementation (with the parameters substituted), np-np -
non-parametric with non-parametric implementation
(parameters substituted)
optional arguments:
-h, --help show this help message and exit
-v, --verbose turn verbosity on
-o, --optimise minimise the parametric computation result
```
See: https://reactics.org

65
TESTING.md Normal file
View File

@@ -0,0 +1,65 @@
# Testing ReactICS
## Prerequisites
- **BDD module**: compiled (`./reactics setup` or `make` in `reactics-bdd/`)
- **SMT module**: Python 3 with `z3-solver` and `pytest` installed
```
pip install z3-solver pytest
```
## Running all tests
```
./run_tests.sh
```
This runs the BDD, SMT, and generator test suites in sequence.
## BDD tests
```
bash tests/run_tests.sh
```
10 regression tests that run the compiled `reactics-bdd/reactics` binary
against example `.drs` files and compare output to saved baselines in
`tests/expected/`. Covers:
- Parsed system printing (`-P`)
- Reaction listing (`-r`)
- Reachable state enumeration (`-s`)
- RSCTLK model checking (`-c`) for properties f1--f4
Input files: `examples/bdd/tgc.drs`, `examples/bdd/tgc4.drs`,
`reactics-bdd/in/trivial.drs`.
To update baselines after an intentional output change, delete the
relevant file in `tests/expected/` and re-run; the test will regenerate it.
## SMT tests
```
python3 -m pytest tests/test_smt.py -v
```
23 pytest tests exercising the Python API directly. Organised by layer:
- **Data model** -- ReactionSystem, concentrations, context automata,
formula construction (BagDescription, rsLTL)
- **SmtCheckerRS** -- basic reachability (no concentrations)
- **SmtCheckerRSC** -- reachability and rsLTL model checking with
concentrations (chain reaction, heat shock response)
- **SmtCheckerRSCParam** -- parametric verification
- **RSC-to-RS translation** -- verifying the translated system
## Generator tests
7 tests that run each generator (from `examples/bdd/generators/`),
feed the output into the BDD model checker, and verify the expected
verification result (holds / does not hold).
Generators using old syntax (`examples/bdd/generators/old_syntax/`)
are not tested this way as they are not compatible with the current
parser.

View 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()

View File

@@ -0,0 +1,301 @@
#!/usr/bin/env python3
"""
Generator for the DRS (Distributed Reaction Systems) epistemic benchmark.
Produces a distributed reaction system with epistemic properties
(knowledge operators). The system models signal transduction cascades
with configurable depth (x), number of components (y), threshold (z),
and context automaton variant (a or b).
"""
import sys
import argparse
import itertools
class SingleReaction:
def __init__(self, reactants=None, inhibitors=None, products=None):
self.reactants = set(reactants) if reactants is not None else set()
self.inhibitors = set(inhibitors) if inhibitors is not None else set()
self.products = set(products) if products is not None else set()
def get_reactants(self):
return "{" + ", ".join(self.reactants) + "}"
def get_inhibitors(self):
return "{" + ", ".join(self.inhibitors) + "}"
def get_products(self):
return "{" + ", ".join(self.products) + "}"
def __str__(self):
return (
"{"
+ f"{self.get_reactants()}, {self.get_inhibitors()} -> {self.get_products()}"
+ "};"
)
class Reactions:
def __init__(self):
self.reactions = []
def add(self, reaction):
self.reactions.append(reaction)
def __str__(self):
ret = ""
for r in self.reactions:
ret += f"{r}\n"
return ret
class Transition:
def __init__(self, src, dst, guard, context):
self.src = src
self.dst = dst
self.guard = guard
self.context = context
def get_context_str(self):
r = []
for proc, entities in self.context:
ent_str = ",".join(entities)
r.append(f"{proc}={{{ent_str}}}")
r = " ".join(r)
return "{ " + r + " }"
def __str__(self):
if self.guard:
return f"{self.get_context_str()}: {self.src} -> {self.dst} : {self.guard};"
else:
return f"{self.get_context_str()}: {self.src} -> {self.dst};"
class Automaton:
def __init__(self):
self.transitions = []
self.states = []
self.init_state = None
def add_transition(self, transition):
self.transitions.append(transition)
def add_state(self, state):
if state not in self.states:
self.states.append(state)
def set_init_state(self, state):
assert state in self.states, f"{state} not in states"
self.init_state = state
def __str__(self):
r = "context-automaton {\n"
r += "\tstates { " + ", ".join(self.states) + " };\n"
r += f"\tinit-state {{ {self.init_state} }};\n"
r += "\ttransitions {\n"
for tr in self.transitions:
r += "\t\t" + str(tr) + "\n"
r += "\t};\n"
r += "};\n"
return r
class DRSGenerator:
def __init__(self, x, y, z, aut):
assert y >= z
assert x >= 2 and y >= 2 and z >= 2
self.x = x
self.y = y
self.z = z
self.aut_id = aut
self.n = self.y
self.reactions = {}
self.automaton = Automaton()
self.generate()
def generate_agent_zero(self):
rcts = Reactions()
for i in range(1, self.y + 1):
rcts.add(SingleReaction(["RTK"], ["h"], [f"RTK{i}"]))
for j in range(1, self.x + 1):
rcts.add(SingleReaction([f"EN:{j}_{i}"], ["h"], [f"ENi:{self.x}_{i}"]))
return rcts
def generate_reactions_for_component(self, i):
self.reactions.setdefault(i, Reactions())
rcts = self.reactions[i]
rcts.add(SingleReaction(["GF"], ["h"], ["GF"]))
rcts.add(SingleReaction(["GF"], ["h", f"RTK{i}"], ["RTK"]))
rcts.add(SingleReaction(["RTK"], [f"ENi:1_{i}"], [f"EN:1_{i}"]))
for j in range(1, self.x):
rcts.add(
SingleReaction([f"EN:{j}_{i}"], [f"ENi:{j+1}_{i}"], [f"EN:{j+1}_{i}"])
)
indices = list(range(1, self.y + 1))
for comb in itertools.combinations(indices, self.z):
reactants = []
for i in comb:
reactants.append(f"EN:{self.x}_{i}")
rcts.add(SingleReaction(reactants, ["h"], ["TF"]))
def generate(self):
print(f"# Generated for: x = {self.x}, y = {self.y}, z = {self.z}")
print("options { use-context-automaton; make-progressive; };")
print("reactions {")
for i in range(1, self.y + 1):
self.generate_reactions_for_component(i)
rcts_0 = self.generate_agent_zero()
print("proc0 {")
print(rcts_0)
print("};")
for proc, reactions in self.reactions.items():
print(f"proc{proc} {{")
print(reactions)
print("};")
print("};")
if self.aut_id == "a":
self.generate_automaton_4(self.n)
elif self.aut_id == "b":
self.generate_automaton_5(self.n)
else:
raise RuntimeError(f"Unknown automaton identifier: {self.aut_id}")
self.generate_formula()
def generate_automaton_4(self, n):
aut = self.automaton
aut.add_state("qI")
aut.add_state("qS")
for i in range(1, n + 1):
aut.add_state(f"q{i}A")
aut.add_state(f"q{i}B")
aut.add_state(f"q{i}C")
aut.add_state(f"q{i}D")
aut.set_init_state("qI")
aut.add_transition(
Transition("qI", "qS", "", [(f"proc{i}", ["GF"]) for i in range(0, n + 1)])
)
for i in range(1, n + 1):
aut.add_transition(Transition("qS", f"q{i}A", "", [(f"proc{i}", [])]))
aut.add_transition(
Transition(
f"q{i}A", f"q{i}B", "", [(f"proc{v}", []) for v in range(0, n + 1)]
)
)
aut.add_transition(Transition(f"q{i}B", f"q{i}C", "", [(f"proc{i}", [])]))
aut.add_transition(
Transition(
f"q{i}C", f"q{i}D", "", [(f"proc{v}", []) for v in range(0, n + 1)]
)
)
for i in range(1, n + 1):
for j in range(1, n + 1):
if i == j:
continue
aut.add_transition(
Transition(f"q{i}B", f"q{j}A", "", [(f"proc{j}", [])])
)
aut.add_transition(
Transition(f"q{i}D", f"q{j}A", "", [(f"proc{j}", [])])
)
print(aut)
def generate_automaton_5(self, n):
aut = self.automaton
for i in range(0, (4 * n + 1)):
aut.add_state(f"q{i}")
aut.set_init_state("q0")
aut.add_transition(
Transition("q0", "q1", "", [(f"proc{i}", ["GF"]) for i in range(0, n + 1)])
)
for i in range(0, n): # 0, ..., n-1
aut.add_transition(
Transition(f"q{4*i+1}", f"q{4*i+2}", "", [(f"proc{i+1}", [])])
)
aut.add_transition(
Transition(
f"q{4*i+2}",
f"q{4*i+3}",
"",
[(f"proc{v}", []) for v in range(0, n + 1)],
)
)
aut.add_transition(
Transition(f"q{4*i+3}", f"q{4*i+4}", "", [(f"proc{i+1}", [])])
)
for i in range(0, n - 1): # 0, ..., n-2
aut.add_transition(
Transition(
f"q{4*i+4}",
f"q{4*i+5}",
"",
[(f"proc{v}", []) for v in range(0, n + 1)],
)
)
aut.add_transition(
Transition(f"q{4*n}", "q1", "", [(f"proc{i}", []) for i in range(0, n + 1)])
)
print(aut)
def generate_formula(self):
disjunction = " OR ".join([f"proc{i}.TF" for i in range(1, self.y + 1)])
conjunction = " AND ".join([f"~proc{i}.TF" for i in range(1, self.y + 1)])
r = (
"rsctlk-property { f0 : AG( K[proc0]( "
+ disjunction
+ " ) OR K[proc0]( "
+ conjunction
+ " ) ) };"
)
print(r)
def main():
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("x", type=int, help="cascade depth (>= 2)")
parser.add_argument("y", type=int, help="number of components (>= 2, >= z)")
parser.add_argument("z", type=int, help="threshold (>= 2, <= y)")
parser.add_argument("aut", choices=["a", "b"], help="automaton variant")
args = parser.parse_args()
if args.x < 2 or args.y < 2 or args.z < 2:
parser.error("x, y, z must all be >= 2")
if args.y < args.z:
parser.error("y must be >= z")
DRSGenerator(x=args.x, y=args.y, z=args.z, aut=args.aut)
if __name__ == "__main__":
main()

View File

@@ -1,13 +1,20 @@
#!/usr/bin/env python
#!/usr/bin/env python3
"""
Generator for the Traffic Guard Controller (TGC) benchmark.
from sys import argv,exit
OPTIONS_STR = """
options { use-context-automaton; make-progressive; };
Produces a distributed reaction system where N processes compete
for access to a shared resource, governed by a context automaton
with green/red states. Generates RSCTLK properties for liveness,
reachability, and mutual exclusion (epistemic).
"""
PROC_STR = """
proc{:d} {{
import argparse
OPTIONS = "options { use-context-automaton; make-progressive; };\n"
PROC_TEMPLATE = """
proc{i} {{
{{{{out}}, {{}} -> {{approach}}}};
{{{{approach}}, {{req}} -> {{req}}}};
{{{{allowed}}, {{}} -> {{in}}}};
@@ -16,102 +23,94 @@ PROC_STR = """
}};
"""
CA_STR = """
CA_TEMPLATE = """
context-automaton {{
states {{ init, green, red }};
init-state {{ init }};
transitions {{
{:s}
{transitions}
}};
}};
"""
PROPERTY_STR = """
rsctlk-property {{ {:s} : {:s} }};
"""
PROPERTY_TEMPLATE = '\nrsctlk-property {{ {name} : {formula} }};\n'
#################################################################
def conj(fmt, indices, sep=" AND "):
return sep.join(fmt.format(i=i) for i in indices)
if len(argv) < 1:
print("Usage: {:s} <number of processes>".format(argv[0]))
exit(100)
n = int(argv[1])
def generate(n):
out = OPTIONS
out += "\nreactions {\n"
for i in range(n):
out += PROC_TEMPLATE.format(i=i)
out += "};\n"
assert n > 1, "number of proc must be > 1"
indent = 8 * " "
transitions = ""
out = ""
# init -> green: all processes start with 'out'
transitions += indent + "{ "
transitions += " ".join("proc{:d}={{out}}".format(i) for i in range(n))
transitions += " }: init -> green;\n"
out += OPTIONS_STR
out += "reactions {\n"
for i in range(n):
out += PROC_STR.format(i)
out += "};\n"
# green -> red: a process requests
for i in range(n):
transitions += "{indent}{{ proc{i}={{allowed}} }}: green -> red : proc{i}.req;\n".format(
indent=indent, i=i)
transitions = ""
# green -> green: no requests pending
no_req = conj("~proc{i}.req", range(n))
for i in range(n):
transitions += "{indent}{{ proc{i}={{}} }}: green -> green : {guard};\n".format(
indent=indent, i=i, guard=no_req)
init_trans = 8*" " + "{ "
for i in range(n):
init_trans += "proc{:d}={{out}} ".format(i)
init_trans += "}: init -> green;\n"
transitions += init_trans
# red -> green: a process leaves
for i in range(n):
transitions += "{indent}{{ proc{i}={{}} }}: red -> green : proc{i}.leave;\n".format(
indent=indent, i=i)
for i in range(n):
transitions += "{:s}{{ proc{:d}={{allowed}} }}: green -> red : proc{:d}.req;\n".format(8*" ", i, i)
# red -> red: no process leaves
no_leave = conj("~proc{i}.leave", range(n))
for i in range(n):
transitions += "{indent}{{ proc{i}={{}} }}: red -> red : {guard};\n".format(
indent=indent, i=i, guard=no_leave)
no_req_cond = "~proc0.req"
for i in range(1, n):
no_req_cond += " AND ~proc{:d}.req".format(i)
out += CA_TEMPLATE.format(transitions=transitions)
for i in range(n):
transitions += "{:s}{{ proc{:d}={{}} }}: green -> green : {:s};\n".format(8*" ", i, no_req_cond)
# f1: each process can eventually enter
f1 = conj("EF( E<proc{i}.allowed>X( proc{i}.in ) )", range(n))
out += PROPERTY_TEMPLATE.format(name="f1", formula=f1)
for i in range(n):
transitions += "{:s}{{ proc{:d}={{}} }}: red -> green : proc{:d}.leave;\n".format(8*" ", i, i)
# f2: all processes can simultaneously approach
f2 = "EF( " + conj("proc{i}.approach", range(n)) + " )"
out += PROPERTY_TEMPLATE.format(name="f2", formula=f2)
no_leave_cond = "~proc0.leave"
for i in range(1, n):
no_leave_cond += " AND ~proc{:d}.leave".format(i)
# f3: mutual exclusion (knowledge)
others_not_in = conj("~proc{i}.in", range(1, n))
f3 = "AG( proc0.in IMPLIES K[proc0]({}) )".format(others_not_in)
out += PROPERTY_TEMPLATE.format(name="f3", formula=f3)
for i in range(n):
transitions += "{:s}{{ proc{:d}={{}} }}: red -> red : {:s};\n".format(8*" ", i, no_leave_cond)
# f4: mutual exclusion (common knowledge)
all_agents = conj("proc{i}", range(n), sep=",")
f4 = "AG( proc0.in IMPLIES C[{}]({}) )".format(all_agents, others_not_in)
out += PROPERTY_TEMPLATE.format(name="f4", formula=f4)
out += CA_STR.format(transitions)
return out
## f1
#formula = "EF( proc0.in )"
#out += PROPERTY_STR.format("f1",formula)
# f1
formula = "EF( E<proc0.allowed>X( proc0.in ) )"
for i in range(1, n):
formula += " AND EF( E<proc{:d}.allowed>X( proc{:d}.in ) )".format(i, i)
out += PROPERTY_STR.format("f1",formula)
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()
# f2
formula = "EF( proc0.approach"
for i in range(1, n):
formula += " AND proc{:d}.approach".format(i)
formula += " )"
out += PROPERTY_STR.format("f2",formula)
if args.n < 2:
parser.error("number of processes must be > 1")
# f3
subf = "~proc1.in"
for i in range(2, n):
subf += " AND ~proc{:d}.in".format(i)
formula = "AG( proc0.in IMPLIES K[proc0]({:s}) )".format(subf)
out += PROPERTY_STR.format("f3",formula)
print(generate(args.n))
# f4
subf = "~proc1.in"
for i in range(2, n):
subf += " AND ~proc{:d}.in".format(i)
all_agents = "proc0"
for i in range(1, n):
all_agents += ",proc{:d}".format(i)
formula = "AG( proc0.in IMPLIES C[{:s}]({:s}) )".format(all_agents,subf)
out += PROPERTY_STR.format("f4",formula)
print(out)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python3
"""
Generator for the Abstract Pipeline benchmark.
Produces a reaction system modelling a pipeline of N modules,
each cycling through entities a -> y,b -> c -> d before passing
activation to the next module. The final reaction requires all
modules to have completed (all y_i present).
NOTE: generates old-syntax input (context-entities, initial-contexts,
rsctl-property) which is not compatible with the current parser.
"""
import argparse
def generate(n, variant):
out = "reactions {\n"
out += "\t{ {x},{s} -> {a1} };\n"
for i in range(1, n + 1):
out += "\t{{ {{a{i}}},{{s}} -> {{y{i}}} }};\n".format(i=i)
out += "\t{{ {{a{i}}},{{s}} -> {{b{i}}} }};\n".format(i=i)
out += "\t{{ {{b{i}}},{{s}} -> {{c{i}}} }};\n".format(i=i)
out += "\t{{ {{c{i}}},{{s}} -> {{d{i}}} }};\n".format(i=i)
out += "\t{{ {{d{i},y{i}}},{{s}} -> {{a{j}}} }};\n".format(i=i, j=i + 1)
out += "\t{{ {{y{i}}},{{s}} -> {{y{i}}} }};\n".format(i=i)
final_reactants = "a" + str(n + 1)
for i in range(1, n + 1):
final_reactants += ",y" + str(i)
out += "\t{{ {{{r}}},{{s}} -> {{r}} }};\n".format(r=final_reactants)
out += "}\n"
if variant == 1:
out += "context-entities { s }\n"
elif variant == 2:
ctx = "s"
for i in range(1, n + 1):
if i % 2 == 0:
ctx += ",a" + str(i)
out += "context-entities {{ {} }}\n".format(ctx)
out += "initial-contexts { {x} }\n"
out += "rsctl-property { E[{}]F(r) }\n"
return out
def main():
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("n", type=int, help="number of pipeline modules")
parser.add_argument("variant", type=int, choices=[1, 2],
help="context variant (1: minimal, 2: extended)")
args = parser.parse_args()
print(generate(args.n, args.variant))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,88 @@
#!/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()

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env python3
"""
Generator for the Mutual Exclusion (Mutex) benchmark.
Produces a reaction system modelling N processes competing for
exclusive access to a critical section, using activation signals,
request tokens, and a lock. Generates one of three RSCTL properties.
NOTE: generates old-syntax input (context-entities, initial-contexts,
rsctl-property) which is not compatible with the current parser.
"""
import argparse
def generate(n, formula):
out = "reactions {\n"
for i in range(n):
out += "\t{{{{out{i},act{i}}},{{}} -> {{request{i}}}}};\n".format(i=i)
out += "\t{{{{out{i}}},{{act{i}}} -> {{out{i}}}}};\n".format(i=i)
for j in range(n):
if i != j:
out += "\t{{{{request{i},act{i},act{j}}},{{}} -> {{request{i}}}}};\n".format(
i=i, j=j)
out += "\t{{{{request{i}}},{{act{i}}} -> {{request{i}}}}};\n".format(i=i)
other_acts = ",".join("act" + str(j) for j in range(n) if i != j)
out += "\t{{{{request{i},act{i}}},{{{others},lock}} -> {{in{i},lock}}}};\n".format(
i=i, others=other_acts)
out += "\t{{{{in{i},act{i}}},{{}} -> {{out{i},done}}}};\n".format(i=i)
out += "\t{{{{in{i}}},{{act{i}}} -> {{in{i}}}}};\n".format(i=i)
out += "\t{{lock},{done} -> {lock}};\n"
out += "}\n"
ctx_ents = ",".join("act" + str(i) for i in range(n))
out += "context-entities {{ {} }}\n".format(ctx_ents)
init_ents = ",".join("out" + str(i) for i in range(n))
out += "initial-contexts {{ {{{}}} }}\n".format(init_ents)
if formula == 1:
out += "rsctl-property { A[{act1}]F(in1) }\n"
elif formula == 2:
out += "rsctl-property { E[{act1}]F(in1) }\n"
elif formula == 3:
pairs = []
for i in range(n):
for j in range(i + 1, n):
pairs.append("~(in{} AND in{})".format(i, j))
out += "rsctl-property {{ AG({}) }}\n".format(" AND ".join(pairs))
return out
def main():
parser = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument("n", type=int, help="number of processes")
parser.add_argument("formula", type=int, choices=[1, 2, 3],
help="formula to generate (1: A[]F, 2: E[]F, 3: AG mutex)")
args = parser.parse_args()
print(generate(args.n, args.formula))
if __name__ == "__main__":
main()

70
examples/bdd/tgc4.drs Normal file
View File

@@ -0,0 +1,70 @@
options { use-context-automaton; make-progressive; };
reactions {
proc0 {
{{out}, {} -> {approach}};
{{approach}, {req} -> {req}};
{{allowed}, {} -> {in}};
{{in}, {} -> {out,leave}};
{{req}, {in} -> {req}};
};
proc1 {
{{out}, {} -> {approach}};
{{approach}, {req} -> {req}};
{{allowed}, {} -> {in}};
{{in}, {} -> {out,leave}};
{{req}, {in} -> {req}};
};
proc2 {
{{out}, {} -> {approach}};
{{approach}, {req} -> {req}};
{{allowed}, {} -> {in}};
{{in}, {} -> {out,leave}};
{{req}, {in} -> {req}};
};
proc3 {
{{out}, {} -> {approach}};
{{approach}, {req} -> {req}};
{{allowed}, {} -> {in}};
{{in}, {} -> {out,leave}};
{{req}, {in} -> {req}};
};
};
context-automaton {
states { init, green, red };
init-state { init };
transitions {
{ proc0={out} proc1={out} proc2={out} proc3={out} }: init -> green;
{ proc0={allowed} }: green -> red : proc0.req;
{ proc1={allowed} }: green -> red : proc1.req;
{ proc2={allowed} }: green -> red : proc2.req;
{ proc3={allowed} }: green -> red : proc3.req;
{ proc0={} }: green -> green : ~proc0.req AND ~proc1.req AND ~proc2.req AND ~proc3.req;
{ proc1={} }: green -> green : ~proc0.req AND ~proc1.req AND ~proc2.req AND ~proc3.req;
{ proc2={} }: green -> green : ~proc0.req AND ~proc1.req AND ~proc2.req AND ~proc3.req;
{ proc3={} }: green -> green : ~proc0.req AND ~proc1.req AND ~proc2.req AND ~proc3.req;
{ proc0={} }: red -> green : proc0.leave;
{ proc1={} }: red -> green : proc1.leave;
{ proc2={} }: red -> green : proc2.leave;
{ proc3={} }: red -> green : proc3.leave;
{ proc0={} }: red -> red : ~proc0.leave AND ~proc1.leave AND ~proc2.leave AND ~proc3.leave;
{ proc1={} }: red -> red : ~proc0.leave AND ~proc1.leave AND ~proc2.leave AND ~proc3.leave;
{ proc2={} }: red -> red : ~proc0.leave AND ~proc1.leave AND ~proc2.leave AND ~proc3.leave;
{ proc3={} }: red -> red : ~proc0.leave AND ~proc1.leave AND ~proc2.leave AND ~proc3.leave;
};
};
rsctlk-property { f1 : EF( E<proc0.allowed>X( proc0.in ) ) AND EF( E<proc1.allowed>X( proc1.in ) ) AND EF( E<proc2.allowed>X( proc2.in ) ) AND EF( E<proc3.allowed>X( proc3.in ) ) };
rsctlk-property { f2 : EF( proc0.approach AND proc1.approach AND proc2.approach AND proc3.approach ) };
rsctlk-property { f3 : AG( proc0.in IMPLIES K[proc0](~proc1.in AND ~proc2.in AND ~proc3.in) ) };
rsctlk-property { f4 : AG( proc0.in IMPLIES C[proc0,proc1,proc2,proc3](~proc1.in AND ~proc2.in AND ~proc3.in) ) };

2
examples/smt/chain_reaction.py Normal file → Executable file
View File

@@ -28,7 +28,6 @@ import resource
def chain_reaction(print_system=False):
if len(sys.argv) < 1 + 3:
print("{source} <N> <M> <type>".format(source=sys.argv[0]))
print()
@@ -115,7 +114,6 @@ def chain_reaction(print_system=False):
def main():
chain_reaction()

103
examples/smt/heat_shock_response.py Normal file → Executable file
View File

@@ -28,8 +28,7 @@ import resource
def heat_shock_response(print_system=True, verify_rsc=True):
if len(sys.argv) < 1+1:
if len(sys.argv) < 1 + 1:
print("{source} <type>".format(source=sys.argv[0]))
print("type:")
print(" - 1 -- RSC")
@@ -37,72 +36,80 @@ def heat_shock_response(print_system=True, verify_rsc=True):
print()
exit(1)
verify_rsc=bool(int(sys.argv[1]))
verify_rsc = bool(int(sys.argv[1]))
stress_temp = 42
max_temp = 50
r = ReactionSystemWithConcentrations()
r.add_bg_set_entity(("hsp",1))
r.add_bg_set_entity(("hsf",1))
r.add_bg_set_entity(("hsf2",1))
r.add_bg_set_entity(("hsf3",1))
r.add_bg_set_entity(("hse",1))
r.add_bg_set_entity(("mfp",1))
r.add_bg_set_entity(("prot",1))
r.add_bg_set_entity(("hsf3:hse",1))
r.add_bg_set_entity(("hsp:mfp",1))
r.add_bg_set_entity(("hsp:hsf",1))
r.add_bg_set_entity(("temp",max_temp))
r.add_bg_set_entity(("heat",1))
r.add_bg_set_entity(("cool",1))
r.add_bg_set_entity(("hsp", 1))
r.add_bg_set_entity(("hsf", 1))
r.add_bg_set_entity(("hsf2", 1))
r.add_bg_set_entity(("hsf3", 1))
r.add_bg_set_entity(("hse", 1))
r.add_bg_set_entity(("mfp", 1))
r.add_bg_set_entity(("prot", 1))
r.add_bg_set_entity(("hsf3:hse", 1))
r.add_bg_set_entity(("hsp:mfp", 1))
r.add_bg_set_entity(("hsp:hsf", 1))
r.add_bg_set_entity(("temp", max_temp))
r.add_bg_set_entity(("heat", 1))
r.add_bg_set_entity(("cool", 1))
r.add_reaction([("hsf",1)], [("hsp",1)], [("hsf3",1)])
r.add_reaction([("hsf",1),("hsp",1),("mfp",1)], [], [("hsf3",1)])
r.add_reaction([("hsf3",1)], [("hse",1),("hsp",1)],[("hsf",1)])
r.add_reaction([("hsf3",1),("hsp",1),("mfp",1)], [("hse",1)], [("hsf",1)])
r.add_reaction([("hsf3",1),("hse",1)], [("hsp",1)], [("hsf3:hse",1)])
r.add_reaction([("hsp",1),("hsf3",1),("mfp",1),("hse",1)],[], [("hsf3:hse",1)])
r.add_reaction([("hse",1)], [("hsf3",1)], [("hse",1)])
r.add_reaction([("hsp",1),("hsf3",1),("hse",1)], [("mfp",1)], [("hse",1)])
r.add_reaction([("hsf3:hse",1)], [("hsp",1)], [("hsp",1),("hsf3:hse",1)])
r.add_reaction([("hsp",1),("mfp",1),("hsf3:hse",1)],[], [("hsp",1),("hsf3:hse",1)])
r.add_reaction([("hsf",1),("hsp",1)], [("mfp",1)], [("hsp:hsf",1)])
r.add_reaction([("hsp:hsf",1),("temp",stress_temp)],[], [("hsf",1),("hsp",1)])
r.add_reaction([("hsp:hsf",1)], [("temp",stress_temp)],[("hsp:hsf",1)])
r.add_reaction([("hsp",1),("hsf3:hse",1)], [("mfp",1)], [("hse",1),("hsp:hsf",1)])
r.add_reaction([("temp",stress_temp),("prot",1)], [], [("mfp",1),("prot",1)])
r.add_reaction([("prot",1)], [("temp",stress_temp)], [("prot",1)])
r.add_reaction([("hsp",1),("mfp",1)], [], [("hsp:mfp",1)])
r.add_reaction([("mfp",1)], [("hsp",1)], [("mfp",1)])
r.add_reaction([("hsp:mfp",1)], [], [("hsp",1),("prot",1)])
r.add_reaction([("hsf", 1)], [("hsp", 1)], [("hsf3", 1)])
r.add_reaction([("hsf", 1), ("hsp", 1), ("mfp", 1)], [], [("hsf3", 1)])
r.add_reaction([("hsf3", 1)], [("hse", 1), ("hsp", 1)], [("hsf", 1)])
r.add_reaction([("hsf3", 1), ("hsp", 1), ("mfp", 1)], [("hse", 1)], [("hsf", 1)])
r.add_reaction([("hsf3", 1), ("hse", 1)], [("hsp", 1)], [("hsf3:hse", 1)])
r.add_reaction(
[("hsp", 1), ("hsf3", 1), ("mfp", 1), ("hse", 1)], [], [("hsf3:hse", 1)]
)
r.add_reaction([("hse", 1)], [("hsf3", 1)], [("hse", 1)])
r.add_reaction([("hsp", 1), ("hsf3", 1), ("hse", 1)], [("mfp", 1)], [("hse", 1)])
r.add_reaction([("hsf3:hse", 1)], [("hsp", 1)], [("hsp", 1), ("hsf3:hse", 1)])
r.add_reaction(
[("hsp", 1), ("mfp", 1), ("hsf3:hse", 1)], [], [("hsp", 1), ("hsf3:hse", 1)]
)
r.add_reaction([("hsf", 1), ("hsp", 1)], [("mfp", 1)], [("hsp:hsf", 1)])
r.add_reaction(
[("hsp:hsf", 1), ("temp", stress_temp)], [], [("hsf", 1), ("hsp", 1)]
)
r.add_reaction([("hsp:hsf", 1)], [("temp", stress_temp)], [("hsp:hsf", 1)])
r.add_reaction(
[("hsp", 1), ("hsf3:hse", 1)], [("mfp", 1)], [("hse", 1), ("hsp:hsf", 1)]
)
r.add_reaction([("temp", stress_temp), ("prot", 1)], [], [("mfp", 1), ("prot", 1)])
r.add_reaction([("prot", 1)], [("temp", stress_temp)], [("prot", 1)])
r.add_reaction([("hsp", 1), ("mfp", 1)], [], [("hsp:mfp", 1)])
r.add_reaction([("mfp", 1)], [("hsp", 1)], [("mfp", 1)])
r.add_reaction([("hsp:mfp", 1)], [], [("hsp", 1), ("prot", 1)])
r.add_reaction_inc("temp", "heat", [("temp",1)],[("temp",max_temp)])
r.add_reaction_dec("temp", "cool", [("temp",1)],[])
r.add_reaction_inc("temp", "heat", [("temp", 1)], [("temp", max_temp)])
r.add_reaction_dec("temp", "cool", [("temp", 1)], [])
r.add_permanency("temp",[("heat",1),("cool",1)])
r.add_permanency("temp", [("heat", 1), ("cool", 1)])
c = ContextAutomatonWithConcentrations(r)
c.add_init_state("0")
c.add_state("1")
c.add_transition("0", [("hsf",1),("prot",1),("hse",1),("temp",35)], "1")
c.add_transition("1", [("cool",1)], "1")
c.add_transition("1", [("heat",1)], "1")
c.add_transition("0", [("hsf", 1), ("prot", 1), ("hse", 1), ("temp", 35)], "1")
c.add_transition("1", [("cool", 1)], "1")
c.add_transition("1", [("heat", 1)], "1")
c.add_transition("1", [], "1")
rc = ReactionSystemWithAutomaton(r,c)
rc = ReactionSystemWithAutomaton(r, c)
if print_system:
rc.show()
prop_req = [ ("mfp",1) ]
prop_block = [ ]
prop = (prop_req,prop_block)
rs_prop = (state_translate_rsc2rs(prop_req),state_translate_rsc2rs(prop_block))
prop_req = [("mfp", 1)]
prop_block = []
prop = (prop_req, prop_block)
rs_prop = (state_translate_rsc2rs(prop_req), state_translate_rsc2rs(prop_block))
if verify_rsc:
smt_rsc = SmtCheckerRSC(rc)
smt_rsc.check_reachability(prop,max_level=40)
smt_rsc.check_reachability(prop, max_level=40)
else:
orc = rc.get_ordinary_reaction_system_with_automaton()
if print_system:
@@ -117,9 +124,9 @@ def state_translate_rsc2rs(p):
def main():
heat_shock_response()
if __name__ == "__main__":
main()

7
examples/smt/mutex_param.py Normal file → Executable file
View File

@@ -77,7 +77,6 @@ def mutex_param_bench(cmd_args):
Inhib = [("s", 1)]
for i in range(n_proc):
r.add_reaction([E("out", i), E("act", i)], Inhib, [E("req", i)])
r.add_reaction([E("out", i)], [E("act", i)], [E("out", i)])
@@ -217,7 +216,6 @@ def mutex_nonparam_bench(cmd_args):
Inhib = [("s", 1)]
for i in range(n_proc):
r.add_reaction([E("out", i), E("act", i)], Inhib, [E("req", i)])
r.add_reaction([E("out", i)], [E("act", i)], [E("out", i)])
@@ -325,7 +323,6 @@ def mutex_nonparam_bench_oldimpl(cmd_args):
Inhib = [("s", 1)]
for i in range(n_proc):
r.add_reaction([E("out", i), E("act", i)], Inhib, [E("req", i)])
r.add_reaction([E("out", i)], [E("act", i)], [E("out", i)])
@@ -407,7 +404,6 @@ def state_translate_rsc2rs(p):
def mutex_bench_main(cmd_args):
mode = cmd_args.mode
if mode == "p":
@@ -422,7 +418,6 @@ def mutex_bench_main(cmd_args):
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
@@ -432,7 +427,7 @@ def main():
parser.add_argument(
"mode",
choices=['p', 'np-p', 'np-np'],
choices=["p", "np-p", "np-np"],
help="Selects the mode: p - parameter synthesis (parametric implementation), np-p - non-parametric with parametric implementation (with the parameters substituted), np-np - non-parametric with non-parametric implementation (parameters substituted)",
)

102
examples/smt/scalable_chain.py Normal file → Executable file
View File

@@ -31,6 +31,7 @@ from itertools import chain, combinations
import sys
import resource
def generate_system(chainLen, maxConc):
"""
This function generates the reaction system with concentrations
@@ -41,31 +42,36 @@ def generate_system(chainLen, maxConc):
"""
r = ReactionSystemWithConcentrations()
r.add_bg_set_entity(("inc",1))
r.add_bg_set_entity(("dec",1))
r.add_bg_set_entity(("inc", 1))
r.add_bg_set_entity(("dec", 1))
for i in range(1,chainLen+1):
r.add_bg_set_entity(("e_" + str(i),maxConc))
for i in range(1, chainLen + 1):
r.add_bg_set_entity(("e_" + str(i), maxConc))
for i in range(1,chainLen+1):
for i in range(1, chainLen + 1):
ent = "e_" + str(i)
r.add_reaction_inc(ent, "inc", [(ent, 1)],[(ent,maxConc)])
r.add_reaction_dec(ent, "dec", [(ent, 1)],[])
r.add_reaction_inc(ent, "inc", [(ent, 1)], [(ent, maxConc)])
r.add_reaction_dec(ent, "dec", [(ent, 1)], [])
if i < chainLen:
r.add_reaction([(ent,maxConc)],[],[("e_"+str(i+1),1)])
r.add_reaction([(ent, maxConc)], [], [("e_" + str(i + 1), 1)])
r.add_reaction([("e_" + str(chainLen),maxConc)],[("dec",1)],[("e_" + str(chainLen),maxConc)])
r.add_reaction(
[("e_" + str(chainLen), maxConc)],
[("dec", 1)],
[("e_" + str(chainLen), maxConc)],
)
c = ContextAutomatonWithConcentrations(r)
c.add_init_state("init")
c.add_state("working")
c.add_transition("init", [("e_1",1),("inc",1)], "working")
c.add_transition("working", [("inc",1)], "working")
c.add_transition("init", [("e_1", 1), ("inc", 1)], "working")
c.add_transition("working", [("inc", 1)], "working")
rc = ReactionSystemWithAutomaton(r,c)
rc = ReactionSystemWithAutomaton(r, c)
return rc
def generate_formula(formula_number, chainLen, maxConc):
"""
This function generates the rsLTL formula
@@ -73,30 +79,50 @@ def generate_formula(formula_number, chainLen, maxConc):
"""
if formula_number == 1:
ret = Formula_rsLTL.f_F( BagDescription.f_entity("inc") > 0, (BagDescription.f_entity('e_'+str(chainLen)) >= maxConc) )
ret = Formula_rsLTL.f_F(
BagDescription.f_entity("inc") > 0,
(BagDescription.f_entity("e_" + str(chainLen)) >= maxConc),
)
elif formula_number == 2:
f_tmp = Formula_rsLTL.f_F( BagDescription.f_entity("inc") > 0, (BagDescription.f_entity('e_'+str(chainLen)) == maxConc) )
for i in range(chainLen-1,0,-1):
f_tmp = Formula_rsLTL.f_F( BagDescription.f_entity("inc") > 0, f_tmp & (BagDescription.f_entity('e_'+str(i)) == maxConc) )
f_tmp = Formula_rsLTL.f_F(
BagDescription.f_entity("inc") > 0,
(BagDescription.f_entity("e_" + str(chainLen)) == maxConc),
)
for i in range(chainLen - 1, 0, -1):
f_tmp = Formula_rsLTL.f_F(
BagDescription.f_entity("inc") > 0,
f_tmp & (BagDescription.f_entity("e_" + str(i)) == maxConc),
)
ret = f_tmp
elif formula_number == 3:
ret = Formula_rsLTL.f_G( BagDescription.f_TRUE(),
ret = Formula_rsLTL.f_G(
BagDescription.f_TRUE(),
Formula_rsLTL.f_Implies(
(BagDescription.f_entity('e_1') == 1),
(BagDescription.f_entity("e_1") == 1),
Formula_rsLTL.f_F(
BagDescription.f_entity("inc") > 0,
(BagDescription.f_entity('e_'+str(chainLen)) == maxConc)
)
)
(BagDescription.f_entity("e_" + str(chainLen)) == maxConc),
),
),
)
elif formula_number == 4:
ret = Formula_rsLTL.f_F( BagDescription.f_entity("inc") > 0 , BagDescription.f_entity('e_1') == maxConc )
ret = Formula_rsLTL.f_F(
BagDescription.f_entity("inc") > 0,
BagDescription.f_entity("e_1") == maxConc,
)
elif formula_number == 5:
ret = Formula_rsLTL.f_X(BagDescription.f_TRUE(), Formula_rsLTL.f_U( BagDescription.f_entity("inc") > 0 , BagDescription.f_entity('e_1') > 0, BagDescription.f_entity('e_2') > 0 ) )
ret = Formula_rsLTL.f_X(
BagDescription.f_TRUE(),
Formula_rsLTL.f_U(
BagDescription.f_entity("inc") > 0,
BagDescription.f_entity("e_1") > 0,
BagDescription.f_entity("e_2") > 0,
),
)
else:
ret = None
@@ -110,19 +136,19 @@ def save_statistics(smt_rsc, formula_number, chainLen, maxConc):
"""
Saves the statistics fetched from smt_rsc into files
"""
time=0
mem_usage=resource.getrusage(resource.RUSAGE_SELF).ru_maxrss/(1024*1024)
filename_t="bench_rsc_F" + str(formula_number) + "_time.log"
filename_m="bench_rsc_F" + str(formula_number) + "_mem.log"
time=smt_rsc.get_verification_time()
time = 0
mem_usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / (1024 * 1024)
filename_t = "bench_rsc_F" + str(formula_number) + "_time.log"
filename_m = "bench_rsc_F" + str(formula_number) + "_mem.log"
time = smt_rsc.get_verification_time()
f=open(filename_t, 'a')
log_str="(" + str(chainLen) + "," + str(maxConc) + "," + str(time) + ")\n"
f = open(filename_t, "a")
log_str = "(" + str(chainLen) + "," + str(maxConc) + "," + str(time) + ")\n"
f.write(log_str)
f.close()
f=open(filename_m, 'a')
log_str="(" + str(chainLen) + "," + str(maxConc) + "," + str(mem_usage) + ")\n"
f = open(filename_m, "a")
log_str = "(" + str(chainLen) + "," + str(maxConc) + "," + str(mem_usage) + ")\n"
f.write(log_str)
f.close()
@@ -131,18 +157,18 @@ def scalable_chain(print_system=False):
"""
This is the entry point for the benchmark
"""
if len(sys.argv) < 1+3:
if len(sys.argv) < 1 + 3:
print("arguments: <chainLen> <maxConc> <formulaNumber>")
exit(1)
chainLen=int(sys.argv[1]) # chain length
maxConc=int(sys.argv[2]) # depth (max concentration)
formula_number=int(sys.argv[3])
chainLen = int(sys.argv[1]) # chain length
maxConc = int(sys.argv[2]) # depth (max concentration)
formula_number = int(sys.argv[3])
if chainLen < 1 or maxConc < 1:
print("be reasonable")
exit(1)
if not formula_number in range(1,5+1):
if not formula_number in range(1, 5 + 1):
print("formulaNumber must be in 1..5")
exit(1)
@@ -168,6 +194,6 @@ def scalable_chain(print_system=False):
def main():
scalable_chain(print_system=True)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,97 @@
#!/usr/bin/env bash
x_values="2 3 4"
y_values="`seq 2 20`"
z_values="`seq 2 20`"
aut_values="a b"
reactics="$1"
reactics_opts="-z -x -vv -B -c"
input_generator="../../examples/bdd/generators/gen_drs.py"
benchname="sig"
formname="f0"
outdir="results_${benchname}"
if [[ -z "$1" ]]
then
echo "Usage: $0 <path to reactics>"
exit 1
fi
if [[ ! -x "$reactics" ]]
then
echo "Provided path to ReactICS not executable"
fi
if [[ ! -d "$outdir" ]]
then
echo "Creating output directory: $outdir"
mkdir -p $outdir
fi
#ulimit -t 3600
#ulimit -v 2097152
ulimit -t 3600
#ulimit -v 1000000
for a in $aut_values
do
for z in $z_values
do
for y in $y_values
do
for x in $x_values
do
if [[ $y -lt $z ]]
then
# Skip undesired values
continue
fi
if [[ $y -ne $z ]]
then
# More aggressive skipping
continue
fi
bench_identifier="${benchname}_F${formname}_A${a}"
filename_base="${outdir}/${benchname}_F${formname}__x${x}_y${y}_z${z}_A${a}"
outfile="${filename_base}.out"
infile="${filename_base}.drs"
stopfile="DONE_${bench_identifier}"
if [[ -e "$stopfile" ]]
then
echo "Time limit -- SKIPPING"
continue
fi
$input_generator $x $y $z $a > ${infile}
$reactics $reactics_opts $formname $infile |& tee ${outfile}
exitcode=$?
echo "ReactICS exit code: $exitcode"
result="$(tail -1 $outfile | grep -E '.*;.*;.*;.*'| sed "s/STAT/$n /")"
if [ "$result" = "" ]
then
echo "TIME LIMIT; marking as finished"
#touch $stopfile
else
echo "$x ; $y ; $z ; $a ; $exitcode $result" >> $outdir/summary_${bench_identifier}.txt
echo "$x $y $z $a $(echo $result | sed 's/;/ /g')" >> $outdir/${bench_identifier}.dat
echo $result
fi
done
done
done
done
# EOF

View File

@@ -0,0 +1,454 @@
#!/usr/bin/env python
#
# Copyright (c) 2015-2019 Artur Meski
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
from rs import *
from smt import *
from logics import *
from rsltl_shortcuts import *
from itertools import chain, combinations
import sys
import resource
import argparse
def powerset(iterable, N=None):
if N is None:
N = len(s)
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(N + 1))
def mutex_param_bench(cmd_args):
"""
Mutex Benchmark
Parametric
"""
base_entities = ["out", "req", "in", "act"]
shared_entities = ["lock", "done", "s"]
if not cmd_args.scaling:
print("Missing scaling parameter")
return
n_proc = int(cmd_args.scaling)
r = ReactionSystemWithConcentrationsParam()
def E(a, b, c=1):
return (a + "_" + str(b), c)
for i in range(n_proc):
for ent in base_entities:
max_conc = 1
if ent == "in":
max_conc = 3
elif ent == "req":
max_conc = 2
r.add_bg_set_entity(E(ent, i, max_conc))
for ent in shared_entities:
max_conc = 1
r.add_bg_set_entity((ent, max_conc))
###################################################
Inhib = [("s", 1)]
for i in range(n_proc):
r.add_reaction([E("out", i), E("act", i)], Inhib, [E("req", i)])
r.add_reaction([E("out", i)], [E("act", i)], [E("out", i)])
for j in range(n_proc):
if i != j:
r.add_reaction(
[E("req", i), E("act", i), E("act", j)], Inhib, [E("req", i)]
)
r.add_reaction([E("req", i)], [E("act", i)], [E("req", i, 2)])
enter_inhib = [E("act", j) for j in range(n_proc) if i != j] + [("lock", 1)]
r.add_reaction(
[E("req", i, 2), E("act", i)], enter_inhib, [E("in", i, 3), ("lock", 1)]
)
r.add_reaction([E("in", i, 3), E("act", i)], Inhib, [E("in", i, 2)])
r.add_reaction([E("in", i, 2), E("act", i)], Inhib, [E("in", i, 1)])
r.add_reaction([E("in", i), E("act", i)], Inhib, [E("out", i), ("done", 1)])
r.add_reaction([E("in", i)], [E("act", i)], [E("in", i)])
r.add_reaction([("lock", 1)], [("done", 1)], [("lock", 1)])
lda1 = r.get_param("lda1")
lda2 = r.get_param("lda2")
lda3 = r.get_param("lda3")
r.add_reaction(lda1, lda2, lda3)
###################################################
c = ContextAutomatonWithConcentrations(r)
c.add_init_state("0")
c.add_state("1")
init_ctx = []
for i in range(n_proc):
init_ctx.append(E("out", i))
# the experiments starts with adding x and y:
c.add_transition("0", init_ctx, "1")
all_act = powerset([E("act", i) for i in range(n_proc)], 2)
for actions in all_act:
actions = list(actions)
c.add_transition("1", actions, "1")
# for all the remaining steps we have empty context sequences
# c.add_transition("1", [], "1")
# c.add_transition("1", [("h", 1)], "1")
###################################################
rc = ReactionSystemWithAutomaton(r, c)
rc.show()
f_attack = ltl_F(
True, bag_And(bag_entity("in_0") == 1, bag_entity("in_" + str(n_proc - 1)) == 1)
)
ent_of_Nth_proc = [
ent + "_" + str(n_proc - 1) for ent in base_entities
] + shared_entities
disallow = ["in_" + str(n_proc - 1)]
for ent in r.background_set:
if ent not in ent_of_Nth_proc:
disallow.append(ent)
# disallow.append("act_" + str(n_proc-1))
# disallow = ["in_0", "in_" + str(n_proc)] #, "req_0", "req_1"]
lda1_disallow = [param_entity(lda1, ent) == 0 for ent in disallow]
lda2_disallow = [param_entity(lda2, ent) == 0 for ent in disallow]
lda3_disallow = [param_entity(lda3, ent) == 0 for ent in disallow]
lda_disallow = lda1_disallow + lda2_disallow + lda3_disallow
# for bent in base_entities:
# print(param_entity(lda3, bent + "_0"))
param_constr = param_And(*lda_disallow)
smt_rsc = SmtCheckerRSCParam(rc, optimise=cmd_args.optimise)
smt_rsc.check_rsltl(
formulae_list=[f_attack], param_constr=param_constr
) # , max_level=4, cont_if_sat=True)
log_suffix = ""
if cmd_args.optimise:
log_suffix = "_OPT"
time = 0
mem_usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / (1024 * 1024)
filename_t = "bench_mutex_param" + log_suffix + "_time.dat"
filename_m = "bench_mutex_param" + log_suffix + "_mem.dat"
time = smt_rsc.get_verification_time()
with open(filename_t, "a") as f:
log_str = "{:d} {:f}\n".format(n_proc, time)
f.write(log_str)
with open(filename_m, "a") as f:
log_str = "{:d} {:f}\n".format(n_proc, mem_usage)
f.write(log_str)
def mutex_nonparam_bench(cmd_args):
"""
Mutex Benchmark
Parametric
"""
base_entities = ["out", "req", "in", "act"]
shared_entities = ["lock", "done", "s"]
if not cmd_args.scaling:
raise RuntimeError("Missing scaling parameter")
n_proc = int(cmd_args.scaling)
r = ReactionSystemWithConcentrationsParam()
def E(a, b):
return (a + "_" + str(b), 1)
for i in range(n_proc):
for ent in base_entities:
r.add_bg_set_entity(E(ent, i))
for ent in shared_entities:
r.add_bg_set_entity((ent, 1))
###################################################
Inhib = [("s", 1)]
for i in range(n_proc):
r.add_reaction([E("out", i), E("act", i)], Inhib, [E("req", i)])
r.add_reaction([E("out", i)], [E("act", i)], [E("out", i)])
for j in range(n_proc):
if i != j:
r.add_reaction(
[E("req", i), E("act", i), E("act", j)], Inhib, [E("req", i)]
)
r.add_reaction([E("req", i)], [E("act", i)], [E("req", i)])
enter_inhib = [E("act", j) for j in range(n_proc) if i != j] + [("lock", 1)]
r.add_reaction(
[E("req", i), E("act", i)], enter_inhib, [E("in", i), ("lock", 1)]
)
r.add_reaction([E("in", i), E("act", i)], Inhib, [E("out", i), ("done", 1)])
r.add_reaction([E("in", i)], [E("act", i)], [E("in", i)])
r.add_reaction([("lock", 1)], [("done", 1)], [("lock", 1)])
r.add_reaction(
[E("out", n_proc - 1)], [("s", 1)], [("done", 1), E("req", n_proc - 1)]
)
###################################################
c = ContextAutomatonWithConcentrations(r)
c.add_init_state("0")
c.add_state("1")
init_ctx = []
for i in range(n_proc):
init_ctx.append(E("out", i))
# the experiments starts with adding x and y:
c.add_transition("0", init_ctx, "1")
all_act = powerset([E("act", i) for i in range(n_proc)], 2)
for actions in all_act:
actions = list(actions)
c.add_transition("1", actions, "1")
# for all the remaining steps we have empty context sequences
# c.add_transition("1", [], "1")
# c.add_transition("1", [("h", 1)], "1")
###################################################
rc = ReactionSystemWithAutomaton(r, c)
rc.show()
f_attack = ltl_F(
True, bag_And(bag_entity("in_0") == 1, bag_entity("in_" + str(n_proc - 1)) == 1)
)
smt_rsc = SmtCheckerRSCParam(rc, optimise=cmd_args.optimise)
smt_rsc.check_rsltl(formulae_list=[f_attack])
time = 0
mem_usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / (1024 * 1024)
filename_t = "bench_mutex_nonparam_time.dat"
filename_m = "bench_mutex_nonparam_mem.dat"
time = smt_rsc.get_verification_time()
with open(filename_t, "a") as f:
log_str = "{:d} {:f}\n".format(n_proc, time)
f.write(log_str)
with open(filename_m, "a") as f:
log_str = "{:d} {:f}\n".format(n_proc, mem_usage)
f.write(log_str)
def mutex_nonparam_bench_oldimpl(cmd_args):
"""
Mutex Benchmark
Parametric
"""
base_entities = ["out", "req", "in", "act"]
shared_entities = ["lock", "done", "s"]
if not cmd_args.scaling:
raise RuntimeError("Missing scaling parameter")
n_proc = int(cmd_args.scaling)
r = ReactionSystemWithConcentrations()
def E(a, b):
return (a + "_" + str(b), 1)
for i in range(n_proc):
for ent in base_entities:
r.add_bg_set_entity(E(ent, i))
for ent in shared_entities:
r.add_bg_set_entity((ent, 1))
###################################################
Inhib = [("s", 1)]
for i in range(n_proc):
r.add_reaction([E("out", i), E("act", i)], Inhib, [E("req", i)])
r.add_reaction([E("out", i)], [E("act", i)], [E("out", i)])
for j in range(n_proc):
if i != j:
r.add_reaction(
[E("req", i), E("act", i), E("act", j)], Inhib, [E("req", i)]
)
r.add_reaction([E("req", i)], [E("act", i)], [E("req", i)])
enter_inhib = [E("act", j) for j in range(n_proc) if i != j] + [("lock", 1)]
r.add_reaction(
[E("req", i), E("act", i)], enter_inhib, [E("in", i), ("lock", 1)]
)
r.add_reaction([E("in", i), E("act", i)], Inhib, [E("out", i), ("done", 1)])
r.add_reaction([E("in", i)], [E("act", i)], [E("in", i)])
r.add_reaction([("lock", 1)], [("done", 1)], [("lock", 1)])
r.add_reaction(
[E("out", n_proc - 1)], [("s", 1)], [("done", 1), E("req", n_proc - 1)]
)
###################################################
c = ContextAutomatonWithConcentrations(r)
c.add_init_state("0")
c.add_state("1")
init_ctx = []
for i in range(n_proc):
init_ctx.append(E("out", i))
# the experiments starts with adding x and y:
c.add_transition("0", init_ctx, "1")
all_act = powerset([E("act", i) for i in range(n_proc)], 2)
for actions in all_act:
actions = list(actions)
c.add_transition("1", actions, "1")
# for all the remaining steps we have empty context sequences
# c.add_transition("1", [], "1")
# c.add_transition("1", [("h", 1)], "1")
###################################################
rc = ReactionSystemWithAutomaton(r, c)
rc.show()
f_attack = ltl_F(
True, bag_And(bag_entity("in_0") == 1, bag_entity("in_" + str(n_proc - 1)) == 1)
)
smt_rsc = SmtCheckerRSC(rc)
smt_rsc.check_rsltl(formula=f_attack)
time = 0
mem_usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / (1024 * 1024)
filename_t = "bench_mutex_nonparam_oldimpl_time.dat"
filename_m = "bench_mutex_nonparam_oldimpl_mem.dat"
time = smt_rsc.get_verification_time()
with open(filename_t, "a") as f:
log_str = "{:d} {:f}\n".format(n_proc, time)
f.write(log_str)
with open(filename_m, "a") as f:
log_str = "{:d} {:f}\n".format(n_proc, mem_usage)
f.write(log_str)
def state_translate_rsc2rs(p):
return [e[0] + "#" + str(e[1]) for e in p]
def mutex_bench_main(cmd_args):
mode = cmd_args.mode
if mode == "p":
mutex_param_bench(cmd_args)
elif mode == "np-p":
mutex_nonparam_bench(cmd_args)
elif mode == "np-np":
mutex_nonparam_bench_oldimpl(cmd_args)
else:
print("Unrecognised mode")
return
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"scaling",
help="scaling parameter value",
)
parser.add_argument(
"mode",
choices=["p", "np-p", "np-np"],
help="Selects the mode: p - parameter synthesis (parametric implementation), np-p - non-parametric with parametric implementation (with the parameters substituted), np-np - non-parametric with non-parametric implementation (parameters substituted)",
)
parser.add_argument(
"-v", "--verbose", help="turn verbosity on", action="store_true"
)
parser.add_argument(
"-o",
"--optimise",
help="minimise the parametric computation result",
action="store_true",
)
args = parser.parse_args()
mutex_bench_main(args)
if __name__ == "__main__":
main()
# EOF

View File

@@ -0,0 +1,26 @@
#!/bin/sh
# sudo systemsetup -getcomputersleep
#sudo systemsetup -setcomputersleep Never
# sudo systemsetup -setcomputersleep 1
REACTICS_SMT="../../reactics-smt"
export PYTHONPATH="$PYTHONPATH:$REACTICS_SMT"
REACTICS_SCRIPT="./pmutex.py"
for i in `seq 2 50`
do
for special_mode in "p" "np-p" "np-np"
do
echo "$i (sm=${special_mode})"
if [[ $special_mode -eq 1 ]]
then
$REACTICS_SCRIPT $i $special_mode
$REACTICS_SCRIPT -o $i $special_mode
else
$REACTICS_SCRIPT $i $special_mode
fi
done
done

View File

@@ -1,4 +1,4 @@
#!/bin/bash
#!/usr/bin/env bash
#
# Copyright (c) 2019 Artur Meski
@@ -52,16 +52,24 @@ then
then
python3 $*
else
echo "Nothing to do"
echo "Provide path to an example script (typically from ./examples/smt)"
fi
elif [[ "$mode" == "setup" ]]
then
which -s gmake
if [[ $? -eq 0 ]]
then
MAKE="gmake"
else
MAKE="make"
fi
git pull
cd $REACTICS_BDD
./build_cudd.sh
make
$MAKE
else

View File

@@ -11,7 +11,7 @@ CXXFLAGS = -std=c++14 -O3 -DPUBLIC_RELEASE -DNDEBUG #-g
CXXFLAGS = -std=c++14 -O3 -DPUBLIC_RELEASE #-g
LDLIBS = $(CUDD_INCLUDE)
OBJ = rs.o ctx_aut.o symrs.o mc.o rsin_driver.o rsin_parser.o rsin_parser.lex.o formrsctlk.o stateconstr.o
OBJ = rs.o ctx_aut.o symrs.o mc.o rsin_driver.o rsin_parser.o rsin_parser.lex.o formrsctlk.o stateconstr.o export.o
all: reactics

View File

@@ -1,7 +1,7 @@
#include "ctx_aut.hh"
#include "rs.hh"
#include "macro.hh"
#include "rs.hh"
#include "stateconstr.hh"
CtxAut::CtxAut(Options *opts, RctSys *parent_rctsys)
@@ -13,12 +13,7 @@ CtxAut::CtxAut(Options *opts, RctSys *parent_rctsys)
bool CtxAut::hasState(std::string name)
{
if (states_names.find(name) == states_names.end()) {
return false;
}
else {
return true;
}
return states_names.find(name) != states_names.end();
}
State CtxAut::getStateID(std::string name)
@@ -75,12 +70,14 @@ void CtxAut::printAutomaton(void)
void CtxAut::showStates(void)
{
if (states_ids.size() > 0) {
cout << "# Context Automaton States:" << endl;
cout << " = Init state: " << getStateName(init_state_id) << endl;
for (const auto &s : states_ids) {
cout << " * " << s << endl;
}
}
}
void CtxAut::pushContextEntity(Entity entity_id)
@@ -98,7 +95,8 @@ void CtxAut::saveCurrentContextSet(Process proc_id)
tmpEntities.clear();
}
void CtxAut::addTransition(std::string srcStateName, std::string dstStateName, StateConstr *stateConstr)
void CtxAut::addTransition(std::string srcStateName, std::string dstStateName,
StateConstr *stateConstr)
{
VERB_L3("Saving transition");
@@ -115,12 +113,17 @@ void CtxAut::addTransition(std::string srcStateName, std::string dstStateName, S
void CtxAut::showTransitions(void)
{
if (transitions.size() == 0) {
cout << "Empty context automaton" << endl;
return;
}
cout << "# Context Automaton Transitions:" << endl;
for (const auto &t : transitions) {
cout << " * [" << getStateName(t.src_state) << " -> " << getStateName(
t.dst_state)
<< "]: { " << parent_rctsys->procEntitiesToStr(t.ctx) << "}";
cout << " * [" << getStateName(t.src_state) << " -> "
<< getStateName(t.dst_state) << "]: { "
<< parent_rctsys->procEntitiesToStr(t.ctx) << "}";
if (t.state_constr != nullptr) {
cout << " " << t.state_constr->toStr();
@@ -162,8 +165,8 @@ void CtxAut::makeProgressive(void)
State curr_st = t.src_state;
if (t.state_constr != nullptr) {
constrs[curr_st] = new StateConstr(
STC_OR, constrs[curr_st], t.state_constr);
constrs[curr_st] =
new StateConstr(STC_OR, constrs[curr_st], t.state_constr);
}
}
@@ -174,13 +177,11 @@ void CtxAut::makeProgressive(void)
state_constr = new StateConstr(STC_NOT, constrs[getStateID(s)]);
addTransition(s, special_loc, state_constr);
}
}
addTransition(special_loc, special_loc, nullptr);
made_progressive = true;
}
/** EOF **/

View File

@@ -12,10 +12,7 @@
#include <vector>
#include <string>
#include <cstdlib>
// #include "rs.hh"
#include "types.hh"
// #include "options.hh"
// #include "stateconstr.hh"
using std::cout;
using std::endl;
@@ -27,6 +24,7 @@ class StateConstr;
class CtxAut
{
friend class SymRS;
friend class RSExporter;
public:
CtxAut(Options *opts, RctSys *parent_rctsys);

View File

@@ -1,6 +1,6 @@
#!/bin/sh
TMPINPUT="tmp_$RANDOM$RANDOM.rs"
TMPINPUT="tmp_$RANDOM$RANDOM.drs"
CMD="./reactics -B"

913
reactics-bdd/export.cc Normal file
View File

@@ -0,0 +1,913 @@
#include "export.hh"
RSExporter::RSExporter(RctSys *rs, rsin_driver *drv, std::ostream & outStream):
rs(rs), drv(drv), output(outStream) {
// Store all possible inputs (reactants and inhibitors) and outputs (products) for each process
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc) {
for (const auto & rr : rs->proc_reactions[proc]) {
for (const auto & e : rr.rctt)
procInputs[proc].insert(e);
for (const auto & e : rr.inhib)
procInputs[proc].insert(e);
for (const auto & e : rr.prod)
procOutputs[proc].insert(e);
}
}
// Add possible inputs from context automaton
for (const auto & trans : rs->ctx_aut->transitions) {
for (const auto & procCtx : trans.ctx) {
for (const auto & e : procCtx.second) {
procInputs[procCtx.first].insert(e);
}
}
}
}
void RSExporter::exportToISPL() {
exportEnvironment();
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc)
exportAgent(proc);
parseFormulas();
exportEvaluation();
exportInitStates();
exportFormulae();
}
void RSExporter::exportEnvironment() {
output << "Agent Environment\n\n";
exportEnvironmentVars();
exportEnvironmentActions();
exportEnvironmentProtocol();
exportEnvironmentEvolution();
output << "\nend Agent\n" << endl;
}
void RSExporter::exportEnvironmentVars() {
output << "Obsvars:\n"
<< indent << "mode: {init, clear, select_active_agents, activate_agents,\n"
<< indent << indent << "distribute_local, add_context, distribute_global, produce,\n";
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc) {
for (const Entity & e : procOutputs[proc]) {
output << indent << indent << "collect_" << rs->processes_ids[proc]
<< "_" << rs->entities_ids[e] << ",\n";
}
}
output << indent << indent << "finalize\n" << indent << "};\n\n";
output << indent << "-- Boolean variables denoting entities available for each agent --\n\n";
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc) {
for (const Entity & e : procInputs[proc]) {
output << indent << rs->processes_ids[proc]
<< "_" << rs->entities_ids[e] << ": 0..1;\n";
}
output << "\n";
}
output << indent << "-- Boolean variables denoting which agents are active --\n\n";
for (const string & procName : rs->processes_ids)
output << indent << "Active_" << procName << ": 0..1;\n";
output << "end Obsvars\n\n"
<< "Vars:\n\n";
output << indent << "-- Context automaton details --\n\n";
output << indent << "state: {";
for (size_t i=0; i<rs->ctx_aut->statesCount(); ++i) {
string stName = rs->ctx_aut->getStateName(i);
// Skip the dummy state used for closure
if (stName == "T")
continue;
if (i) output << ", ";
output << stName;
}
output << "};\n";
// Add dummy transition leading to the initial state (no agent is active)
output << indent << "transition: {"
<< "\n" << indent << indent << "init_0";
int trId {1};
for (const CtxAutTransition & trans : rs->ctx_aut->transitions) {
string dstName = rs->ctx_aut->getStateName(trans.dst_state);
if (dstName == "T")
continue;
output << ",";
output << "\n" << indent << indent << rs->ctx_aut->getStateName(trans.src_state)
<< "_" << dstName << "_" << trId;
++trId;
}
output << indent << "\n};\n\n";
output << indent << "-- Boolean variables denoting existence of entities in the environment.\n\n";
for (const string & entityName : rs->entities_ids)
output << indent << entityName << " : 0..1;\n";
output << "end Vars" << endl;
}
void RSExporter::exportEnvironmentActions() {
output << "\nActions = {\n"
<< indent << "init, clear, select_active_agents, activate_agents,\n"
<< indent << "distribute_local, add_context, distribute_global, produce,\n";
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc) {
for (const Entity & e : procOutputs[proc]) {
output << indent << "collect_" << rs->processes_ids[proc]
<< "_" << rs->entities_ids[e] << ",\n";
}
}
output << indent << "finalize, sleep\n};\n";
}
void RSExporter::exportEnvironmentProtocol() {
output << "\nProtocol:\n"
<< indent << "mode=clear : {clear};\n"
<< indent << "mode=select_active_agents : {select_active_agents};\n"
<< indent << "mode=activate_agents : {activate_agents};\n\n";
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc) {
for (const Entity & e : procOutputs[proc]) {
output << indent << "mode=collect_" << rs->processes_ids[proc]
<< "_" << rs->entities_ids[e]
<< ": {collect_" << rs->processes_ids[proc]
<< "_" << rs->entities_ids[e] << "};\n";
}
output << "\n";
}
output << indent << "mode=distribute_local : {distribute_local};\n"
<< indent << "mode=add_context : {add_context};\n"
<< indent << "mode=distribute_global : {distribute_global};\n"
<< indent << "mode=produce : {produce};\n"
<< indent << "mode=finalize : {finalize};\n\n"
<< indent << "Other : {sleep};\n"
<< "end Protocol\n";
}
void RSExporter::exportEnvironmentEvolution() {
output << "\nEvolution:\n\n";
//--------------------------------------------------------------------------------
// Reset the environment state after the previous computation step.
// (reset agent activity status, availability of entities, etc.)
//--------------------------------------------------------------------------------
output << indent <<"--------------------------------------------------------------------------------\n"
<< indent <<"-- Reset the environment state after the previous computation step.\n"
<< indent <<"-- (reset agent activity status, availability of entities, etc.)\n"
<< indent <<"--------------------------------------------------------------------------------\n\n"
<< indent;
for (const string & procName : rs->processes_ids)
output << "Active_" << procName << "=0 and ";
output << "\n" << indent << indent;
for (const string & entityName : rs->entities_ids)
output << entityName << "=0 and ";
output << "\n" << indent << indent << "mode=select_active_agents\n"
<< indent << indent << indent << "if mode=clear;\n\n";
//--------------------------------------------------------------------------------
// Active agents are selected based on the current context automaton transition.
//--------------------------------------------------------------------------------
output << indent <<"--------------------------------------------------------------------------------\n"
<< indent <<"-- Active agents are selected based on the current context automaton transition.\n"
<< indent <<"--------------------------------------------------------------------------------\n\n"
<< indent;
// For the dummy initial transition leading to the initial state no agent is active
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc)
output << "Active_" << rs->getProcessName(proc) << "=0 and ";
output << "mode=activate_agents\n"
<< indent << indent << "if mode=select_active_agents and transition=init_0;\n\n" << indent;
unsigned transNo = 1;
for (const CtxAutTransition & trans : rs->ctx_aut->transitions) {
vector<bool> isActive(rs->getNumberOfProcesses(), false);
string dstName = rs->ctx_aut->getStateName(trans.dst_state);
if (dstName == "T")
continue;
for (const auto & entry : trans.ctx)
isActive[entry.first] = true;
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc)
output << "Active_" << rs->getProcessName(proc) << "="
<< (isActive[proc] ? "1" : "0")
<< " and ";
output << "mode=activate_agents\n"
<< indent << indent << "if mode=select_active_agents and transition="
<< rs->ctx_aut->getStateName(trans.src_state) << "_"
<< rs->ctx_aut->getStateName(trans.dst_state) << "_"
<< to_string(transNo) << ";\n\n" << indent;
++transNo;
}
//--------------------------------------------------------------------------------
// Conduct a series of queries to active agents regarding products
// that may have been produced in the last step when they were active.
//--------------------------------------------------------------------------------
output << "--------------------------------------------------------------------------------\n"
<< indent << "-- Conduct a series of queries to active agents regarding products\n"
<< indent << "-- that may have been produced in the last step when they were active.\n"
<< indent << "--------------------------------------------------------------------------------\n\n";
vector<pair<Process, Entity>> procProducts;
for (Process proc=0; proc < rs->getNumberOfProcesses(); ++proc)
for (const Entity & e : procOutputs[proc])
procProducts.push_back(make_pair(proc, e));
output << indent << "mode=collect_"
<< rs->getProcessName(procProducts[0].first) << "_"
<< rs->getEntityName(procProducts[0].second) << "\n"
<< indent << indent << "if mode=activate_agents;\n\n";
for (unsigned pairIdx=1; pairIdx < procProducts.size(); ++pairIdx) {
output << indent << rs->getEntityName(procProducts[pairIdx-1].second)
<< "=1 and mode=collect_"
<< rs->getProcessName(procProducts[pairIdx].first) << "_"
<< rs->getEntityName(procProducts[pairIdx].second) << "\n"
<< indent << indent << "if mode=collect_"
<< rs->getProcessName(procProducts[pairIdx-1].first) << "_"
<< rs->getEntityName(procProducts[pairIdx-1].second)
<< " and " << rs->getProcessName(procProducts[pairIdx-1].first)
<< ".Action=produce_"
<< rs->getEntityName(procProducts[pairIdx-1].second)
<< ";\n";
output << indent << "mode=collect_"
<< rs->getProcessName(procProducts[pairIdx].first) << "_"
<< rs->getEntityName(procProducts[pairIdx].second) << "\n"
<< indent << indent << "if mode=collect_"
<< rs->getProcessName(procProducts[pairIdx-1].first) << "_"
<< rs->getEntityName(procProducts[pairIdx-1].second)
<< " and (" << rs->getProcessName(procProducts[pairIdx-1].first)
<< ".Action=not_produce_"
<< rs->getEntityName(procProducts[pairIdx-1].second)
<< " or " << rs->getProcessName(procProducts[pairIdx-1].first)
<< ".Action=sleep);\n\n";
}
output << indent << rs->getEntityName(procProducts.rbegin()->second)
<< "=1 and mode=distribute_local\n"
<< indent << indent << "if mode=collect_"
<< rs->getProcessName(procProducts.rbegin()->first) << "_"
<< rs->getEntityName(procProducts.rbegin()->second)
<< " and " << rs->getProcessName(procProducts.rbegin()->first)
<< ".Action=produce_"
<< rs->getEntityName(procProducts.rbegin()->second)
<< ";\n";
output << indent << "mode=distribute_local\n"
<< indent << indent << "if mode=collect_"
<< rs->getProcessName(procProducts.rbegin()->first) << "_"
<< rs->getEntityName(procProducts.rbegin()->second)
<< " and (" << rs->getProcessName(procProducts.rbegin()->first)
<< ".Action=not_produce_"
<< rs->getEntityName(procProducts.rbegin()->second)
<< " or " << rs->getProcessName(procProducts.rbegin()->first)
<< ".Action=sleep);\n\n";
//--------------------------------------------------------------------------------
// The entities available in the environment are distributed between the agents.
//--------------------------------------------------------------------------------
output << indent <<"--------------------------------------------------------------------------------\n"
<< indent <<"-- The entities available in the environment are distributed between the agents. \n"
<< indent <<"--------------------------------------------------------------------------------\n\n"
<< indent;
bool first = true;
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc) {
for (const Entity & e : procInputs[proc]) {
if (!first)
output << " and ";
else
first = false;
output << rs->getProcessName(proc) << "_" << rs->getEntityName(e) << "=" << rs->getEntityName(e);
}
output << "\n" << indent;
}
output << "and mode=add_context\n" << indent << indent
<< "if mode=distribute_local;\n\n";
//--------------------------------------------------------------------------------
// A set of additional entities, if any, is provided for each active agent
// following the context automaton transition description.
//--------------------------------------------------------------------------------
output << indent <<"--------------------------------------------------------------------------------\n"
<< indent <<"-- A set of additional entities, if any, is provided for each active agent\n"
<< indent <<"-- following the context automaton transition description.\n"
<< indent <<"--------------------------------------------------------------------------------\n\n"
<< indent;
transNo = 1;
vector<tuple<State, State, unsigned>> noCtxTrans;
for (const CtxAutTransition & trans : rs->ctx_aut->transitions) {
if (rs->ctx_aut->getStateName(trans.dst_state) == "T")
continue;
string ctxStr {""};
string separator {""};
first = true;
for (const auto & procCtx : trans.ctx) {
for (auto ent : procCtx.second) {
if (first) {
first = false;
separator = "";
}
else
separator = "and ";
ctxStr += separator + rs->getProcessName(procCtx.first) + "_" + rs->getEntityName(ent) + "=1 ";
}
}
if (ctxStr.length() > 0)
output << indent << ctxStr
<< "and mode=distribute_global\n" << indent << indent
<< "if mode=add_context and transition="
<< rs->ctx_aut->getStateName(trans.src_state) << "_" << rs->ctx_aut->getStateName(trans.dst_state) << "_" << transNo
<< ";\n\n";
else
noCtxTrans.push_back({trans.src_state, trans.dst_state, transNo});
++transNo;
}
//--------------------------------------------------------------------------------
// Mode change for transitions having no additional entities in the context
//--------------------------------------------------------------------------------
if (noCtxTrans.size() > 0) {
output << indent << "mode=distribute_global if mode=add_context and\n"
<< indent << indent << " (transition=init_0";
for (const auto & trans : noCtxTrans) {
output << " or transition=" << rs->ctx_aut->getStateName(get<0>(trans))
<< "_" << rs->ctx_aut->getStateName(get<1>(trans))
<< "_" << get<2>(trans);
}
output << ");\n\n";
}
//--------------------------------------------------------------------------------
// Notify active agents to execute all possible reactions.
//--------------------------------------------------------------------------------
output << indent << "--------------------------------------------------------------------------------\n"
<< indent <<"-- Notify active agents to execute all possible reactions.\n"
<< indent <<"--------------------------------------------------------------------------------\n\n"
<< indent;
output << "mode=produce if mode=distribute_global;\n\n";
output << indent << "mode=finalize\n"
<< indent << indent << "if mode=produce;\n\n";
//--------------------------------------------------------------------------------
// Select next computation step (choose context automaton transition).
//--------------------------------------------------------------------------------
output << indent <<"--------------------------------------------------------------------------------\n"
<< indent <<"-- Select next computation step (choose context automaton transition).\n"
<< indent <<"--------------------------------------------------------------------------------\n\n"
<< indent;
transNo = 1;
for (const CtxAutTransition & trans : rs->ctx_aut->transitions) {
if (rs->ctx_aut->getStateName(trans.dst_state) == "T")
continue;
output << indent << "mode=clear and state="
<< rs->ctx_aut->getStateName(trans.dst_state)
<< " and transition="
<< rs->ctx_aut->getStateName(trans.src_state) << "_"
<< rs->ctx_aut->getStateName(trans.dst_state) << "_"
<< transNo << "\n" << indent << indent;
output << "\n" << indent << indent << "if mode=finalize and state="
<< rs->ctx_aut->getStateName(trans.src_state);
if (trans.state_constr)
output << " and " << stateConstrToStr(trans.state_constr);
output << ";\n\n";
++transNo;
}
output << "end Evolution\n";
}
void RSExporter::exportEnvironmentInitState() {
output << indent << "Environment.mode=clear\n\n";
for (const string & procName : rs->processes_ids)
output << indent << indent << "and Environment.Active_" << procName << "=0\n";
output << "\n";
for (const string & entName : rs->entities_ids)
output << indent << indent << "and Environment." << entName << "=0\n";
output << "\n";
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc) {
for (const Entity & e : procInputs[proc])
output << indent << indent << "and Environment." << rs->getProcessName(proc) << "_"
<< rs->entities_ids[e] << "=0\n";
output << "\n";
}
State initState = rs->ctx_aut->getInitState();
output << indent << indent
<< "and Environment.state="
<< rs->ctx_aut->getStateName(initState) << "\n"
<< indent << indent << "and Environment.transition=init_0";
}
void RSExporter::exportAgent(const Process & proc) {
output << "\nAgent " << rs->processes_ids[proc] << "\n\n";
exportAgentVars(proc);
exportAgentProtocol(proc);
exportAgentEvolution(proc);
output << "end Agent\n" << endl;
}
void RSExporter::exportAgentVars(const Process & proc) {
output << "Vars:\n"
<< indent << "isActive: 0..1;\n";
for (const Entity & e : procInputs[proc]) {
output << indent << rs->entities_ids[e] << "_in: 0..1;\n";
}
for (const Entity & e : procOutputs[proc]) {
output << indent << rs->entities_ids[e] << "_out: 0..1;\n";
}
output << "end Vars\n\n";
output << "Actions = {\n";
for (const Entity & e : procOutputs[proc]) {
output << indent << "produce_" << rs->entities_ids[e]
<< ", not_produce_" << rs->entities_ids[e] << ",\n";
}
output << indent << "sleep\n};\n\n";
}
void RSExporter::exportAgentProtocol(const Process & proc) {
string procName = rs->processes_ids[proc];
output << "Protocol:\n";
for (const Entity & e : procOutputs[proc]) {
string entityName = rs->entities_ids[e];
output << indent << entityName << "_out=1 and (Environment.mode=collect_" << procName << "_" << entityName
<< " and isActive=1): {produce_" << entityName << "};\n"
<< indent << entityName << "_out=0 and (Environment.mode=collect_" << procName << "_" << entityName
<< " and isActive=1): {not_produce_" << entityName << "};\n\n";
}
output << indent << "Other: {sleep};\n"
<< "end Protocol\n\n";
}
void RSExporter::exportAgentEvolution(const Process & proc) {
string procName = rs->processes_ids[proc];
output << "Evolution:\n\n";
//--------------------------------------------------------------------------------
// Set the agent's activity status.
//--------------------------------------------------------------------------------
output << indent <<"--------------------------------------------------------------------------------\n"
<< indent <<"-- Set the agent's activity status.\n"
<< indent <<"--------------------------------------------------------------------------------\n\n";
output << indent << "isActive=Environment.Active_" << procName << " ";
for (const Entity & e : procInputs[proc])
output << "and " << rs->entities_ids[e] << "_in=0 ";
output << "\n" << indent << indent << "if Environment.Action=activate_agents;\n\n";
bool first {true};
//--------------------------------------------------------------------------------
// Synchronise with the environment state.
//--------------------------------------------------------------------------------
output << indent << "--------------------------------------------------------------------------------\n"
<< indent <<"-- Synchronise with the environment state.\n"
<< indent <<"--------------------------------------------------------------------------------\n\n";
for (const Entity & e : procInputs[proc]) {
string entityName = rs->entities_ids[e];
if (first) {
first = false;
output << indent;
}
else {
output << "and ";
}
output << entityName << "_in=Environment." << procName << "_" << entityName << " ";
}
output << "\n" << indent << indent << "if isActive=1 and Environment.Action=distribute_global;\n\n";
exportAgentReactions(proc);
output << "end Evolution\n\n";
}
void RSExporter::exportAgentReactions(const Process & proc) {
output << indent <<"--------------------------------------------------------------------------------\n"
<< indent <<"-- Agent's reactions.\n"
<< indent <<"--------------------------------------------------------------------------------\n\n";
// For each entity produced accumulate all the ways it may be produced
map<string, string> sources;
for (const auto & reaction : rs->proc_reactions[proc]) {
string rctCond = reactionCondToStr(reaction);
for (const Entity & e : reaction.prod) {
string rctProduct = rs->getEntityName(e);
if (sources.count(rctProduct))
sources[rctProduct] = appendCondition(sources[rctProduct], rctCond);
else
sources[rctProduct] = rctCond;
}
}
// Output a single formula combining all the agent's reactions
bool moreReactions {false};
for (const auto & entry : sources) {
if (moreReactions)
output << indent << indent << "and\n";
else
moreReactions = true;
output << indent << entry.first << "_out = " << entry.second << "\n";
}
output << indent << indent << "if isActive=1 and Environment.Action=produce;\n\n";
}
void RSExporter::exportAgentInitState(const Process & proc) {
string procName = rs->processes_ids[proc];
output << "\n\n" << indent << indent << "and " << procName << ".isActive=0";
for (const Entity & e : procInputs[proc]) {
output << "\n" << indent << indent << "and " << procName << "." << rs->entities_ids[e] << "_in=0";
}
for (const Entity & e : procOutputs[proc]) {
output << "\n" << indent << indent << "and " << procName << "." << rs->entities_ids[e] << "_out=0";
}
}
void RSExporter::parseFormulas() {
for (const auto & prop : drv->properties) {
formulas.push_back(formulaToStr(prop.second));
}
}
void RSExporter::exportEvaluation() {
output << "\nEvaluation\n";
for (const auto & a : atoms)
output << indent << a.second << " if " << a.first << ";\n";
output << "end Evaluation" << endl;
}
void RSExporter::exportInitStates() {
output << "\nInitStates\n";
exportEnvironmentInitState();
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc)
exportAgentInitState(proc);
output << ";\n"
<< "end InitStates" << endl;
}
void RSExporter::exportFormulae() {
output << "\nFormulae\n";
for (const string & fStr : formulas)
output << indent << fStr << ";\n";
output << "end Formulae" << endl;
}
/* State constraints are required to be in conjunctive normal form. */
string RSExporter::stateConstrToStr(const StateConstr * guard) {
string expr;
switch (guard->oper) {
case STC_PV:
return guard->proc_name + "_" + guard->entity_name + "=1";
case STC_TF:
return guard->tf ? "true" : "false";
case STC_AND:
return "(" + stateConstrToStr(guard->arg[0]) + " and " + stateConstrToStr(guard->arg[1]) + ")";
case STC_OR:
return "(" + stateConstrToStr(guard->arg[0]) + " or " + stateConstrToStr(guard->arg[1]) + ")";
case STC_NOT:
expr = stateConstrToStr(guard->arg[0]);
return expr.substr(0, expr.length()-1) + "0";
default:
return "??";
assert(0);
}
}
string RSExporter::reactionCondToStr(const Reaction & reaction) {
string cond;
bool moreRctts {false};
for (const Entity & e : reaction.rctt) {
if (moreRctts)
cond += "*";
else
moreRctts = true;
cond += rs->getEntityName(e) + "_in";
}
for (const Entity & e : reaction.inhib)
cond += "*(1-" + rs->getEntityName(e) + "_in)";
return cond;
}
string RSExporter::appendCondition(string & oldCond, string & newCond) {
return "(" + oldCond + ") + " + newCond + " - (" + oldCond + ") * " + newCond;
}
string RSExporter::formulaToStr(const FormRSCTLK * form) {
string varStr;
string labelStr;
switch (form->oper) {
case RSCTLK_PV: // propositional variable
varStr = form->proc_name + "." + form->entity_name + "_out=1";
if (atoms.find(varStr) == atoms.end()) {
labelStr = "atomic_" + to_string(atoms.size());
atoms[varStr] = labelStr;
}
else {
labelStr = atoms[varStr];
}
return labelStr;
case RSCTLK_AND:
return "(" + formulaToStr(form->arg[0]) + " and " + formulaToStr(form->arg[1]) + ")";
case RSCTLK_OR:
return "(" + formulaToStr(form->arg[0]) + " or " + formulaToStr(form->arg[1]) + ")";
case RSCTLK_XOR:
return "((" + formulaToStr(form->arg[0]) + " or " + formulaToStr(form->arg[1]) + ") and !(" +
formulaToStr(form->arg[0]) + " and " + formulaToStr(form->arg[1]) + "))";
case RSCTLK_NOT:
return "!(" + formulaToStr(form->arg[0]) +")";
case RSCTLK_IMPL:
return "(" + formulaToStr(form->arg[0]) + " -> " + formulaToStr(form->arg[1]) + ")";
case RSCTLK_EG: // Existential...
return "EG(" + formulaToStr(form->arg[0]) + ")";
case RSCTLK_EU:
return "E(" + formulaToStr(form->arg[0]) + " U " + formulaToStr(form->arg[1]) + ")";
case RSCTLK_EX:
return "EX(" + formulaToStr(form->arg[0]) + ")";
case RSCTLK_EF:
return "EF(" + formulaToStr(form->arg[0]) + ")";
case RSCTLK_AG: // Universal...
return "AG(" + formulaToStr(form->arg[0]) + ")";
case RSCTLK_AU:
return "A(" + formulaToStr(form->arg[0]) + " U " + formulaToStr(form->arg[1]) + ")";
case RSCTLK_AX:
return "AX(" + formulaToStr(form->arg[0]) + ")";
case RSCTLK_AF:
return "AF(" + formulaToStr(form->arg[0]) + ")";
case RSCTLK_UK: // Epistemic operators
return "K(" + form->getSingleAgent() + ", " + formulaToStr(form->arg[0]) + ")";
default:
assert(0);
return "??";
}
}
void RSExporter::exportToXML() {
output << "<xml version=\"1.0\">\n"
<< indent << "<reaction-system>\n";
for (Process proc=0; proc<rs->getNumberOfProcesses(); ++proc) {
output << indent << indent << "<process name=\"" << rs->processes_ids[proc] << "\">\n";
for (const auto & reaction : rs->proc_reactions[proc]) {
output << indent << indent << indent << "<reaction>\n";
for (const Entity & e : reaction.rctt) {
output << indent << indent << indent << indent
<< "<reactant>" << rs->getEntityName(e) << "</reactant>\n";
}
for (const Entity & e : reaction.inhib) {
output << indent << indent << indent << indent
<< "<inhibitor>" << rs->getEntityName(e) << "</inhibitor>\n";
}
for (const Entity & e : reaction.prod) {
output << indent << indent << indent << indent
<< "<product>" << rs->getEntityName(e) << "</product>\n";
}
output << indent << indent << indent << "</reaction>\n";
}
output << indent << indent << "</process>\n";
}
output << indent << "</reaction-system>\n";
output << indent << "<context-automaton>\n";
for (unsigned stId=0; stId<rs->ctx_aut->states_ids.size(); ++stId) {
if (rs->ctx_aut->states_ids[stId] == "T")
continue;
output << indent << indent << "<state id=\"" << stId + 1 << "\" name=\""
<< rs->ctx_aut->states_ids[stId] << "\" x=\"0\" y=\"0\"";
if (rs->ctx_aut->init_state_defined && stId == rs->ctx_aut->init_state_id)
output << " initial=\"true\"";
output << "/>\n";
}
vector<map<State, vector<CtxAutTransition>>> edges(rs->ctx_aut->states_ids.size());
for (const CtxAutTransition & trans : rs->ctx_aut->transitions) {
if (rs->ctx_aut->states_ids[trans.src_state] == "T" || rs->ctx_aut->states_ids[trans.dst_state] == "T")
continue;
edges[trans.src_state][trans.dst_state].push_back(trans);
}
for (unsigned src=0; src<edges.size(); ++src) {
for (const auto &dst : edges[src]) {
output << indent << indent << "<edge from=\"" << rs->ctx_aut->getStateName(src)
<< "\" to=\"" << rs->ctx_aut->getStateName(dst.first) << "\">\n";
for (const CtxAutTransition &trans : dst.second) {
output << indent << indent << indent << "<transition context=\"" << rs->procEntitiesToStr(trans.ctx) << "\"";
if (trans.state_constr)
output << " guard=\"" << trans.state_constr->toStr() << "\"";
output << "/>\n";
}
output << indent << indent << "</edge>\n";
}
}
output << indent << "</context-automaton>\n";
output << indent << "<formulas>\n";
for (const auto & prop : drv->properties) {
string fStr = "";
for (const char ch : prop.second->toStr()) {
if (ch == '<')
fStr += "&lt;";
else if (ch =='>')
fStr += "&gt;";
else
fStr += ch;
}
output << indent << indent << indent << "<formula label=\"" << prop.first <<"\">"
<< fStr << "</formula>\n";
}
output << indent << "</formulas>\n";
output << "</xml>" << endl;
}

57
reactics-bdd/export.hh Normal file
View File

@@ -0,0 +1,57 @@
#ifndef EXPORT_HH
#define EXPORT_HH
#include <iostream>
#include "types.hh"
#include "mc.hh"
#include "rs.hh"
#include "rsin_driver.hh"
class RSExporter {
public:
RSExporter(RctSys *rs, rsin_driver *drv, std::ostream & outStream = std::cout);
void exportToISPL();
void exportToXML();
private:
RctSys *rs;
rsin_driver *drv;
string indent {" "};
std::ostream &output;
void exportEnvironment();
void exportAgent(const Process & proc);
void exportEnvironmentVars();
void exportEnvironmentActions();
void exportEnvironmentProtocol();
void exportEnvironmentEvolution();
void exportEnvironmentInitState();
void exportAgentVars(const Process & proc);
void exportAgentProtocol(const Process & proc);
void exportAgentEvolution(const Process & proc);
void exportAgentReactions(const Process & proc);
void exportAgentInitState(const Process & proc);
void parseFormulas();
void exportEvaluation();
void exportInitStates();
void exportFormulae();
std::string stateConstrToStr(const StateConstr * guard);
std::string reactionCondToStr(const Reaction & reaction);
std::string appendCondition(std::string & oldCond, std::string & newCond);
std::string formulaToStr(const FormRSCTLK * form);
EntitiesForProc procInputs;
EntitiesForProc procOutputs;
std::map<std::string, std::string> atoms;
std::vector<std::string> formulas;
};
#endif

View File

@@ -172,39 +172,6 @@ bool FormRSCTLK::isERSCTLK(void) const
std::string FormRSCTLK::getActionsStr(void) const
{
// if (actions != nullptr) {
// std::string r = "[ ";
// bool firstact = true;
//
// for (ActionsVec_f::iterator act = actions->begin(); act != actions->end();
// ++act) {
// if (!firstact) {
// r += ",";
// }
// else {
// firstact = false;
// }
//
// r += "{";
// bool firstent = true;
//
// for (Action_f::iterator ent = act->begin(); ent != act->end(); ++ent) {
// if (!firstent) {
// r += ",";
// }
// else {
// firstent = false;
// }
//
// r += *ent;
// }
//
// r += "}";
// }
//
// r += " ]";
// return r;
// }
if (boolCtx != nullptr) {
return "< " + boolCtx->toStr() + " >";
}
@@ -222,22 +189,6 @@ void FormRSCTLK::encodeActions(const SymRS *srs)
actions_bdd = new BDD(srs->getBDDfalse());
assert(boolCtx != nullptr);
// assert(actions != nullptr || boolCtx != nullptr);
// assert(!(actions != nullptr && boolCtx != nullptr));
// if (actions != nullptr) {
// for (ActionsVec_f::iterator act = actions->begin(); act != actions->end();
// ++act) {
// BDD single_action = srs->getBDDtrue();
//
// for (Action_f::iterator ent = act->begin(); ent != act->end(); ++ent) {
// single_action *= srs->encActStrEntity(*ent);
// }
//
// single_action = srs->compContext(single_action);
// *actions_bdd += single_action;
// }
// }
if (boolCtx != nullptr) {
*actions_bdd = boolCtx->getBDDforContext(srs);
}

View File

@@ -9,7 +9,6 @@
#include <iostream>
#include <string>
#include <cassert>
// #include "rs.hh"
#include "symrs.hh"
#include "cudd.hh"
#include "types.hh"
@@ -56,22 +55,21 @@
using std::cout;
using std::endl;
// typedef std::string Entity_f;
// typedef std::set<Entity_f> Action_f;
// typedef vector<Action_f> ActionsVec_f;
typedef std::set<std::string> Agents_f;
class StateConstr;
class RSExporter;
class FormRSCTLK
{
friend class RSExporter;
Oper oper;
FormRSCTLK *arg[2];
std::string entity_name;
std::string proc_name;
bool tf;
BDD *bdd;
// ActionsVec_f *actions;
BDD *actions_bdd;
StateConstr *boolCtx;
Agents_f agents;
@@ -90,7 +88,6 @@ class FormRSCTLK
arg[0] = nullptr;
arg[1] = nullptr;
bdd = nullptr;
// actions = nullptr;
actions_bdd = nullptr;
boolCtx = nullptr;
}
@@ -107,7 +104,6 @@ class FormRSCTLK
arg[0] = nullptr;
arg[1] = nullptr;
bdd = nullptr;
// actions = nullptr;
actions_bdd = nullptr;
boolCtx = nullptr;
}
@@ -123,28 +119,10 @@ class FormRSCTLK
arg[0] = form1;
arg[1] = form2;
bdd = nullptr;
// actions = nullptr;
actions_bdd = nullptr;
boolCtx = nullptr;
}
/**
* @brief Constructor for two-argument formula with action restrictions.
*/
// FormRSCTLK(Oper op, ActionsVec_f *acts, FormRSCTLK *form1, FormRSCTLK *form2)
// {
// assert(acts != nullptr);
// assert(RSCTLK_COND_2ARG(op));
// assert(RSCTLK_COND_ACT(op));
// oper = op;
// arg[0] = form1;
// arg[1] = form2;
// bdd = nullptr;
// actions = acts;
// actions_bdd = nullptr;
// boolCtx = nullptr;
// }
/**
* @brief Constructor for two-argument formula with Boolean context restrictions.
*/
@@ -157,7 +135,6 @@ class FormRSCTLK
arg[0] = form1;
arg[1] = form2;
bdd = nullptr;
// actions = nullptr;
actions_bdd = nullptr;
boolCtx = bctx;
}
@@ -173,28 +150,10 @@ class FormRSCTLK
arg[0] = form1;
arg[1] = nullptr;
bdd = nullptr;
// actions = nullptr;
actions_bdd = nullptr;
boolCtx = nullptr;
}
/**
* @brief Constructor for one-argument formula with action restrictions.
*/
// FormRSCTLK(Oper op, ActionsVec_f *acts, FormRSCTLK *form1)
// {
// assert(acts != nullptr);
// assert(RSCTLK_COND_1ARG(op));
// assert(RSCTLK_COND_ACT(op));
// oper = op;
// arg[0] = form1;
// arg[1] = nullptr;
// bdd = nullptr;
// // actions = acts;
// actions_bdd = nullptr;
// boolCtx = nullptr;
// }
/**
* @brief Constructor for one-argument formula with Boolean context restrictions.
*/
@@ -207,7 +166,6 @@ class FormRSCTLK
arg[0] = form1;
arg[1] = nullptr;
bdd = nullptr;
// actions = nullptr;
actions_bdd = nullptr;
boolCtx = bctx;
}
@@ -231,7 +189,6 @@ class FormRSCTLK
delete arg[0];
delete arg[1];
delete bdd;
// delete actions;
delete actions_bdd;
delete boolCtx;
}

View File

@@ -42,10 +42,10 @@ for form in $forms; do
echo "$x" > $filename
./gen_bc.py $n $form > tmp.rs
./gen_bc.py $n $form > tmp.drs
echo "EXEC: $tool $options $popt tmp.rs"
$tool $options $popt tmp.rs >&1 >> $filename
echo "EXEC: $tool $options $popt tmp.drs"
$tool $options $popt tmp.drs >&1 >> $filename
result="$(tail -1 $filename | grep -E '.*;.*;.*;.*'| sed "s/STAT/$n /")"
if [ "$result" = "" ];then

View File

@@ -44,11 +44,11 @@ for form in $forms; do
echo "$x" > $filename
./gen_mutex.py $n $form > tmp.rs
./gen_mutex.py $n $form > tmp.drs
echo "EXEC: $tool $options $popt tmp.rs"
echo "EXEC: $tool $options $popt tmp.drs"
$tool $options $popt tmp.rs >&1 >> $filename
$tool $options $popt tmp.drs >&1 >> $filename
result="$(tail -1 $filename | grep -E '.*;.*;.*;.*'| sed "s/STAT/$n /")"
if [ "$result" = "" ];then

View File

@@ -43,11 +43,11 @@ for form in $forms; do
echo "$x" > $filename
./gen_abstract1.py $n $form > tmp.rs
./gen_abstract1.py $n $form > tmp.drs
echo "EXEC: $tool $options $popt tmp.rs"
echo "EXEC: $tool $options $popt tmp.drs"
$tool $options $popt tmp.rs >&1 >> $filename
$tool $options $popt tmp.drs >&1 >> $filename
result="$(tail -1 $filename | grep -E '.*;.*;.*;.*'| sed "s/STAT/$n /")"
if [ "$result" = "" ];then

View File

@@ -4,8 +4,8 @@ for x in `seq 2 1 24`;do
echo $y $x
filename="results/f${y}_n${x}.out"
echo "$x" > $filename
./gen_bc.py $x $y > tmp.rs
../main -c -B tmp.rs >> $filename
./gen_bc.py $x $y > tmp.drs
../main -c -B tmp.drs >> $filename
result="$(tail -1 $filename | sed "s/STAT/$x /")"
echo $result >> results/summary_f${y}.out
echo $result
@@ -13,4 +13,4 @@ for x in `seq 2 1 24`;do
done
done
rm tmp.rs
rm tmp.drs

View File

@@ -4,8 +4,8 @@ for x in `seq 1 60`;do
echo $x
filename="results/abs_v${y}_f0_n${x}.out"
echo "$x" > $filename
./gen_abstract1.py $x $y > tmp.rs
../main -z -c -p -v -B tmp.rs >&1 >> $filename
./gen_abstract1.py $x $y > tmp.drs
../main -z -c -p -v -B tmp.drs >&1 >> $filename
result="$(tail -1 $filename | sed "s/STAT/$x /")"
echo $result >> results/summary_v${y}_abs_f0.out
echo $result
@@ -13,4 +13,4 @@ for x in `seq 1 60`;do
done
done
rm tmp.rs
rm tmp.drs

View File

@@ -4,8 +4,8 @@ for x in `seq 1 60`;do
echo $x
filename="results/abs_v${y}_f0_n${x}_PT.out"
echo "$x" > $filename
./gen_abstract1.py $x $y > tmp.rs
../main -z -x -c -p -v -B tmp.rs >&1 >> $filename
./gen_abstract1.py $x $y > tmp.drs
../main -z -x -c -p -v -B tmp.drs >&1 >> $filename
result="$(tail -1 $filename | sed "s/STAT/$x /")"
echo $result >> results/summary_v${y}_abs_f0_PT.out
echo $result
@@ -13,4 +13,4 @@ for x in `seq 1 60`;do
done
done
rm tmp.rs
rm tmp.drs

View File

@@ -4,8 +4,8 @@ for x in `seq 1 50`;do
echo $x $y
filename="results/bc_f${y}_n${x}.out"
echo "$x" > $filename
./gen_bc.py $x $y > tmp.rs
../main -z -c -v -B tmp.rs >&1 >> $filename
./gen_bc.py $x $y > tmp.drs
../main -z -c -v -B tmp.drs >&1 >> $filename
result="$(tail -1 $filename | sed "s/STAT/$x /")"
echo $result >> results/summary_bc_f${y}.out
echo $result
@@ -13,4 +13,4 @@ for x in `seq 1 50`;do
done
done
rm tmp.rs
rm tmp.drs

View File

@@ -4,8 +4,8 @@ for x in `seq 2 40`;do
echo $x $y
filename="results/mutex_f${y}_n${x}.out"
echo "$x" > $filename
./gen_mutex.py $x $y > tmp.rs
../main -z -c -p -v -B tmp.rs >&1 >> $filename
./gen_mutex.py $x $y > tmp.drs
../main -z -c -p -v -B tmp.drs >&1 >> $filename
result="$(tail -1 $filename | sed "s/STAT/$x /")"
echo $result >> results/summary_mutex_f${y}.out
echo $result
@@ -13,4 +13,4 @@ for x in `seq 2 40`;do
done
done
rm tmp.rs
rm tmp.drs

View File

@@ -4,8 +4,8 @@ for x in `seq 2 40`;do
echo $x $y
filename="results/mutex_f${y}_n${x}_PT.out"
echo "$x" > $filename
./gen_mutex.py $x $y > tmp.rs
../main -zcpxvB tmp.rs >&1 >> $filename
./gen_mutex.py $x $y > tmp.drs
../main -zcpxvB tmp.drs >&1 >> $filename
result="$(tail -1 $filename | sed "s/STAT/$x /")"
echo $result >> results/summary_mutex_f${y}_PT.out
echo $result
@@ -13,4 +13,4 @@ for x in `seq 2 40`;do
done
done
rm tmp.rs
rm tmp.drs

View File

@@ -1,47 +0,0 @@
#!/usr/bin/env python
from sys import argv,exit
if len(argv) < 3:
print "Usage:", argv[0], "<number of modules> <variant>"
exit(100)
n = int(argv[1])
v = int(argv[2])
if not ( v > 0 and v < 3 ):
print "unsupported variant"
exit(100)
print "reactions {"
s = "\t{ {x},{s} -> {a1} };\n"
print s
for i in range(1,n+1):
s = "\t{ {a" + str(i) + "},{s} -> {y" + str(i) + "} };\n"
s += "\t{ {a" + str(i) + "},{s} -> {b" + str(i) + "} };\n"
s += "\t{ {b" + str(i) + "},{s} -> {c" + str(i) + "} };\n"
s += "\t{ {c" + str(i) + "},{s} -> {d" + str(i) + "} };\n"
s += "\t{ {d" + str(i) + ",y" + str(i) + "},{s} -> {a" + str(i+1) + "} };\n"
s += "\t{ {y" + str(i) + "},{s} -> {y" + str(i) + "} };\n"
print s
s = "\t{ {a" + str(n+1)
for i in range(1,n+1):
s += ",y" + str(i)
s += "},{s} -> {r} };\n"
print s
print "}"
if v == 1:
print "context-entities { s }"
elif v == 2:
s = "context-entities { s"
for i in range(1,n+1):
if i % 2 == 0:
s += ",a" + str(i)
s += " }"
print s
print "initial-contexts { {x} }"
print "rsctl-property { E[{}]F(r) }"

View File

@@ -1,93 +0,0 @@
#!/usr/bin/env python
from sys import argv,exit
OPTIONS_STR = """
options { use-context-automaton; make-progressive; };
"""
PROC_STR = """
proc{:d} {{
{{{{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_STR = """
context-automaton {{
states {{ init, act }};
init-state {{ init }};
transitions {{
{:s}
}};
}};
"""
PROPERTY_STR = """
rsctlk-property {{ {:s} : {:s} }};
"""
#################################################################
if len(argv) < 1:
print("Usage: {:s} <number of processes>".format(argv[0]))
exit(100)
n = int(argv[1])
assert n > 1, "number of proc must be > 1"
out = ""
out += OPTIONS_STR
out += "reactions {\n"
for i in range(1, n+1):
out += PROC_STR.format(i)
out += FINAL_PROC
out += "};\n"
transitions = ""
init_trans = 8*" " + "{ proc1={a} }: init -> act;\n"
transitions += init_trans
for i in range(1, n+1):
transitions += "{:s}{{ proc{:d}={{}} }}: act -> act : ~proc{:d}.dy;\n".format(8*" ", i, i, i)
for i in range(2, n+1):
transitions += "{:s}{{ proc{:d}={{a}} }}: act -> act : proc{:d}.dy;\n".format(8*" ", i, i-1)
final_cond = "proc1.dy"
for i in range(2, n+1):
final_cond += " AND proc{:d}.dy".format(i)
transitions += "{:s}{{ procFinal={{done}} }}: act -> act : {:s};\n".format(8*" ", final_cond)
out += CA_STR.format(transitions)
# f1
formula = "EF( procFinal.done )"
out += PROPERTY_STR.format("f1",formula)
# f2
formula = "AG( proc{:d}.d IMPLIES K[proc{:d}]( proc{:d}.y ) )".format(n, n, n-1)
out += PROPERTY_STR.format("f2",formula)
# x1
formula = "EF( ~procFinal.done )"
out += PROPERTY_STR.format("x1",formula)
print(out)

View File

@@ -1,118 +0,0 @@
#!/usr/bin/env python2.7
from sys import argv,exit
if len(argv) < 3:
print "Usage:", argv[0], "<number of bits> <property>"
exit(100)
n = int(argv[1])
property = int(argv[2])
K = 8
if property == 3:
if n < K+1:
print "too small n"
exit(100)
if not ( property >= 1 and property < 5 ):
print "property: 1-4"
exit(101)
print "reactions {"
# (1) no dec, no inc
print "\t# (1) no decrement, no increment"
for j in range(0,n):
print "\t{{p" + str(j) + "},{dec,inc} -> {p" + str(j) + "}};"
# (2) increment
s = "\n\t# (2) increment operation\n"
s += "\t{{inc},{dec,p0} -> {p0}};\n"
for j in range(1,n):
s += "\t{{inc,"
for k in range(0,j):
s += "p" + str(k)
if k < j-1:
s += ","
s += "},{dec,p" + str(j) + "} -> {p" + str(j) + "}};\n"
print s
print "\t# the more significant bits remain (inc)"
s = ""
for j in range(0,n):
for k in range(j+1,n):
s += "\t{{inc,p" + str(k) + "},{dec,p" + str(j) + "} -> {p" + str(k) + "}};\n"
print s
print "\t# (3) decrement operation"
s = ""
for j in range(0,n):
s += "\t{{dec},{inc,"
for k in range(0,j+1):
s += "p" + str(k)
if k < j:
s += ","
s += "} -> {p" + str(j) + "}};\n"
print s
print "\t# the more significant bits remain (dec)"
s = ""
for j in range(0,n):
for k in range(j+1,n):
s += "\t{{dec,p" + str(j) + ",p" + str(k) + "},{inc} -> {p" + str(k) + "}};\n"
s += "}\n"
print s
print "context-entities { inc,dec }"
print "initial-contexts { {} }"
if property == 4:
print "rsctl-property { AG( p" + str(n-1) + " IMPLIES EF ~p" + str(n-1) + " ) }"
elif property == 1:
s = "rsctl-property { AG(("
for i in range(0,n):
s += "~p" + str(i)
if i < n-1:
s += " AND "
s += ") IMPLIES E[{inc},{dec}]F("
for i in range(0,n):
s += "p" + str(i)
if i < n-1:
s += " AND "
s += ")) }"
print s
elif property == 2:
s = "rsctl-property { AG(("
for i in range(0,n):
s += "p" + str(i)
if i < n-1:
s += " AND "
s += ") IMPLIES A[{inc}]X("
for i in range(0,n):
s += "~p" + str(i)
if i < n-1:
s += " AND "
s += ")) }"
print s
elif property == 3:
s = "rsctl-property { E[{inc}]F("
for i in range(0,n-K):
s += "p" + str(i)
if i < n-1:
s += " AND "
for i in range(n-K,n):
s += "~p" + str(i)
if i < n-1:
s += " AND "
s += ") }"
print s

View File

@@ -1,76 +0,0 @@
#!/usr/bin/env python
from sys import argv,exit
if len(argv) < 3:
print "Usage:", argv[0], "<number of processes> <formula>"
exit(100)
n = int(argv[1])
f = int(argv[2])
if not ( f>0 and f<4 ):
print "unsupported formula"
exit(100)
print "reactions {"
for i in range(0,n):
s = "\t{{out" + str(i) + ",act" + str(i) + "},{} -> {request" + str(i) + "}};\n"
s += "\t{{out" + str(i) + "},{act" + str(i) + "} -> {out" + str(i) + "}};\n"
for j in range(0,n):
if i != j:
s += "\t{{request" + str(i) + ",act" + str(i) + ",act" + str(j) + "},{} -> {request" + str(i) + "}};\n"
#s += "\t{{request" + str(i) + "},{"
#for j in range(0,n):
# s += "act" + str(j)
# if j < n-1:
# s += ","
#s += "} -> {request" + str(i) + "}};\n"
s += "\t{{request" + str(i) + "},{act" + str(i) + "} -> {request" + str(i) + "}};\n"
s += "\t{{request" + str(i) + ",act" + str(i) + "},{"
for j in range(0,n):
if i != j:
s += "act" + str(j) + ","
s += "lock} -> {in" + str(i) + ",lock}};\n"
s += "\t{{in" + str(i) + ",act" + str(i) + "},{} -> {out" + str(i) + ",done}};\n"
s += "\t{{in" + str(i) + "},{act" + str(i) + "} -> {in" + str(i) + "}};\n"
print s
print "\t{{lock},{done} -> {lock}};"
print "}"
s = "context-entities {"
for i in range(0,n):
s += "act" + str(i)
if i < n-1:
s += ","
s += "}\n"
print s
s = "initial-contexts { {"
for i in range(0,n):
s += "out" + str(i)
if i < n-1:
s += ","
s += "} }\n"
print s
#print "rsctl-property { A[{act1}]G(A[{act1}]F(in1)) }"
if f == 1:
print "rsctl-property { A[{act1}]F(in1) }"
elif f == 2:
print "rsctl-property { E[{act1}]F(in1) }"
elif f == 3:
s = "rsctl-property { AG("
for i in range(0,n):
for j in range(i+1,n):
s += "~(in" + str(i) + " AND in" + str(j) + ")"
if i < n-2:
s += " AND "
s += ") }"
print s
else:
exit(111)

View File

@@ -1,117 +0,0 @@
#!/usr/bin/env python
from sys import argv,exit
OPTIONS_STR = """
options { use-context-automaton; make-progressive; };
"""
PROC_STR = """
proc{:d} {{
{{{{out}}, {{}} -> {{approach}}}};
{{{{approach}}, {{req}} -> {{req}}}};
{{{{allowed}}, {{}} -> {{in}}}};
{{{{in}}, {{}} -> {{out,leave}}}};
{{{{req}}, {{in}} -> {{req}}}};
}};
"""
CA_STR = """
context-automaton {{
states {{ init, green, red }};
init-state {{ init }};
transitions {{
{:s}
}};
}};
"""
PROPERTY_STR = """
rsctlk-property {{ {:s} : {:s} }};
"""
#################################################################
if len(argv) < 1:
print("Usage: {:s} <number of processes>".format(argv[0]))
exit(100)
n = int(argv[1])
assert n > 1, "number of proc must be > 1"
out = ""
out += OPTIONS_STR
out += "reactions {\n"
for i in range(n):
out += PROC_STR.format(i)
out += "};\n"
transitions = ""
init_trans = 8*" " + "{ "
for i in range(n):
init_trans += "proc{:d}={{out}} ".format(i)
init_trans += "}: init -> green;\n"
transitions += init_trans
for i in range(n):
transitions += "{:s}{{ proc{:d}={{allowed}} }}: green -> red : proc{:d}.req;\n".format(8*" ", i, i)
no_req_cond = "~proc0.req"
for i in range(1, n):
no_req_cond += " AND ~proc{:d}.req".format(i)
for i in range(n):
transitions += "{:s}{{ proc{:d}={{}} }}: green -> green : {:s};\n".format(8*" ", i, no_req_cond)
for i in range(n):
transitions += "{:s}{{ proc{:d}={{}} }}: red -> green : proc{:d}.leave;\n".format(8*" ", i, i)
no_leave_cond = "~proc0.leave"
for i in range(1, n):
no_leave_cond += " AND ~proc{:d}.leave".format(i)
for i in range(n):
transitions += "{:s}{{ proc{:d}={{}} }}: red -> red : {:s};\n".format(8*" ", i, no_leave_cond)
out += CA_STR.format(transitions)
## f1
#formula = "EF( proc0.in )"
#out += PROPERTY_STR.format("f1",formula)
# f1
formula = "EF( E<proc0.allowed>X( proc0.in ) )"
for i in range(1, n):
formula += " AND EF( E<proc{:d}.allowed>X( proc{:d}.in ) )".format(i, i)
out += PROPERTY_STR.format("f1",formula)
# f2
formula = "EF( proc0.approach"
for i in range(1, n):
formula += " AND proc{:d}.approach".format(i)
formula += " )"
out += PROPERTY_STR.format("f2",formula)
# f3
subf = "~proc1.in"
for i in range(2, n):
subf += " AND ~proc{:d}.in".format(i)
formula = "AG( proc0.in IMPLIES K[proc0]({:s}) )".format(subf)
out += PROPERTY_STR.format("f3",formula)
# f4
subf = "~proc1.in"
for i in range(2, n):
subf += " AND ~proc{:d}.in".format(i)
all_agents = "proc0"
for i in range(1, n):
all_agents += ",proc{:d}".format(i)
formula = "AG( proc0.in IMPLIES C[{:s}]({:s}) )".format(all_agents,subf)
out += PROPERTY_STR.format("f4",formula)
print(out)

View File

@@ -198,8 +198,15 @@ void ModelChecker::printReachWithSucc(void)
while (!unproc.IsZero()) {
BDD t;
t = unproc.PickOneMinterm(*pv);
cout << "Successors of " << srs->decodedRctSysStateToStr(t) << ":" << endl;
srs->printDecodedRctSysStates(getSucc(t));
if (opts->backend_mode)
{
cout << "G " << srs->decodedRctSysStateWithCtxAutToStr(t) << endl;
}
else
{
cout << "Successors of " << srs->decodedRctSysStateWithCtxAutToStr(t) << ":" << endl;
}
srs->printDecodedRctSysWithCtxAutStates(getSucc(t));
unproc -= t;
}
@@ -510,9 +517,9 @@ BDD ModelChecker::getIthOnly(Process proc_id)
/* nothing has been found in the cache */
BDD bdd = BDD_TRUE;
for (auto i = 0; i < pv_drs_E->size(); ++i) {
for (size_t i = 0; i < pv_drs_E->size(); ++i) {
if (i == proc_id) {
if (i == static_cast<size_t>(proc_id)) {
continue;
}
@@ -584,18 +591,16 @@ bool ModelChecker::checkRSCTLKfull(FormRSCTLK *form)
VERB("Checking the formula");
//if (*initStates * getStatesRSCTLK(form) != cuddMgr->bddZero())
if (*initStates * getStatesRSCTLK(form) == *initStates) {
result = true;
}
else {
result = false;
}
result = (*initStates * getStatesRSCTLK(form) == *initStates);
cleanup();
if (opts->backend_mode) {
cout << "Result:" << result << endl;
} else {
cout << "Formula " << form->toStr() << (result ? " holds" : " does not hold")
<< endl;
}
if (opts->measure) {
opts->ver_time = cpuTime() - opts->ver_time;
@@ -658,8 +663,12 @@ bool ModelChecker::checkRSCTLKbmc(FormRSCTLK *form)
cleanup();
if (opts->backend_mode) {
cout << "result:" << result << endl;
} else {
cout << "Formula " << form->toStr() << " " << (result ? "holds" :
"does not hold") << endl;
}
if (opts->measure) {
opts->ver_time = cpuTime() - opts->ver_time;

View File

@@ -5,7 +5,12 @@
#define __MEMTIME_H__
#include <sys/time.h>
#ifdef __WIN32__
#include <windows.h>
#include <psapi.h>
#else
#include <sys/resource.h>
#endif
#if defined(__APPLE__)
#include <malloc/malloc.h>
#endif
@@ -17,6 +22,25 @@ using namespace std;
typedef long long int64;
#ifdef __WIN32__
static inline double cpuTime()
{
FILETIME createTime, exitTime, kernelTime, userTime;
if (!GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime)) {
return 0.0;
}
ULARGE_INTEGER u;
u.LowPart = userTime.dwLowDateTime;
u.HighPart = userTime.dwHighDateTime;
return (double)u.QuadPart / 10e6;
}
#else
static inline double cpuTime(void)
{
struct rusage ru;
@@ -24,6 +48,8 @@ static inline double cpuTime(void)
return (double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec / 1000000;
}
#endif
static inline int memReadStat(void)
{
char name[256];
@@ -47,11 +73,28 @@ static inline int memReadStat(void)
return value;
}
#ifdef __WIN32__
static inline int64 memUsedInt64()
{
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return (int64) pmc.WorkingSetSize;
}
return 0;
}
#else
static inline int64 memUsedInt64()
{
return (int64)memReadStat() * (int64)getpagesize();
}
#endif
#if defined(__APPLE__)
static inline double memUsed()

View File

@@ -11,6 +11,7 @@ class Options
bool part_tr_rel;
bool reorder_reach;
bool reorder_trans;
bool backend_mode;
double enc_time;
double enc_mem;
@@ -23,10 +24,12 @@ class Options
show_progress = false;
measure = false;
part_tr_rel = false;
part_tr_rel = true;
reorder_reach = false;
reorder_trans = false;
reorder_reach = true;
reorder_trans = true;
backend_mode = false;
enc_time = 0;
enc_mem = 0;

View File

@@ -16,6 +16,8 @@ int main(int argc, char **argv)
bool rstl_model_checking = false;
bool reach_states = false;
bool reach_states_succ = false;
bool export_to_ispl = false;
bool export_to_xml = false;
bool bmc = true;
bool benchmarking = false;
bool dump_help_message = false;
@@ -31,17 +33,17 @@ int main(int argc, char **argv)
int c;
int option_index = 0;
while ((c = getopt_long(argc, argv, "c:bBmpPrsStTvxzh", long_options,
while ((c = getopt_long(argc, argv, "c:bBmpPrsStTvXheyEG", long_options,
&option_index)) != -1) {
switch (c) {
case 0:
printf("option %s", long_options[option_index].name);
cout << "option " << long_options[option_index].name;
if (optarg) {
printf(" with arg %s", optarg);
cout << " with arg " << optarg;
}
printf("\n");
cout << endl;
if (strcmp(long_options[option_index].name, "trace-parsing")) {
driver.trace_parsing = true;
@@ -52,6 +54,14 @@ int main(int argc, char **argv)
break;
case 'e':
export_to_ispl = true;
break;
case 'y':
export_to_xml = true;
break;
//case 'b':
// printf("-b with %s\n", optarg);
// break;
@@ -97,13 +107,17 @@ int main(int argc, char **argv)
opts->verbose++;
break;
case 'x':
opts->part_tr_rel = true;
case 'E':
opts->reorder_reach = false;
opts->reorder_trans = false;
break;
case 'z':
opts->reorder_reach = true;
opts->reorder_trans = true;
case 'G':
opts->part_tr_rel = false;
break;
case 'X':
opts->backend_mode = true;
break;
case 'h':
@@ -132,8 +146,8 @@ int main(int argc, char **argv)
}
if (!(reach_states || reach_states_succ || rstl_model_checking
|| show_reactions || print_parsed_sys)) {
FERROR("No task specified: -c, -P, -r, or -s needs to be used");
|| show_reactions || print_parsed_sys || export_to_ispl || export_to_xml)) {
FERROR("No task specified: -c, -P, -r, -s, or -e needs to be used");
}
if (opts->verbose > 0) {
@@ -167,7 +181,7 @@ int main(int argc, char **argv)
rs.printSystem();
}
if (reach_states || reach_states_succ || rstl_model_checking) {
if (reach_states || reach_states_succ || rstl_model_checking || export_to_ispl || export_to_xml) {
SymRS srs(&rs, opts);
ModelChecker mc(&srs, opts);
@@ -180,6 +194,16 @@ int main(int argc, char **argv)
mc.printReachWithSucc();
}
if (export_to_ispl) {
RSExporter exp(&rs, &driver);
exp.exportToISPL();
}
if (export_to_xml) {
RSExporter exp(&rs, &driver);
exp.exportToXML();
}
if (rstl_model_checking) {
if (bmc) {
cout << "Using BDD-based Bounded Model Checking" << endl;
@@ -212,16 +236,7 @@ int main(int argc, char **argv)
delete opts;
int ret_val;
if (result) {
ret_val = 0;
}
else {
ret_val = 1;
}
return ret_val;
return result ? 0 : 1;
}
void print_help(std::string path_str)
@@ -252,16 +267,20 @@ void print_help(std::string path_str)
<< endl
<< endl << " OTHER:" << endl
<< " -b -- disable bounded model checking (BMC) heuristic" << endl
<< " -x -- use partitioned transition relation" <<
endl
<< " -z -- use reordering of the BDD variables" << endl
<< " -v -- verbose (use more than once to increase verbosity)" <<
endl
<< " -v -- verbose (use more than once to increase verbosity)" << endl
<< " -p -- show progress (where possible)" << endl
<< " -X -- backend mode (makes output parsing easier)" << endl
<< " -y -- export to XML (for GUI tool)" << endl
<< endl
<< " Optimisations:" << endl
<< " -E -- disable auto-reordering optimisation of BDDs" << endl
<< " -G -- disable partitioned transition relation optimisation" << endl
<< endl
<< " Benchmarking options:" << endl
<< " -m -- measure and display time and memory usage" << endl
<< " -B -- display an easy to parse summary (enables -m)" << endl
<< " -e -- exports to ISPL (MCMAS input format)" << endl
<< endl;
}

View File

@@ -18,6 +18,7 @@
#include "rsin_driver.hh"
#include "options.hh"
#include "memtime.hh"
#include "export.hh"
#define VERSION "2.0"
//#define AUTHOR "Artur Meski <artur.meski@gmail.com>"

View File

@@ -14,12 +14,7 @@ RctSys::RctSys(void)
bool RctSys::hasEntity(std::string name)
{
if (entities_names.find(name) == entities_names.end()) {
return false;
}
else {
return true;
}
return entities_names.find(name) != entities_names.end();
}
void RctSys::addEntity(std::string name)
@@ -84,21 +79,12 @@ void RctSys::addProcess(std::string processName)
bool RctSys::hasProcess(std::string processName)
{
if (processes_names.find(processName) == processes_names.end()) {
return false;
}
else {
return true;
}
return processes_names.find(processName) != processes_names.end();
}
bool RctSys::hasProcess(Process processID)
{
if (processID >= processes_ids.size()) {
return false;
}
return true;
return processID < processes_ids.size();
}
Process RctSys::getProcessID(std::string processName)
@@ -120,28 +106,26 @@ std::string RctSys::getProcessName(Process processID)
}
}
void RctSys::pushReactant(std::string entityName)
void RctSys::ensureEntity(std::string entityName)
{
if (!hasEntity(entityName)) {
addEntity(entityName);
}
}
void RctSys::pushReactant(std::string entityName)
{
ensureEntity(entityName);
tmpReactants.insert(getEntityID(entityName));
}
void RctSys::pushInhibitor(std::string entityName)
{
if (!hasEntity(entityName)) {
addEntity(entityName);
}
ensureEntity(entityName);
tmpInhibitors.insert(getEntityID(entityName));
}
void RctSys::pushProduct(std::string entityName)
{
if (!hasEntity(entityName)) {
addEntity(entityName);
}
ensureEntity(entityName);
tmpProducts.insert(getEntityID(entityName));
}
@@ -232,10 +216,7 @@ void RctSys::commitInitState(void)
void RctSys::addActionEntity(std::string entityName)
{
if (!hasEntity(entityName)) {
addEntity(entityName);
}
ensureEntity(entityName);
actionEntities.insert(getEntityID(entityName));
}
@@ -248,12 +229,7 @@ void RctSys::addActionEntity(Entity entity)
bool RctSys::isActionEntity(Entity entity)
{
if (actionEntities.count(entity) > 0) {
return true;
}
else {
return false;
}
return actionEntities.count(entity) > 0;
}
void RctSys::showActionEntities(void)

View File

@@ -28,6 +28,7 @@ class RctSys
{
friend class SymRS;
friend class SymRSstate;
friend class RSExporter;
public:
RctSys(void);
@@ -49,6 +50,7 @@ class RctSys
void addReactionForCurrentProcess(Reaction reaction);
void ensureEntity(std::string entityName);
void pushReactant(std::string entityName);
void pushInhibitor(std::string entityName);
void pushProduct(std::string entityName);

View File

@@ -23,9 +23,12 @@
#define STC_IS_VALID(a) (STC_COND_1ARG(a) || STC_COND_2ARG(a) || (a) == STC_PV || (a) == STC_TF)
class SymRS;
class RSExporter;
class StateConstr
{
friend class RSExporter;
Oper oper;
StateConstr *arg[2];
std::string entity_name;

View File

@@ -17,9 +17,6 @@ SymRS::SymRS(RctSys *rs, Options *opts)
totalEntities = rs->getEntitiesSize();
// TODO: remove
totalActions = 0;
totalRctSysStateVars = getTotalProductVariables();
totalCtxEntities = getTotalCtxEntitiesVariables();
@@ -404,39 +401,19 @@ BDD SymRS::encCtxEntity(Process proc_id, Entity entity) const
bool SymRS::productEntityExists(Process proc_id, Entity entity) const
{
if (prod_ent_local_idx.count(proc_id) == 0) {
return false;
}
else {
if (prod_ent_local_idx.at(proc_id).count(entity) == 1) {
return true;
}
}
return false;
return prod_ent_local_idx.count(proc_id) != 0 &&
prod_ent_local_idx.at(proc_id).count(entity) == 1;
}
bool SymRS::ctxEntityExists(Process proc_id, Entity entity) const
{
if (ctx_ent_local_idx.count(proc_id) == 0) {
return false;
}
else {
if (ctx_ent_local_idx.at(proc_id).count(entity) == 1) {
return true;
}
}
return false;
return ctx_ent_local_idx.count(proc_id) != 0 &&
ctx_ent_local_idx.at(proc_id).count(entity) == 1;
}
bool SymRS::processUsesEntity(Process proc_id, Entity entity_id) const
{
if (productEntityExists(proc_id, entity_id) || ctxEntityExists(proc_id, entity_id)) {
return true;
}
return false;
return productEntityExists(proc_id, entity_id) || ctxEntityExists(proc_id, entity_id);
}
BDD SymRS::encEntitiesConj_raw(Process proc_id, const Entities &entities, bool succ)
@@ -511,20 +488,6 @@ BDD SymRS::encContext(const EntitiesForProc &proc_entities)
return r;
}
BDD SymRS::compState(const BDD &state) const
{
assert(0);
BDD s = state;
for (unsigned int i = 0; i < totalRctSysStateVars; ++i) {
if (!(*pv)[i] * state != cuddMgr->bddZero()) {
s *= !(*pv)[i];
}
}
return s;
}
BDD SymRS::compContext(const BDD &context) const
{
BDD c = context;
@@ -567,13 +530,35 @@ std::string SymRS::decodedRctSysStateToStr(const BDD &state)
return s;
}
std::string SymRS::decodedRctSysStateWithCtxAutToStr(const BDD &state)
{
std::string s = "( ";
s += decodedRctSysStateToStr(state) + " ";
for (const auto &aut_state : rs->ctx_aut->states_ids) {
const auto state_id = rs->ctx_aut->getStateID(aut_state);
if (!(encCtxAutState(state_id) * state).IsZero()) {
s += aut_state + " ";
break;
}
}
s += ")";
return s;
}
void SymRS::printDecodedRctSysStates(const BDD &states)
{
BDD unproc = states;
while (!unproc.IsZero()) {
BDD t = unproc.PickOneMinterm(*pv_drs_flat);
if (opts->backend_mode)
{
cout << "s " << decodedRctSysStateToStr(t) << endl;
}
else
{
cout << decodedRctSysStateToStr(t) << endl;
}
if (opts->verbose > 9) {
BDD_PRINT(t);
@@ -584,6 +569,31 @@ void SymRS::printDecodedRctSysStates(const BDD &states)
}
}
void SymRS::printDecodedRctSysWithCtxAutStates(const BDD &states)
{
BDD unproc = states;
while (!unproc.IsZero()) {
BDD t = unproc.PickOneMinterm(*pv);
if (opts->backend_mode)
{
cout << "s " << decodedRctSysStateWithCtxAutToStr(t) << endl;
}
else
{
cout << decodedRctSysStateWithCtxAutToStr(t) << endl;
}
if (opts->verbose > 9) {
BDD_PRINT(t);
cout << endl;
}
unproc -= t;
}
}
DecompReactions SymRS::getProductionConditions(Process proc_id)
{
DecompReactions dr;
@@ -678,65 +688,6 @@ BDD SymRS::encEnabledness(Process prod_proc_id, Entity entity_id)
return enab;
}
// BDD SymRS::encEnabledness(Process prod_proc_id, Entity entity_id)
// {
// assert(prod_conds.size() > prod_proc_id);
// BDD enab = BDD_FALSE;
// auto production_conditions = prod_conds[prod_proc_id][entity_id];
// VERB_LN(5, "| Produce " << rs->getEntityName(entity_id) << " in " << rs->getProcessName(prod_proc_id) << ":");
// for (const auto &cond : production_conditions) {
// BDD reactants = BDD_TRUE;
// BDD inhibitors = BDD_TRUE;
// for (const auto &reactant : cond.rctt) {
// BDD proc_reactants = BDD_FALSE;
// for (unsigned int proc_id = 0; proc_id < numberOfProc; ++proc_id) {
// if (processUsesEntity(proc_id, reactant)) {
// proc_reactants += encProcEnabled(proc_id) * encEntityCondition(proc_id, reactant);
// VERB_LN(5, "| - if process " << rs->getProcessName(proc_id) << " is enabled and has " << rs->getEntityName(reactant));
// }
// } // END FOR: prod_id
// reactants *= proc_reactants;
// } // END FOR: reactant
// // For inhibitors, we take all the processes first and then we iterate over the inhibitors
// for (unsigned int proc_id = 0; proc_id < numberOfProc; ++proc_id) {
// BDD proc_inhibitors = BDD_TRUE;
// for (const auto &inhibitor : cond.inhib) {
// if (processUsesEntity(proc_id, inhibitor)) {
// proc_inhibitors *= !encEntityCondition(proc_id, inhibitor);
// }
// }
// if (proc_inhibitors != BDD_TRUE) { // just an optimisation
// proc_inhibitors += !encProcEnabled(proc_id);
// inhibitors *= proc_inhibitors;
// }
// }
// enab += reactants * inhibitors;
// } // END FOR: cond
// if (opts->reorder_trans) {
// VERB_L2("Reordering");
// Cudd_ReduceHeap(cuddMgr->getManager(), CUDD_REORDER_SIFT, 10000);
// }
// return enab;
// }
BDD SymRS::encEntitySameSuccessor(Process proc_id, Entity entity_id)
{
return BDD_IFF(encEntity(proc_id, entity_id), encEntitySucc(proc_id, entity_id));
@@ -763,7 +714,7 @@ void SymRS::encodeTransitions(void)
prod_conds.resize(numberOfProc);
for (auto proc_id = 0; proc_id < numberOfProc; ++proc_id) {
for (unsigned int proc_id = 0; proc_id < numberOfProc; ++proc_id) {
prod_conds[proc_id] = getProductionConditions(proc_id);
}

View File

@@ -15,7 +15,6 @@
#include "types.hh"
#include "macro.hh"
#include "bdd_macro.hh"
// #include "rs.hh"
#include "options.hh"
#include "memtime.hh"
@@ -240,16 +239,11 @@ class SymRS
vector<BDDvec> *pv_proc_ctx;
BDDvec *pv_proc_ctx_E;
// TODO: remove
BDDvec *pv_act;
BDD *pv_act_E;
unsigned int totalEntities;
unsigned int numberOfProc; /*!< The number of DRS processes */
unsigned int totalStateVars;
unsigned int totalRctSysStateVars; /*!< Total number of different entities produced by reactions */
unsigned int totalCtxEntities; /*!< Total number of different (process,context) entities used */
unsigned int totalActions;
unsigned int totalCtxAutStateVars;
EntitiesForProc usedProducts; /*!< Entities used in products (per process) */
@@ -309,17 +303,12 @@ class SymRS
BDD encContext(const EntitiesForProc &proc_entities);
/**
* @brief Complements an encoding of a given state by negating all the variables that are not set to true
*
* @return Returns the encoded state
*/
BDD compState(const BDD &state) const;
BDD compContext(const BDD &context) const;
std::string decodedRctSysStateToStr(const BDD &state);
std::string decodedRctSysStateWithCtxAutToStr(const BDD &state);
void printDecodedRctSysStates(const BDD &states);
void printDecodedRctSysWithCtxAutStates(const BDD &states);
DecompReactions getProductionConditions(Process proc_id);

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,321 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ReactICS GUI Help</title>
</head>
<body>
<hr>
<center><a name="top"><h1>ReactICS - Distributed Reaction Systems Model Checker</h1></a></center>
<hr>
<p align="justify">
<b>ReactICS</b> is a toolkit that allows for verification of Reaction Systems.
The toolkit consists of two separate modules implementing:
<ul>
<li>Methods using binary decision diagrams (BDD)
for storing and manipulating the state space of the verified system.</li>
<li>Methods translating the verification problems into satisfiability modulo theories (SMT).</li>
</ul>
</p>
<p align="justify">
<b>ReactICS GUI</b> offers a graphical user interface allowing for editing the reaction system details
and model checking using BDD module.
</p>
<p align="justify">
More on <b>ReactICS</b> can be found at <a href="https://reactics.org">The Reactics Webpage</a>.
</p>
<br/>
<hr/>
<h2>Table of contents</h2>
<ul>
<li><a href="#reaction-systems">Reaction systems</a><br/></li>
<li><a href="#gui">Application functions</a><br/></li>
<li><a href="#rs-edit">Reaction system editor</a><br/></li>
<li><a href="#ctx-edit">Context automaton editor</a><br/></li>
<li><a href="#trs-view">Transition system viewer</a><br/></li>
<li><a href="#model-checking">Model checking</a><br/></li>
</ul>
<br/>
<hr/>
<a name="reaction-systems"><h2>Reaction Systems</h2></a>
<hr/>
<p align="justify">
<b>Reaction Systems</b> are a formalism inspired by the functioning of living cells.
They allow for specifying and analysing computational processes in which reactions operate on sets of molecules.
</p>
<p align="justify">
The behaviour of a reaction system is determined by the interactions of its reactions, which are based on
the mechanisms of facilitation and inhibition.
The formal treatment of reaction systems is qualitative and there is no direct representation of the number
of molecules involved in reactions.
</p>
<p align="justify">
A <b>Distributed Reaction System</b> is a computational model in which multiple autonomous processes (aka. agents)
interact locally through rule-based reactions.
Each agent operates independently (without any central controller—coordination),
processing inputs and producing outputs based on predefined reactions,
and their collective behavior leads to complex system dynamics.
</p>
<p align="justify">
More on reaction system can be found at <a href="https://www.reactionsystems.org">The Reaction System Webpage</a>
</p>
<center><a href="#top">Back to top</a></center>
<br/>
<hr/>
<a name="gui"><h2>Application functions</h2></a>
<hr/>
<p align="justify">
<b>ReactICS GUI</b> allows to:
<ul>
<li>Edit the reaction system structure (the number of processes/agents, reactions for each process/agent, etc.)</li>
<li>Edit the context automaton structure (adding/removing states and transitions,
edit context for active processes/agents, setting guards for transitions, etc.). </li>
<li>Preview of the state space represented as a transition system.</li>
<li>Verification of properties defined by formulas using rsCTLK semantics.</li>
<li>Save/load the reaction system structure to/from XML file.</li>
<li>Export/import the reaction system to/from RSSL file.</li>
<li>Export the reaction system structure and behaviour to ISPL file.</li>
</ul>
</p>
<center><a href="#top">Back to top</a></center>
<br/>
<hr/>
<a name="rs-edit"><h2>Distributed reaction system editor</h2></a>
<hr/>
<p align="justify">
The structure of distributed reaction system can be edited using the following buttons from the distributed reaction system control panel:
<center><img src="img/rs-ctrl-buttons.png"/></center>
<ul>
<li><b>New process</b> - Creates a new empty process.</li>
<li><b>Remove</b> - Removes selected processes.</li>
<li><b>Copy</b> - Makes copies of selected processes (together with all reactions).</li>
<li><b>Rename</b> - Renames a selected process. Note that process names should be unique.</li>
<li><b>Move up</b> - Moves selected process up the list of all processes.</li>
<li><b>Move down</b> - Moves selected process down the list of all processes.</li>
</ul>
</p>
<p align="justify">
The details of a single process can be edited using the following buttons in the process panel:
<center><img src="img/process-edit-button.png"/></center>
<ul>
<li><b>Add reaction</b> - Creates a new reaction. The details of the reaction should be specified in dialog shown below.</li>
<li><b>Edit reaction</b> - Allows to edit the details of a selected reaction using dialog shown below.</li>
<li><b>Remove reaction</b> - Removes a selected reaction.</li>
</ul>
</p>
<center><img src="img/reaction-details.png"/></center>
<p align="justify">
Verification of formulas against a system specification is done after selecting desired formulas
and clicking <b>Evaluate</b> button.
The result of the verification (<b>True</b>/<b>False</b>), as well as time and memory used are presented next to each verified formula.
</p>
<center><img src="img/model-checking.png"/></center>
<p align="justify">
Clicking the <b>Reset</b> button resets the status of the model checking.
Note that updating the reaction system specification (the list of processes, details of the reactions or the content automaton structure)
the results of model checking, if any, are reset automatically.
</p>
<center><a href="#top">Back to top</a></center>
<br/>
<hr/>
<a name="ctx-edit"><h2>Context automaton editor</h2></a>
<hr/>
<p align="justify">
To create or edit the context automaton structure a proper edit mode should be set using the <b>edit mode panel</b>.
</p>
<br/>
<center><img src="img/ctx-automaton-panel.png"/></center>
<p align="justify">
The type of the newly created object (state or edge) is set by checking the proper toggle button.
With no button checked, one can transform the net by moving states around, etc.
(see below for more details).
</p>
<br/>
<h3>States</h3>
<p align="justify">
A new state is created by left-clicking the edit area (the main part of the component).
As it is customary in automata theory, states are numbered separately starting from 1.
The types of states are distinguished by shape and colour:
the initial state is depicted as a square, all other states are depicted as circles.
Moreover, hovering the mouse above a state allows to see its full description containing both
its name and its (distinct) number.
</p>
<br/>
<center><img src="img/ctx-automaton-state.png"/></center>
<p align="justify">
The details of a state can be edited by right-clicking the existing
state and choosing the right option from the popup menu:
<ul>
<li><b>Set as initial</b> - Makes the selected state the initial state of the context automaton.</li>
<li><b>Set label</b> - Allows to set the custom label for the selected state. Note that state labels have to be unique.</li>
</ul>
</p>
<br/>
<center><img src="img/ctx-automaton-state.png"/></center>
<h3>Edges</h3>
<p align="justify">
A directed edge between two states is created by left-clicking both its endpoints in correct order.
Each edge may contain several transitions, each of them defined by a <i>context</i> (additional entities
provided for active processes/agents) and a <i>guard</i> (a condition required by the transition to execute).
The list of transitions may be edited by right-clicking the existing
edge and choosing the <b>Nondeterministic transitions</b> popup menu.
</p>
<center><img src="img/ctx-automaton-transition-edit.png"/></center>
<p align="justify">
Hovering the mouse above an edge allows to see the full list of transitions
including context and guards.
</p>
<center><img src="img/ctx-automaton-edge-details.png"/></center>
<br/>
<h3>Removing context automaton elements</h3>
<p align="justify">
Switching the toggle button <b>Delete</b> on allows removing context automaton elements.
Each left-clicked element is removed from the automaton grapn.
Moreover, the entire context automaton graph may be deleted by clicking the <b>Clear</b> button.
</p>
<br/>
<h3>Transforming the context automaton graph</h3>
<p align="justify">
Any state of the automaton may be picked and dragged around the edit area to obtain the desired graph shape.
It is also possible to select multiple states and move them together at the same time.
After <b>CTRL + left-click</b> on a particular state the entire automaton graph is shifted to be centered
on the clicked state.
Checking the <b>Lock relative nodes positions</b> checkbox locks the relative positions of the states.
In that case, dragging a single state moves the entire automaton graph.
Moreover, using mouse scroll the automaton graph view can be zoomed in and out.
</p>
<center><a href="#top">Back to top</a></center>
<br/>
<hr/>
<a name="trs-view"><h2>Transition system viewer</h2></a>
<hr/>
<p align="justify">
The component offers the visualisation of the transition system representing the state space of the reaction systems.
The initial state is depicted as a square, all other states are depicted as circles.
There is a directed edge connecting the state S<sub>i</sub> to the state S<sub>j</sub>
if S<sub>f</sub> is reachable from S<sub>i</sub> by a single computation step of the reaction system.
</p>
<p align="justify">
The component has two separate instances represented by two separate tabs in the application window.
The first visualises the complete state space of the reaction system,
where each state is represented by sets of entities possessed by each agent and the current context automaton state.
The second visualises the compressed state space, where context automaton states are ignored
(states are represented only by the sets of entities possessed by each agent).
</p>
<p align="justify">
Computation is done by pressing <b>Update transition system</b> button.
The reaction system structure should be loaded from the file or edited manually for the computation to be possible.
</p>
<p align="justify">
Note that no matter in which component the <b>Update transition system</b> button
is pressed, the transition system structure will be updated in both.
</p>
<p align="justify">
Hovering the mouse above a state allows to see its full description: entities possessed by each process/agent
and the context automaton state (not present in the case of the compressed graph).
</p>
<center><img src="img/ctx-automaton-edge-details.png"/></center>
<br/>
<h3>Transforming the transition system graph</h3>
<p align="justify">
Any state of the transition system may be picked and dragged around the edit area to obtain the desired graph shape.
It is also possible to select multiple states and move them together at the same time.
After <b>CTRL + left-click</b> on a particular state the entire transition system graph is shifted to be centered
on the clicked state.
Checking the <b>Lock relative nodes positions</b> checkbox locks the relative positions of the states.
In that case, dragging a single state moves the entire transition system graph.
Moreover, using mouse scroll the transition system graph view can be zoomed in and out.
</p>
<center><a href="#top">Back to top</a></center>
<br/>
<hr/>
<a name="model-checking"><h2>Model checking</h2></a>
<hr/>
<p align="justify">
Model checking is handled by the component at the bottom of the application window.
The properties of the analysed system are expressed as formulas following <b>rsCTLK</b> syntax.
</p>
<p align="justify">
The list of formulas may be modified using the following buttons:
<ul>
<li><b>Add formula</b> - Creates an empty formula. The details of the formula should be specified in dialog shown below.</li>
<li><b>Edit formula</b> - Allows to edit the details of a selected formula using dialog shown below.</li>
<li><b>Remove formulas</b> - Removes selected formulas.</li>
</ul>
</p>
<center><img src="img/formula-details.png"/></center>
<p align="justify">
Verification of formulas against a system specification is done after selecting desired formulas
and clicking <b>Evaluate</b> button.
The result of the verification (<b>True</b>/<b>False</b>), as well as time and memory used are presented next to each verified formula.
</p>
<center><img src="img/model-checking.png"/></center>
<p align="justify">
Clicking the <b>Reset</b> button resets the status of the model checking.
Note that updating the reaction system specification (the list of processes, details of the reactions or the content automaton structure)
the results of model checking, if any, are reset automatically.
</p>
<center><a href="#top">Back to top</a></center>
<br/>
<br/>
</body>
</html>

View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: pl.umk.mat.martinp.reactics.ReacticsGUI

View File

@@ -0,0 +1,693 @@
package pl.umk.mat.martinp.reactics;
import edu.uci.ics.jung.algorithms.layout.FRLayout;
import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor;
import edu.uci.ics.jung.algorithms.layout.Layout;
import edu.uci.ics.jung.algorithms.layout.StaticLayout;
import edu.uci.ics.jung.algorithms.layout.util.Relaxer;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.util.Context;
import edu.uci.ics.jung.graph.util.Pair;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.EdgeShape;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.picking.PickedState;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import org.apache.commons.collections15.Transformer;
import org.w3c.dom.Document;
import javax.swing.*;
import javax.swing.border.EtchedBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.io.PrintWriter;
import java.util.*;
public class ContextAutomatonEditor extends JPanel implements RSObserver {
private enum EditorState {STATE, EDGE, DELETE, CLEAR, NONE}
private static final long serialVersionUID = 1L;
private ReactionSystem rs;
//---------------------------------------------------------------
// Visual configuration settings
//---------------------------------------------------------------
private static final Color pickedNodeColor = Color.yellow;
//private static final Color pickedEdgeColor = Color.red;
private static final Color pickedEdgeColor = Color.black;
private static final Color edgeColor = Color.black;
private static final Color emptyEdgeColor = Color.lightGray;
private static final Font nodeLabelFont = new Font("Helvetica", Font.BOLD, 20);
private static final Font edgeLabelFont = new Font("Helvetica", Font.BOLD, 15);
private static final Font toolTipFont = new Font("Helvetica", Font.PLAIN, 14);
private static final float[] dash = {10.0f, 10.0f};
private static final Stroke basicEdgeStroke = new BasicStroke(3.0f,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
private static final Stroke emptyEdgeStroke = new BasicStroke(3.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f, dash, 0.f);
private static final Stroke basicEdgeArrow = new BasicStroke(3.0f);
private static final Stroke emptyEdgeArrow = new BasicStroke(3.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10.0f, dash, 10.0f);
private static Dimension initialEditorSize;
private VisualizationViewer<CAState, CAEdge> graphViewer;
private Layout<CAState, CAEdge> gLayout;
DefaultModalGraphMouse graphMouse;
private ContextAutomatonGraph graph;
// Context menus for transitions, places and edges
private JPopupMenu stateContextMenu;
private JPopupMenu edgeContextMenu;
private TransitionEditor transitionEditor = null;
private EditorState edtState;
private Vector<EditorModeButton> modeButtons;
private CAState lastPickedNode = null;
public ContextAutomatonEditor(Dimension size) {
this.setLayout(new BorderLayout());
initialEditorSize = size;
edtState = EditorState.NONE;
graph = new ContextAutomatonGraph();
createGraphEditor();
createModeButtonsPanel();
createContextMenus();
rs = ReactionSystem.getInstance();
}
public boolean isModified() { return graph.isModified(); }
public void clearModificationStatus() { graph.clearModificationStatus(); }
public String toRSSLString() {
return graph.toRSSLString();
}
public void exportToXML(PrintWriter output) {
updateNodesLocations();
graph.exportToXML(output);
}
public void loadFromXML(Document input) throws ContextAutomatonStructureError {
clear();
graph.loadFromXML(input);
}
public void recalculateCoordinates() {
Layout<CAState, CAEdge> autoLayout = new FRLayout<CAState, CAEdge>(graph, graphViewer.getSize());
autoLayout.initialize();
for (CAState state : graph.getVertices()) {
Point2D pos = autoLayout.transform(state);
state.updateLocation(pos);
}
}
public void clear() {
graph.clear();
for (EditorModeButton emb : modeButtons)
emb.setSelected(false);
graphViewer.repaint();
}
public void lockNodesPositions(boolean lock) {
if (lock)
graphMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);
else
graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
}
public Set<String> getReactantsSet() { return graph.getReactantsSet(); }
//--------------------------------------------------------------------------
// Creates visualization viewer for context automaton graph display/edition
//--------------------------------------------------------------------------
private void createGraphEditor() {
gLayout = new StaticLayout<CAState, CAEdge>(graph,
new Transformer<CAState, Point2D>() {
public Point2D transform(CAState node) {
return node.getLocation();
}
});
graphViewer = new VisualizationViewer<CAState, CAEdge>(gLayout, initialEditorSize) {
public JToolTip createToolTip() {
JToolTip tooltip = super.createToolTip();
tooltip.setFont(toolTipFont);
return tooltip;
}
};
// Nodes labels
graphViewer.getRenderContext().setVertexLabelTransformer(
new ToStringLabeller<CAState>());
graphViewer.getRenderer().getVertexLabelRenderer()
.setPosition(Renderer.VertexLabel.Position.CNTR);
graphViewer.getRenderContext().setVertexFontTransformer(
new Transformer<CAState,Font>() {
public Font transform(CAState v) {
return nodeLabelFont;
}
});
// Nodes colour, background, etc.
graphViewer.getRenderContext().setVertexIconTransformer(new Transformer<CAState,Icon>() {
public Icon transform(final CAState v) {
Color nodeColor = null;
if(graphViewer.getPickedVertexState().isPicked(v))
nodeColor = pickedNodeColor;
else
nodeColor = v.getFillColor();
return (v.isInitial() ? new SquareIcon(nodeColor, v.getWidth()) : new CircleIcon(nodeColor, v.getWidth()));
}});
// Edge color, shape and weight
graphViewer.getRenderContext().setEdgeDrawPaintTransformer(new Transformer<CAEdge, Paint>() {
public Paint transform(CAEdge e) {
return edgeColor;
}
});
graphViewer.getRenderContext().setEdgeStrokeTransformer(new Transformer<CAEdge, Stroke>() {
public Stroke transform(CAEdge e) {
return basicEdgeStroke;
}
});
graphViewer.getRenderContext().setEdgeArrowStrokeTransformer(new Transformer<CAEdge, Stroke>() {
public Stroke transform(CAEdge e) {
return basicEdgeArrow;
}
});
graphViewer.getRenderContext().setArrowFillPaintTransformer(new Transformer<CAEdge, Paint>() {
public Paint transform(CAEdge caEdge) {
if (caEdge.hasTransition())
return edgeColor;
else
return emptyEdgeColor;
}
});
graphViewer.getRenderContext().setEdgeShapeTransformer(new ConditionalEdgeShape<>(1.5f));
// Edge labels
graphViewer.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<CAEdge>());
graphViewer.getRenderContext().getEdgeLabelRenderer().setRotateEdgeLabels(true);
graphViewer.getRenderContext().setLabelOffset(20);
graphViewer.getRenderContext().setEdgeFontTransformer(new Transformer<CAEdge, Font>() {
public Font transform(CAEdge CAEdge) {
return edgeLabelFont;
}
});
// For interactive graph editing
graphMouse = new DefaultModalGraphMouse();
graphViewer.setGraphMouse(graphMouse);
graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
graphViewer.setVertexToolTipTransformer(new Transformer<CAState, String>() {
public String transform(CAState caState) {
return caState.getTooltipText();
}
});
graphViewer.setEdgeToolTipTransformer(new Transformer<CAEdge, String>() {
public String transform(CAEdge caEdge) {
return caEdge.getTooltipText();
}
});
graphViewer.setBackground(Color.white);
graphViewer.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
graphViewer.addMouseListener(new EditorMouseListener());
add(graphViewer,BorderLayout.CENTER);
}
//---------------------------------------------------------------
// Create panel with buttons alowing editing mode choice
//---------------------------------------------------------------
private void createModeButtonsPanel() {
modeButtons = new Vector<EditorModeButton>();
modeButtons.add(new EditorModeButton("STATE",new CircleIcon(CAState.baseFillColor, 15), EditorState.STATE, 0));
modeButtons.add(new EditorModeButton("EDGE", EditorState.EDGE, 1));
modeButtons.add(new EditorModeButton("DELETE", EditorState.DELETE, 2));
modeButtons.add(new EditorModeButton("CLEAR", EditorState.CLEAR, 3));
ModeButtonsListener mbListener = new ModeButtonsListener();
for(int i=0;i<modeButtons.size();++i)
modeButtons.elementAt(i).addActionListener(mbListener);
JPanel btnPanel = new JPanel();
btnPanel.setLayout(new FlowLayout());
for(int i=0;i<modeButtons.size();++i)
btnPanel.add(modeButtons.elementAt(i));
JCheckBox posLockCBox = new JCheckBox("Lock relative nodes positions");
posLockCBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
lockNodesPositions(posLockCBox.isSelected());
}
});
btnPanel.add(posLockCBox);
add(btnPanel,BorderLayout.NORTH);
}
//---------------------------------------------------------------
// Create context menus for transitions, places and edges
//---------------------------------------------------------------
private void createContextMenus() {
stateContextMenu = new JPopupMenu();
JMenuItem stateInitialItem = new JMenuItem("Set as initial");
stateInitialItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PickedState<CAState> pickedVertexState = graphViewer.getPickedVertexState();
Set<CAState> pickedNodes = pickedVertexState.getPicked();
Iterator<CAState> it = pickedNodes.iterator();
if(!it.hasNext()) {
return;
}
CAState editedNode = it.next();
pickedVertexState.clear();
graph.setInitialState(editedNode);
}
});
JMenuItem setLabelItem = new JMenuItem("Set label");
setLabelItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PickedState<CAState> pickedVertexState = graphViewer.getPickedVertexState();
Set<CAState> pickedNodes = pickedVertexState.getPicked();
Iterator<CAState> it = pickedNodes.iterator();
if(!it.hasNext()) {
return;
}
CAState state = it.next();
pickedVertexState.clear();
showStateLabelEditDialog(state);
}
});
stateContextMenu.add(stateInitialItem);
stateContextMenu.add(setLabelItem);
stateContextMenu.setVisible(false);
edgeContextMenu = new JPopupMenu();
JMenuItem edgeLabelEditItem = new JMenuItem("Nondeterministic transitions");
edgeLabelEditItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
PickedState<CAEdge> pickedEdgeState = graphViewer.getPickedEdgeState();
Set<CAEdge> pickedEdges = pickedEdgeState.getPicked();
Iterator<CAEdge> it = pickedEdges.iterator();
if(!it.hasNext()) {
return;
}
CAEdge editedEdge = it.next();
pickedEdgeState.clear();
showEdgeLabelEditDialog(editedEdge);
}
});
edgeContextMenu.add(edgeLabelEditItem);
edgeContextMenu.setVisible(false);
transitionEditor = new TransitionEditor();
}
private void showStateLabelEditDialog(CAState state) {
String idRegex = "[a-zA-Z][a-zA-Z_0-9:-]*";
boolean idOk = false;
do {
String newLabel = JOptionPane.showInputDialog(this, "State label", state.getLabel());
if (newLabel == null)
return;
newLabel = newLabel.trim();
if (!newLabel.matches(idRegex)) {
JOptionPane.showMessageDialog(this,
"<html>State label should start with a letter and may contain only:<br/>" +
"letters, numbers, colons (:), underscores (_) and hyphens (-)</html>",
"Error", JOptionPane.ERROR_MESSAGE);
}
else {
idOk = true;
state.setLabel(newLabel);
}
}
while (!idOk);
graph.markAsModified();
this.repaint();
}
//---------------------------------------------------------------
// Creates a simple dialog window for editing edge labels
//---------------------------------------------------------------
private void showEdgeLabelEditDialog(CAEdge edge) {
Pair<CAState> endPoints = graph.getEndpoints(edge);
transitionEditor.showTransitionEditDialog(this, edge.getTransitions(), endPoints.getFirst().getLabel(), endPoints.getSecond().getLabel());
graph.markAsModified();
graphViewer.repaint();
rs.notifyObservers();
}
/** Updates coordinates stored in each graph node (eg. after interactive graph modification).
* Called before each storing net structure to the file. */
private void updateNodesLocations() {
Collection<CAState> nodes = graph.getVertices();
for(CAState n : nodes) {
n.updateLocation(gLayout.transform(n));
}
}
/** For better vertex placement */
private void relax() {
Layout<CAState, CAEdge> layout = graphViewer.getGraphLayout();
layout.initialize();
layout.setSize(graphViewer.getSize());
Relaxer relaxer = graphViewer.getModel().getRelaxer();
if (relaxer != null) {
relaxer.stop();
relaxer.prerelax();
relaxer.relax();
}
}
public void onRSUpdate() {
repaint();
}
//---------------------------------------------------------------------------------------------
static class EditorModeButton extends JToggleButton {
private EditorState mode;
int seqNum;
public EditorModeButton(String label, EditorState mode) {
super(label);
this.mode = mode;
seqNum = 0;
}
public EditorModeButton(String label, EditorState mode, int seqNum) {
super(label);
this.mode = mode;
this.seqNum = seqNum;
}
public EditorModeButton(String label, Icon icon, EditorState mode, int seqNum) {
super(label, icon);
this.mode = mode;
this.seqNum = seqNum;
}
public EditorState getMode() {
return mode;
}
public int getSeqNum() {
return seqNum;
}
}
//---------------------------------------------------------------------------------------------
class ModeButtonsListener implements ActionListener {
public void actionPerformed(ActionEvent changeEvent) {
EditorModeButton emb = (EditorModeButton) changeEvent.getSource();
if(emb.isSelected()) {
int num = emb.getSeqNum();
for(int i=0;i<modeButtons.size();++i)
if(i != num || emb.mode == EditorState.CLEAR)
modeButtons.elementAt(i).setSelected(false);
edtState = emb.getMode();
}
else {
edtState = EditorState.NONE;
}
if (edtState == EditorState.CLEAR) {
graph.clear();
repaint();
edtState = EditorState.NONE;
}
}
};
//---------------------------------------------------------------------------------------------
// Mouse event handler. To allow interactive net editing
//---------------------------------------------------------------------------------------------
class EditorMouseListener extends MouseAdapter {
public void mouseClicked(MouseEvent me) {
int btnClicked = me.getButton();
if(btnClicked == MouseEvent.BUTTON1)
leftButtonClicked(me);
else if(btnClicked == MouseEvent.BUTTON3)
rightButtonClicked(me);
}
private void leftButtonClicked(MouseEvent me) {
Point clickPt = me.getPoint();
GraphElementAccessor<CAState, CAEdge> pickSupport = null;
Layout<CAState, CAEdge> layout = null;
CAState node = null;
CAEdge edge = null;
switch(edtState) {
case STATE:
try {
// Transform screen coordinates to layout coordinates.
// Necessary for possible automaton structure viewer scaling.
Point2D nodeLocation = graphViewer.getRenderContext().getMultiLayerTransformer().inverseTransform(clickPt);
graph.addState(new CAState(nodeLocation));
} catch (ContextAutomatonStructureError e) {
JOptionPane.showMessageDialog(null,
e.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
break;
case EDGE:
PickedState<CAState> pickedVertexState = graphViewer.getPickedVertexState();
pickSupport = graphViewer.getPickSupport();
layout = graphViewer.getGraphLayout();
node = pickSupport.getVertex(layout, clickPt.getX(), clickPt.getY());
if (node != null) {
if (lastPickedNode == null) {
lastPickedNode = node;
} else {
graph.addEdge(lastPickedNode, node);
lastPickedNode = null;
pickedVertexState.pick(node,false);
}
} else {
lastPickedNode = null;
}
break;
case DELETE:
pickSupport = graphViewer.getPickSupport();
layout = graphViewer.getGraphLayout();
node = pickSupport.getVertex(layout, clickPt.getX(), clickPt.getY());
edge = pickSupport.getEdge(layout, clickPt.getX(), clickPt.getY());
if (node != null) {
Collection<CAEdge> edges = graph.getIncidentEdges(node);
for (CAEdge e : edges)
rs.removeCAEdge(e);
graph.removeState(node);
}
else if (edge != null) {
graph.removeEdge(edge);
rs.removeCAEdge(edge);
}
break;
case NONE:
default:
break;
}
me.consume();
}
private void rightButtonClicked(MouseEvent me) {
GraphElementAccessor<CAState, CAEdge> pickSupport = graphViewer.getPickSupport();
Layout<CAState, CAEdge> layout = graphViewer.getGraphLayout();
CAState node = pickSupport.getVertex(layout, me.getX(), me.getY());
CAEdge edge = pickSupport.getEdge(layout, me.getX(), me.getY());
if (node != null) {
PickedState<CAState> pickedVertexState = graphViewer.getPickedVertexState();
pickedVertexState.clear();
pickedVertexState.pick(node,true);
stateContextMenu.show(graphViewer, me.getX(), me.getY());
}
else if (edge != null) {
PickedState<CAEdge> pickedEdgeState = graphViewer.getPickedEdgeState();
pickedEdgeState.clear();
pickedEdgeState.pick(edge, true);
edgeContextMenu.show(graphViewer, me.getX(), me.getY());
}
me.consume();
}
};
//---------------------------------------------------------------------------------------------
// For drawing the initial state
//---------------------------------------------------------------------------------------------
static class SquareIcon implements Icon {
private Color fillColor;
private int width;
public SquareIcon(Color fColor, int width) {
fillColor = fColor;
this.width = width;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(fillColor);
g.fillRect(x, y, width, width);
g.setColor(Color.black);
g.drawRect(x, y, width, width);
}
public int getIconWidth() {
return width;
}
public int getIconHeight() {
return width;
}
}
//---------------------------------------------------------------------------------------------
// For drawing all non-initial states
//---------------------------------------------------------------------------------------------
static class CircleIcon implements Icon {
private Color fillColor;
private int radius;
public CircleIcon(Color fColor, int radius) {
fillColor = fColor;
this.radius = radius;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(fillColor);
g.fillOval(x, y, radius, radius);
g.setColor(Color.black);
g.drawOval(x, y, radius, radius);
}
public int getIconWidth() {
return radius;
}
public int getIconHeight() {
return radius;
}
}
}
class ConditionalEdgeShape<V, E> implements Transformer<Context<Graph<V, E>, E>, Shape> {
private final EdgeShape.Loop<V, E> loopShape;
private final Transformer<Context<Graph<V, E>, E>, Shape> defaultShape;
private final float loopScale;
public ConditionalEdgeShape(float loopScale) {
this.loopShape = new EdgeShape.Loop<>();
this.defaultShape = new EdgeShape.QuadCurve<>(); // or Line<>
this.loopScale = loopScale;
}
public Shape transform(Context<Graph<V, E>, E> context) {
Graph<V, E> graph = context.graph;
E edge = context.element;
V src = graph.getSource(edge);
V dst = graph.getDest(edge);
if (src.equals(dst)) {
// Scale the self-loop
Shape baseLoop = loopShape.transform(context);
Rectangle bounds = baseLoop.getBounds();
double centerX = bounds.getCenterX();
double centerY = bounds.getCenterY();
AffineTransform at = new AffineTransform();
at.translate(centerX, centerY);
at.scale(loopScale, loopScale);
at.translate(-centerX, -centerY);
return at.createTransformedShape(baseLoop);
} else {
return defaultShape.transform(context);
}
}
}

View File

@@ -0,0 +1,438 @@
package pl.umk.mat.martinp.reactics;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.util.Pair;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.awt.*;
import java.awt.geom.Point2D;
import java.io.PrintWriter;
import java.util.*;
class ContextAutomatonGraph extends DirectedSparseGraph<CAState, CAEdge> {
private static final long serialVersionUID = 1L;
HashMap<Integer, CAState> states = new HashMap<>();
private CAState initialState = null;
boolean modified = false;
public ContextAutomatonGraph() {
super();
}
public boolean isModified() { return modified; }
public void markAsModified() { modified = true; }
public void clearModificationStatus() { modified = false; }
String toRSSLString() {
StringBuilder rsslString = new StringBuilder("context-automaton {\n");
rsslString.append(" states { ");
Collection<CAState> allStates = states.values();
Iterator<CAState> it = allStates.iterator();
if (it.hasNext()) {
rsslString.append(it.next().getLabel());
}
while (it.hasNext()) {
rsslString.append(", ").append(it.next().getLabel());
}
rsslString.append(" };\n");
rsslString.append(" init-state { ").append(initialState != null ? initialState.getLabel() : "").append(" };\n");
rsslString.append(" transitions {\n");
for (CAEdge edge : this.getEdges()) {
for (Transition tr : edge.getTransitions()) {
rsslString.append(" { ").append(tr.context).append(" }: ");
rsslString.append(this.getSource(edge).label).append(" -> ").append(this.getDest(edge).label);
String guard = tr.guard;
if (guard.length() > 0) {
rsslString.append(" : ").append(guard);
}
rsslString.append(";\n");
}
}
rsslString.append(" };\n");
rsslString.append("};\n");
return rsslString.toString();
}
public void exportToXML(PrintWriter output) {
output.println(" <context-automaton>");
for (CAState state : states.values()) {
Point2D pos = state.getLocation();
output.print(" <state");
output.print(" id=\"" + state.getId() + "\"");
output.print(" name=\"" + state.getLabel() + "\"");
output.print(" x=\"" + pos.getX() + "\"");
output.print(" y=\"" + pos.getY() + "\"");
if (state.isInitial())
output.print(" initial=\"true\"");
output.println("/>");
}
for (CAEdge edge : edges.keySet()) {
Pair<CAState> endPts = this.getEndpoints(edge);
output.print(" <edge");
output.print(" from=\"" + endPts.getFirst().getLabel() + "\"");
output.print(" to=\"" + endPts.getSecond().getLabel() + "\"");
output.println(">");
for (Transition tr : edge.getTransitions()) {
output.print(" <transition");
output.print(" context=\"" + tr.context + "\"");
output.print(" guard=\"" + tr.guard + "\"");
output.println("/>");
}
output.println(" </edge>");
}
output.println(" </context-automaton>");
}
/**
* Reads the context automaton structure from the XML file.
*
* @param input An XML file containing a valid description of a context automaton.
* @throws ContextAutomatonStructureError In the case of <b>inputFile</b> structure error, eg. \
* more than one context-automaton section, more than one \
* initial state, repeating state identifiers, \
* edge between non-existing nodes, etc.
*/
public void loadFromXML(Document input) throws ContextAutomatonStructureError {
NodeList caSections = input.getElementsByTagName("context-automaton");
if (caSections.getLength() == 0 || caSections.getLength() > 1) {
throw new ContextAutomatonStructureError("An XML file should contain a single context automaton description.");
}
//--------------------------------------------------------------------------------------------------------------
// Retrieve the states
//--------------------------------------------------------------------------------------------------------------
HashMap<String, CAState> states = new HashMap<String, CAState>();
NodeList stateList = input.getElementsByTagName("state");
boolean hasInitialState = false;
for (int idx = 0; idx < stateList.getLength(); ++idx) {
Node stateNode = stateList.item(idx);
if (stateNode.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
Element stateElement = (Element) stateNode;
int id = Integer.parseInt(stateElement.getAttribute("id"));
double x = Double.parseDouble(stateElement.getAttribute("x"));
double y = Double.parseDouble(stateElement.getAttribute("y"));
String name = stateElement.getAttribute("name");
String initial = stateElement.getAttribute("initial");
if (states.containsKey(name)) {
throw new ContextAutomatonStructureError("State name <" + name + "> already used.");
}
CAState newState = new CAState(id, name, new Point2D.Double(x, y));
this.addState(newState);
states.put(name, newState);
if (initial.equals("true")) {
if (hasInitialState)
throw new ContextAutomatonStructureError("There should not be more than one initial state.");
hasInitialState = true;
this.setInitialState(newState);
}
}
//--------------------------------------------------------------------------------------------------------------
// Retrieve the edges
//--------------------------------------------------------------------------------------------------------------
NodeList edgeList = input.getElementsByTagName("edge");
for (int idx = 0; idx < edgeList.getLength(); ++idx) {
Node edgeNode = edgeList.item(idx);
if (edgeNode.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
Element edgeElement = (Element) edgeNode;
String from = edgeElement.getAttribute("from");
String to = edgeElement.getAttribute("to");
// Retrieve all child nodes describing nondeterministic transitions related to this edge
NodeList childNodeList = edgeNode.getChildNodes();
Vector<Transition> transitionList = new Vector<Transition>();
for (int cIdx=0; cIdx < childNodeList.getLength(); ++ cIdx) {
Node childNode = childNodeList.item(cIdx);
if (childNode.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
Element transElement = (Element) childNode;
transitionList.add(new Transition(transElement.getAttribute("context"), transElement.getAttribute("guard")));
}
CAState stateFrom = states.get(from);
CAState stateTo = states.get(to);
if (stateFrom == null || stateTo == null)
throw new ContextAutomatonStructureError("An edge may be created only between existing nodes.");
this.addEdge(stateFrom, stateTo, transitionList);
}
}
public Set<String> getReactantsSet() {
Set<String> reactants = new HashSet<String>();
for (CAEdge edge : getEdges()) {
for (Transition trans : edge.getTransitions()) {
int start = trans.context.indexOf("{");
int end = trans.context.indexOf("}");
if (start != -1 && end != -1 && start < end) {
reactants.addAll(Arrays.asList(trans.context.substring(start + 1, end).split("\\s*,\\s*")));
}
}
}
return reactants;
}
public void setInitialState(CAState state) {
if (initialState != null)
initialState.setInitial(false);
state.setInitial(true);
initialState = state;
modified = true;
}
public CAState getInitialState() {
return initialState;
}
/**
* Clears the entire automaton structure structure
*/
public void clear() {
for (CAState st : states.values())
removeVertex(st);
states.clear();
CAState.resetIdCounter();
modified = true;
}
public boolean addEdge(CAState from, CAState to) {
modified = true;
return this.addEdge(new CAEdge(), from, to);
}
public void addEdge(CAState from, CAState to, Collection<Transition> transitionList) {
CAEdge edge = this.findEdge(from, to);
if (edge == null) {
CAEdge caEdge = ReactionSystem.getInstance().createCAEdge();
caEdge.addTransitions(transitionList);
this.addEdge(caEdge, from, to);
}
else
edge.addTransitions(transitionList);
modified = true;
}
public void addState(CAState state) throws ContextAutomatonStructureError {
int stateId = state.getId();
if (states.get(stateId) != null)
throw new ContextAutomatonStructureError("State id " + stateId + " already in use.");
states.put(stateId, state);
this.addVertex(state);
modified = true;
}
public boolean removeState(CAState state) {
if (states.get(state.getId()) != null) {
states.remove(state.getId());
}
modified = true;
// Remove the state with all connected edges
return this.removeVertex(state);
}
}
//-------------------------------------------------------------------------------------------------
// Single node of the context automaton graph
//-------------------------------------------------------------------------------------------------
class CAState {
public final static Color baseFillColor = Color.lightGray;
public final static Color selectedFillColor = Color.lightGray;
public final static Color initStateFillColor = new Color(102, 178, 255);
private static final int nodeWidth = 30;
private static final int nodeHeight = 30;
protected static int nextId = 1;
/** Unique auto incremented identifier of the node */
protected int id;
/** User defined label of the node displayed as a tool tip and used in RSSL and XML files */
protected String label;
protected Point2D location;
private boolean isInitial = false;
/** A state created from the description stored in a file. */
public CAState(int id, String label, Point2D location) {
this.id = id;
this.label = label;
this.location = location;
// To avoid duplicate node identifiers
if (id >= nextId)
nextId = id + 1;
}
/** A state created by clicking in graphical component. */
public CAState(Point2D location) {
this.id = nextId;
this.label = "q" + id;
this.location = location;
++nextId;
}
public Point2D getLocation() { return location; }
public void updateLocation(Point2D location) { this.location = location; }
public boolean isInitial() { return isInitial; }
public void setInitial(boolean status) { isInitial = status; }
public int getWidth() { return nodeWidth; }
public int getHeight() { return nodeHeight; }
public String getLabel() { return label; }
public void setLabel(String newLabel) { label = newLabel; }
public int getId() { return id; }
static void resetIdCounter() { nextId = 1; }
public String toString() { return Integer.toString(id); }
public String getTooltipText() {
return "<html>"+
"<b>State</b> " + id + "<br/><hr>" + getLabel() + //"<hr>"+
"</html>";
}
Color getFillColor() {
return isInitial ? initStateFillColor : baseFillColor;
}
}
//-------------------------------------------------------------------------------------------------
// Single edge of the context automaton graph.
// Each edge can represent a number of single transitions between the same pair of automaton states.
//-------------------------------------------------------------------------------------------------
class CAEdge {
protected static int nextId = 0;
protected int id;
// The list of all nondeterministic transitions represented by this edge
private Vector<Transition> transitions = new Vector<Transition>();
public boolean hasTransition() { return transitions.size() > 0; }
public CAEdge() {
this.id = nextId++;
}
// public CAEdge(Collection<Transition> transitionList) {
// this.transitions.addAll(transitionList);
// }
Vector<Transition> getTransitions() {
return transitions;
}
public int getId() {
return id;
}
public String toString() {
// Update this if you need any label displayed together with graph edge
return "";
}
public String getTooltipText() {
StringBuilder tooTip = new StringBuilder("<html><hr/><center><b>Context <font color=\"red\">:</font> Guard</b></center><hr/>");
for (Transition tr : transitions) {
tooTip.append(tr.context).append(" <b><font color=\"red\">:</font></b> ").append(tr.guard).append("<br/><hr/>");
}
tooTip.append("</html>");
return tooTip.toString();
}
public void addTransitions(Collection<Transition> transitionList) {
transitions.addAll(transitionList);
}
}
//-------------------------------------------------------------------------------------------------
// Single transition. To be included in a multiedge.
//-------------------------------------------------------------------------------------------------
class Transition {
String context;
String guard;
public Transition(String ctx, String grd) {
context = ctx;
guard = grd;
}
}
class ContextAutomatonStructureError extends FileStructureError {
public ContextAutomatonStructureError(String message) {
super(message);
}
}

View File

@@ -0,0 +1,13 @@
package pl.umk.mat.martinp.reactics;
import javax.swing.*;
import java.awt.*;
public class CumulatedReactionsViewer extends JPanel {
public CumulatedReactionsViewer() {
this.setLayout(new BorderLayout());
this.add(new JLabel("Cumulate Reactions Viewer", SwingConstants.CENTER), BorderLayout.CENTER);
}
}

View File

@@ -0,0 +1,410 @@
package pl.umk.mat.martinp.reactics;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;
import java.awt.*;
import java.io.*;
import java.util.Collection;
import java.util.Vector;
public class FormulaEditor extends JPanel implements RSObserver {
private FormulaTableModel ftModel;
private JTable formTable;
private ReactionSystem rs;
private Vector<Formula> formulaList;
boolean modified = false;
static final Color TableHeaderBackgroundColor = Color.gray;
static final Color TableHeaderFontColor = Color.white;
static final Color BaseFormulaBackgroundColor = Color.white;
static final Color TrueFormulaBackgroundColor = new Color(138, 242, 183);
static final Color FalseFormulaBackgroundColor = new Color(240, 141, 141);
static final Color InvalidFormulaBackgroundColor = new Color(124, 124, 124);
static final Border emptyBorder = BorderFactory.createEmptyBorder(1, 1, 1, 1);
static final Border selectedBorder = BorderFactory.createLineBorder(Color.RED, 2);
public FormulaEditor(ReactionSystem rs) {
this.rs = rs;
formulaList = rs.formulas;
// Create the table for displaying formulas. Prevent default selection modes.
ftModel = new FormulaTableModel();
formTable = new JTable(ftModel, new FormulaColumnModel());
formTable.setCellSelectionEnabled(false);
formTable.setRowSelectionAllowed(true);
Font headerFont = formTable.getTableHeader().getFont();
Font cellFont = formTable.getFont();
JTableHeader formHeader = formTable.getTableHeader();
formTable.setFont(new Font("Monospaced", Font.PLAIN, cellFont.getSize() + 2));
formHeader.setFont(new Font(headerFont.getFamily(), Font.BOLD, headerFont.getSize() + 2));
formHeader.setBackground(TableHeaderBackgroundColor);
formHeader.setForeground(TableHeaderFontColor);
formHeader.setReorderingAllowed(false);
formHeader.setResizingAllowed(true);
formHeader.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
FormulaTableCellRenderer renderer = new FormulaTableCellRenderer();
formTable.setDefaultRenderer(Object.class, renderer);
formTable.createDefaultColumnsFromModel();
setLayout(new BorderLayout());
add(new JScrollPane(formTable), BorderLayout.CENTER);
}
public boolean isModified() { return modified; }
public void clearModificationStatus() { modified = false; }
public String toRSSLString() {
StringBuilder rsslString = new StringBuilder();
for (Formula f: formulaList)
rsslString.append(f.toRSSLString()).append("\n");
return rsslString.toString();
}
public void exportToXML(PrintWriter output) {
output.println(" <formulas>");
for (Formula f : formulaList)
output.println(" " + f.toXMLString());
output.println(" </formulas>");
}
public void loadFromXML(Document input) {
formulaList.clear();
NodeList formulaTags = input.getElementsByTagName("formula");
for (int idx = 0; idx < formulaTags.getLength(); ++idx) {
Node formulaNode = formulaTags.item(idx);
if (formulaNode.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
Element formulaElement = (Element) formulaNode;
String label = formulaElement.getAttribute("label");
String formula = formulaElement.getTextContent();
formulaList.add(new Formula(label, formula));
}
ftModel.fireTableDataChanged();
}
private boolean showFormulaEditDialog(JFrame parent, Formula ff) {
final int Select = 0;
final int Approve = 1;
JTextField labelInput = new JTextField(30);
JTextField formulaInput = new JTextField(30);
String labelStr = "";
String formulaStr = "";
labelStr = ff.label;
formulaStr = ff.formula;
labelInput.setToolTipText("<html>A unique label of the formula</html>");
formulaInput.setToolTipText("<html>Formula to be evaluated</html>");
JPanel myPanel = new JPanel(new GridBagLayout());
GridBagConstraints cs = new GridBagConstraints();
cs.insets = new Insets(5, 5, 5, 5);
cs.anchor = GridBagConstraints.WEST;
cs.gridx = 0;
cs.gridy = 0;
myPanel.add(new JLabel("Label"), cs);
cs.gridx = 1;
cs.gridy = 0;
myPanel.add(labelInput, cs);
cs.gridx = 0;
cs.gridy = 1;
myPanel.add(new JLabel("Formula"), cs);
cs.gridx = 1;
cs.gridy = 1;
myPanel.add(formulaInput, cs);
int opStatus = Select;
do {
labelInput.setText(labelStr);
formulaInput.setText(formulaStr);
int result = JOptionPane.showConfirmDialog(parent, myPanel,
"Formula details", JOptionPane.OK_CANCEL_OPTION);
if (result != JOptionPane.OK_OPTION) {
return false;
}
labelStr = labelInput.getText();
formulaStr = formulaInput.getText();
ff.label = labelStr;
ff.formula = formulaStr;
opStatus = Approve;
}
while(opStatus == Select);
return true;
}
public void addFormula(JFrame parent) {
Formula ff = new Formula();
if (showFormulaEditDialog(parent, ff)) {
formulaList.add(ff);
modified = true;
ftModel.fireTableDataChanged();
}
}
// If more than one formula is selected throw an exception only the first can be edited
public void editFormula(JFrame parent) {
int[] selected = formTable.getSelectedRows();
if (selected.length != 1) {
JOptionPane.showMessageDialog(parent, "Select a single formula to edit.", "Select formula", JOptionPane.WARNING_MESSAGE);
return;
}
Formula fEdt = formulaList.get(formTable.convertRowIndexToModel(selected[0]));
if (fEdt == null)
return;
showFormulaEditDialog(parent, fEdt);
fEdt.status = Formula.FormulaStatus.None;
modified = true;
ftModel.fireTableDataChanged();
}
public void removeFormulas() {
int[] viewRows = formTable.getSelectedRows();
// Remove formulas starting from the last to avoid indexes updates
for (int vIdx = viewRows.length - 1; vIdx>=0; --vIdx) {
int mr = formTable.convertRowIndexToModel(viewRows[vIdx]);
formulaList.remove(mr);
}
modified = true;
ftModel.fireTableDataChanged();
}
public Collection<Formula> getSelectedFormulas() {
Vector<Formula> selected = new Vector<Formula>();
int[] viewRows = formTable.getSelectedRows();
for (int vr : viewRows) {
int mr = formTable.convertRowIndexToModel(vr);
selected.add(formulaList.get(mr));
}
return selected;
}
// Needed to repaint JTable. Called after content modification by an external object.
public void refreshStatus() {
ftModel.fireTableDataChanged();
}
public void resetFormulasStatus() {
for (Formula ff : formulaList) {
ff.status = Formula.FormulaStatus.None;
ff.mcTime = ff.totalTime = ff.memory = "-";
}
ftModel.fireTableDataChanged();
}
public void onRSUpdate() {
resetFormulasStatus();
refreshStatus();
}
static class FormulaColumnModel extends DefaultTableColumnModel {
int colno = 0;
public void addColumn(TableColumn tc) {
switch (colno) {
case 0 -> {
tc.setMinWidth(60);
tc.setMaxWidth(Integer.MAX_VALUE / 10);
tc.setPreferredWidth(100);
}
case 1 -> {
tc.setMinWidth(100);
tc.setMaxWidth(Integer.MAX_VALUE);
}
case 2, 3, 4, 5 -> {
tc.setMinWidth(50);
tc.setPreferredWidth(50);
tc.setMaxWidth(Integer.MAX_VALUE / 10);
}
}
super.addColumn(tc);
++colno;
}
}
class FormulaTableModel extends AbstractTableModel implements TableModelListener {
private final String[] columnNames = {"Label", "Formula", "Status", "MC Time (s)", "Total Time (s)", "Memory (MB)"};
public String getColumnName(int colIdx) {
return columnNames[colIdx];
}
public int getRowCount() {
return formulaList.size();
}
public int getColumnCount() {
return columnNames.length;
}
public Object getValueAt(int row, int column) {
Formula ff = formulaList.get(row);
return switch (column) {
case 0 -> ff.label;
case 1 -> ff.formula;
case 2 -> ff.status;
case 3 -> ff.mcTime;
case 4 -> ff.totalTime;
case 5 -> ff.memory;
default -> "";
};
}
public void setValueAt(Object value, int row, int column) {
// fireTableDataChanged();
}
public boolean isCellEditable(int rowIndex, int columnIndex) { return false; }
public Class getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
public void tableChanged(TableModelEvent tableModelEvent) { }
}
// To properly display the content of the table containing formulas
class FormulaTableCellRenderer extends JLabel implements TableCellRenderer {
public FormulaTableCellRenderer() {
// Allows background to be visible
setOpaque(true);
}
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
String statusStr = "";
Formula ff = formulaList.get(row);
setForeground(Color.black);
if (isSelected) {
setBorder(selectedBorder);
}
else {
setBorder(emptyBorder);
}
// Set cell background and formula evaluation status
if (column == 2) {
switch (ff.status) {
case None -> {
statusStr = "?";
setBackground(BaseFormulaBackgroundColor);
}
case True -> {
statusStr = "True";
setBackground(TrueFormulaBackgroundColor);
}
case False -> {
statusStr = "False";
setBackground(FalseFormulaBackgroundColor);
}
case Invalid -> {
statusStr = "Invalid";
setBackground(InvalidFormulaBackgroundColor);
}
}
setText(statusStr);
}
else {
setText((String) value);
setBackground(BaseFormulaBackgroundColor);
}
if (column > 2) {
setHorizontalAlignment(SwingConstants.RIGHT);
} else {
setHorizontalAlignment(SwingConstants.LEFT);
}
return this;
}
}
}
class Formula {
public enum FormulaStatus {None, True, False, Invalid};
String label;
String formula;
FormulaStatus status;
String mcTime;
String totalTime;
String memory;
public Formula() {
this("", "");
}
public Formula(String label, String formula) {
this.label = label;
this.formula = formula;
this.status = FormulaStatus.None;
this.mcTime = this.totalTime = this.memory = "-";
}
public String toRSSLString() {
return "rsctlk-property { " + label + " : " + formula + " };";
}
public String toXMLString() {
return "<formula label=\"" + label +"\">" +
formula.replaceAll("<", "&lt;").replaceAll(">", "&gt;") +
"</formula>";
}
}

View File

@@ -0,0 +1,125 @@
package pl.umk.mat.martinp.reactics;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
public class HelpWindow extends JFrame {
private static final long serialVersionUID = 327019113533268901L;
private static final String startDocument = "index.html";
private static final String docPath = "/help/";
private static HelpWindow instance = null;
private static JTextPane helpPane = new JTextPane();;
public static synchronized HelpWindow getInstance() {
if (instance == null)
instance = new HelpWindow();
return instance;
}
private HelpWindow() {
super("ReactICS GUI Help");
getContentPane().setLayout(new BorderLayout());
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BorderLayout());
EtchedBorder panelBorder = new EtchedBorder(EtchedBorder.LOWERED);
mainPanel.setBorder(panelBorder);
helpPane.setEditable(false);
helpPane.addHyperlinkListener(new HyperlinkListener() {
public void hyperlinkUpdate(HyperlinkEvent hle) {
if (hle.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
String target = hle.getDescription();
if (target.startsWith("#")) {
helpPane.scrollToReference(target.substring(1));
}
}
}
});
try {
URL helpUrl = this.getClass().getResource(docPath + startDocument);
helpPane.setPage(helpUrl);
helpPane.revalidate();
helpPane.repaint();
}
catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
JOptionPane.showMessageDialog(null, "Can not load help content",
"Help", JOptionPane.ERROR_MESSAGE);
}
JScrollPane helpScroller = new JScrollPane();
JViewport helpVp = new JViewport();
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
helpVp.setPreferredSize(new Dimension(screenSize.width/2, screenSize.height-200));
helpVp.add(helpPane);
helpScroller.setViewport(helpVp);
mainPanel.add(helpScroller, BorderLayout.CENTER);
getContentPane().add(mainPanel, BorderLayout.CENTER);
pack();
}
public void show(Component parent) {
setLocationRelativeTo(parent);
setVisible(true);
}
}
class AboutWindow extends JFrame {
private static AboutWindow instance = null;
public static synchronized AboutWindow getInstance() {
if (instance == null)
instance = new AboutWindow();
return instance;
}
private AboutWindow() {
super("About ...");
getContentPane().setLayout(new BorderLayout());
JPanel infoPanel = new JPanel();
infoPanel.add(new JLabel("<html><h1>" + ReacticsGUI.ApplicationName + "</h1>"
+ "<h2>version " + ReacticsGUI.ApplicationVersion + " (" + ReacticsGUI.ApplicationReleaseDate + ")</h2>"
+ "<h3>Model Checker for Reaction Systems</h3>"
+ "<h3>ReactICS Research Team (CC BY 4.0)</h3>"
+ "<h3><a href=\"https://reactics.org\">https://reactics.org</a></h3></html>"));
getContentPane().add(infoPanel, BorderLayout.CENTER);
JButton closeButton = new JButton("Close");
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
setVisible(false);
}
});
JPanel ctrlPanel = new JPanel();
ctrlPanel.add(closeButton);
ctrlPanel.setAlignmentX(SwingConstants.RIGHT);
getContentPane().add(ctrlPanel, BorderLayout.SOUTH);
setSize(new Dimension(400, 250));
setResizable(false);
this.setAlwaysOnTop(true);
this.setUndecorated(true);
}
public void show(Component parent) {
setLocationRelativeTo(parent);
setVisible(true);
}
}

View File

@@ -0,0 +1,427 @@
package pl.umk.mat.martinp.reactics;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.util.*;
//-------------------------------------------------------------------------------------------------
// Graphical component for editing a single process (list of reactions)
//-------------------------------------------------------------------------------------------------
class ProcessEditor extends JPanel {
private JTable reactionList;
private RSTableModel reactionsModel;
private RSProcess rsProcess;
private boolean modified = false;
private JCheckBox selectBox;
private TitledBorder outBorder;
private ReactionSystem rs;
private final Color borderColor = new Color(24, 104, 92);;
private final Color selectedBorderColor = new Color(150, 10, 10);
private static final int borderThickness = 4;
public ProcessEditor(RSProcess rsProc) {
rsProcess = rsProc;
init();
}
public RSProcess getProcess() { return rsProcess; }
public boolean isSelected() {
return selectBox.isSelected();
}
public boolean isModified() { return modified; }
public void clearModificationStatus() { modified = false; }
public String getLabel() {
return rsProcess.label;
}
private void init() {
// Create border for the component
outBorder = BorderFactory.createTitledBorder(rsProcess.label);
Font font = outBorder.getTitleFont();
Font newFont = new Font (font.getFamily(), Font.BOLD, font.getSize() + 2);
outBorder.setTitleFont(new Font (font.getFamily(), Font.BOLD, font.getSize() + 2));
outBorder.setTitleColor(borderColor);
outBorder.setBorder(new LineBorder(borderColor, borderThickness, true));
setBorder(outBorder);
// Create reactions list component
reactionsModel = new RSTableModel();
reactionList = new JTable(reactionsModel);
Font cellFont = reactionList.getFont();
Font headerFont = reactionList.getTableHeader().getFont();
reactionList.setFont(new Font("Monospaced", 0, cellFont.getSize() + 2));
reactionList.getTableHeader().setFont(new Font(headerFont.getFamily(), Font.BOLD, headerFont.getSize() + 2));
reactionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
JPanel buttonPanel = new JPanel();
JButton addButton = new JButton("Add reaction");
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { addReaction(); }
});
buttonPanel.add(addButton);
JButton edtButton = new JButton("Edit reaction");
edtButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
editReaction();
}
});
buttonPanel.add(edtButton);
JButton rmButton = new JButton("Remove reaction");
rmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
removeReactions();
}
});
buttonPanel.add(rmButton);
selectBox = new JCheckBox("Select");
selectBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
toggleSelection();
}
});
buttonPanel.add(selectBox);
add(buttonPanel);
add(new JScrollPane(reactionList));
setPreferredSize(new Dimension(-1, 200));
rs = ReactionSystem.getInstance();
}
private boolean showReactionEditDialog(JComponent parent, Reaction rr) {
final int Select = 0;
final int Approve = 1;
JTextField reactantsInput = new JTextField(30);
JTextField inhibitorsInput = new JTextField(30);
JTextField productsInput = new JTextField(30);
String reactantsStr = "";
String inhibitorsStr = "";
String productsStr = "";
Iterator<?> it = rr.reactants.iterator();
StringBuilder dataStr = new StringBuilder();
while (it.hasNext())
dataStr.append(it.next()).append(" ");
reactantsStr = dataStr.toString();
it = rr.inhibitors.iterator();
dataStr.setLength(0);
while (it.hasNext())
dataStr.append(it.next()).append(" ");
inhibitorsStr = dataStr.toString();
it = rr.products.iterator();
dataStr.setLength(0);
while (it.hasNext())
dataStr.append(it.next()).append(" ");
productsStr = dataStr.toString();
reactantsInput.setToolTipText("<html>Space separated list of reactants</html>");
inhibitorsInput.setToolTipText("<html>Space separated list of inhibitors</html>");
productsInput.setToolTipText("<html>Space separated list of products</html>");
JPanel myPanel = new JPanel(new GridBagLayout());
GridBagConstraints cs = new GridBagConstraints();
cs.insets = new Insets(5, 5, 5, 5);
cs.anchor = GridBagConstraints.WEST;
cs.gridx = 0;
cs.gridy = 0;
myPanel.add(new JLabel("Reactants"), cs);
cs.gridx = 1;
cs.gridy = 0;
myPanel.add(reactantsInput, cs);
cs.gridx = 0;
cs.gridy = 1;
myPanel.add(new JLabel("Inhibitors"), cs);
cs.gridx = 1;
cs.gridy = 1;
myPanel.add(inhibitorsInput, cs);
cs.gridx = 0;
cs.gridy = 2;
myPanel.add(new JLabel("Products"), cs);
cs.gridx = 1;
cs.gridy = 2;
myPanel.add(productsInput, cs);
int opStatus = Select;
do {
reactantsInput.setText(reactantsStr);
inhibitorsInput.setText(inhibitorsStr);
productsInput.setText(productsStr);
int result = JOptionPane.showConfirmDialog(parent, myPanel,
"Reaction details", JOptionPane.OK_CANCEL_OPTION);
if (result != JOptionPane.OK_OPTION) {
return false;
}
reactantsStr = reactantsInput.getText();
inhibitorsStr = inhibitorsInput.getText();
productsStr = productsInput.getText();
HashSet<String> reactantsSet = new HashSet<String>(Arrays.asList(reactantsStr.trim().split("\\s+")));
HashSet<String> inhibitorsSet = new HashSet<String>(Arrays.asList(inhibitorsStr.trim().split("\\s+")));
HashSet<String> productsSet = new HashSet<String>(Arrays.asList(productsStr.trim().split("\\s+")));
// Verify that reactant and inhibitor sets have empty intersection
boolean intersection = false;
for (String entity : inhibitorsSet) {
if (reactantsSet.contains(entity)) {
intersection = true;
break;
}
}
if (intersection) {
JOptionPane.showMessageDialog(this, "Reactant and inhibitor sets have to be disjoint.", "Error", JOptionPane.ERROR_MESSAGE);
continue;
}
rr.reactants.clear();
rr.reactants.addAll(reactantsSet);
rr.inhibitors.clear();
rr.inhibitors.addAll(inhibitorsSet);
rr.products.clear();
rr.products.addAll(productsSet);
opStatus = Approve;
}
while(opStatus == Select);
return true;
}
public Set<String> getReactantsSet() {
HashSet<String> rset = new HashSet<String>();
for (Reaction rr : rsProcess.reactions)
rset.addAll(rr.getReactantsSet());
return rset;
}
public void exportToXML(PrintWriter output) {
output.println(" <process name=\"" + rsProcess.label + "\">");
for (Reaction rr : rsProcess.reactions)
rr.exportToXML(output);
output.println(" </process>");
}
public String toRSSLString() {
StringBuilder rsslString = new StringBuilder(" " + rsProcess.label + " {\n");
for (Reaction rr : rsProcess.reactions) {
rsslString.append(rr.toRSSLString());
}
rsslString.append(" };\n");
return rsslString.toString();
}
void rename(String newLabel) {
rsProcess.label = newLabel;
outBorder.setTitle(rsProcess.label);
this.repaint();
}
// Add new reaction
public void addReaction(Reaction rr) {
rsProcess.reactions.add(rr);
reactionsModel.fireTableDataChanged();
}
private void addReaction() {
Reaction rr = new Reaction();
if (!showReactionEditDialog(this, rr))
return;
rsProcess.reactions.add(rr);
modified = true;
reactionsModel.fireTableDataChanged();
rs.notifyObservers();
}
// Edit details of an existing reaction
private void editReaction() {
int rIdx = reactionList.getSelectedRow();
if (rIdx == -1) {
JOptionPane.showMessageDialog(this, "Select the reaction to edit.", "Select reaction", JOptionPane.WARNING_MESSAGE);
return;
}
Reaction rr = new Reaction(rsProcess.reactions.get(rIdx));
reactionList.clearSelection();
if (!showReactionEditDialog(this, rr)) {
return;
}
rsProcess.reactions.setElementAt(rr, rIdx);
modified = true;
reactionsModel.fireTableDataChanged();
rs.notifyObservers();
}
// Remove an existing reaction
private void removeReactions() {
int rIdx = reactionList.getSelectedRow();
if (rIdx == -1) {
JOptionPane.showMessageDialog(this, "Select the reaction to be removed.", "Select reaction", JOptionPane.WARNING_MESSAGE);
return;
}
rsProcess.reactions.remove(rIdx);
reactionList.clearSelection();
reactionsModel.fireTableDataChanged();
modified = true;
this.repaint();
rs.notifyObservers();
}
private void toggleSelection() {
if (selectBox.isSelected()) {
outBorder.setTitleColor(selectedBorderColor);
outBorder.setBorder(new LineBorder(selectedBorderColor, borderThickness, true));
}
else {
outBorder.setTitleColor(borderColor);
outBorder.setBorder(new LineBorder(borderColor, borderThickness, true));
}
this.repaint();
}
class RSTableModel extends AbstractTableModel {
private String columnNames[] = {"Reactants", "Inhibitors", "Results"};
private Vector<String>[] data;
public String getColumnName(int colIdx) {
return columnNames[colIdx];
}
public int getRowCount() {
return rsProcess.reactions.size();
}
public int getColumnCount() {
return columnNames.length;
}
public Object getValueAt(int row, int column) {
Reaction rr = rsProcess.reactions.get(row);
return switch (column) {
case 0 -> rr.reactants;
case 1 -> rr.inhibitors;
case 2 -> rr.products;
default -> "";
};
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
}
}
//-------------------------------------------------------------------------------------------------
// Object representing a single reaction
//-------------------------------------------------------------------------------------------------
class Reaction {
LinkedList<String> reactants;
LinkedList<String> inhibitors;
LinkedList<String> products;
public Reaction() {
reactants = new LinkedList<String>();
inhibitors = new LinkedList<String>();
products = new LinkedList<String>();
}
public Reaction(Reaction rr) {
reactants = new LinkedList<String>(rr.reactants);
inhibitors = new LinkedList<String>(rr.inhibitors);
products = new LinkedList<String>(rr.products);
}
public Set<String> getReactantsSet() {
Set<String> rset = new HashSet<String>();
rset.addAll(reactants);
rset.addAll(inhibitors);
rset.addAll(products);
return rset;
}
public String toRSSLString() {
return " {" + "{" + reactants.toString().replace("[", "").replace("]", "") + "}, " +
"{" + inhibitors.toString().replace("[", "").replace("]", "") + "} -> " +
"{" + products.toString().replace("[", "").replace("]", "") + "}" +
"};\n";
}
public void exportToXML(PrintWriter output) {
output.println(" <reaction>");
for (String str : reactants)
output.println(" <reactant>" + str + "</reactant>");
for (String str : inhibitors)
output.println(" <inhibitor>" + str + "</inhibitor>");
for (String str : products)
output.println(" <product>" + str + "</product>");
output.println(" </reaction>");
}
}

View File

@@ -0,0 +1,49 @@
package pl.umk.mat.martinp.reactics;
import javax.swing.*;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.util.*;
import java.util.stream.Collectors;
public class ReactantSetPanel extends JPanel implements RSObserver {
private final int borderThickness = 2;
JTextArea textArea = new JTextArea();
public ReactantSetPanel() {
textArea.setEditable(false);
textArea.setLineWrap(true);
textArea.setWrapStyleWord(false);
Font textFont = textArea.getFont();
textArea.setFont(new Font(textFont.getFamily(), Font.BOLD, textFont.getSize()+2));
this.setPreferredSize(new Dimension(-1, 75));
this.setLayout(new BorderLayout());
this.add(new JScrollPane(textArea), BorderLayout.CENTER);
TitledBorder outBorder = BorderFactory.createTitledBorder("Reactants");
Font borderFont = outBorder.getTitleFont();
outBorder.setTitleFont(new Font (borderFont.getFamily(), Font.BOLD, borderFont.getSize()+2));
outBorder.setBorder(new LineBorder(Color.black, borderThickness, true));
setBorder(outBorder);
}
public void updateReactants(Set<String> reactantsSet) {
textArea.setText("");
// textArea.setText(Arrays.toString(reactantsSet.toArray()));
textArea.setText(Arrays.stream(reactantsSet.toArray()).map(String::valueOf).collect(Collectors.joining(" ")));
}
public void clear() {
textArea.setText("");
}
public void onRSUpdate() {
ReactionSystem rs = ReactionSystem.getInstance();
updateReactants(rs.getReactants());
}
}

View File

@@ -0,0 +1,791 @@
/** Main application window */
package pl.umk.mat.martinp.reactics;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.swing.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Collection;
import java.util.TreeSet;
public class ReacticsGUI extends JFrame {
public final static String ApplicationName = "ReactICS GUI";
public final static String ApplicationVersion = "0.1";
public final static String ApplicationReleaseDate = "2025";
private static final String defaultConfigFileName = "reactics.conf";
private JFrame window;
private JTabbedPane modulePane;
private ReactantSetPanel reactantSetPanel;
private ReactionSystemEditor reactionSystemEditor;
private ContextAutomatonEditor contextAutomatonEditor;
private TransitionSystemViewer transitionSystemViewer;
private TransitionSystemViewer compressedTransitionSystemViewer;
private FormulaEditor formulaEditor;
private FileSelector fileSelector;
private ReactionSystem reactionSystem;
private ReacticsRuntime reactics;
public ReacticsGUI() {
super(ApplicationName);
reactionSystem = ReactionSystem.getInstance();
try {
reactics = ReacticsRuntime.getInstance();
}
catch (ReacticsRuntimeException rre) {
JOptionPane.showMessageDialog(this,
rre.getMessage(),
"Reactics Runtime Error", JOptionPane.ERROR_MESSAGE);
}
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setSize(new Dimension(screenSize.width-200, screenSize.height-200));
createMenuBar();
createContentPane();
fileSelector = FileSelector.getInstance();
try {
reactics.loadConfig(defaultConfigFileName);
}
catch (ConfigReadingError cre) {
System.err.println("[ReactICS] Error reading configuration: " + cre.getMessage());
JOptionPane.showMessageDialog(this,
"Could not read configuration\n" + cre.getMessage(),
"Reactics Runtime Error", JOptionPane.ERROR_MESSAGE);
}
catch (InvalidRuntimeException ire) {
System.err.println("[ReactICS] ReactICS runtime cannot be executed" + ire.getMessage());
JOptionPane.showMessageDialog(this,
"Invalid ReactICS runtime patn\n" + ire.getMessage() +
"\nYou may proceed with editing reaction system structure," +
"however not model checking will be possible.",
"Reactics Runtime Error", JOptionPane.ERROR_MESSAGE);
}
window = this;
}
private void createMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = new JMenu("File");
menuBar.add(fileMenu);
JMenuItem xmlLoadItem = new JMenuItem("Load from XML file");
xmlLoadItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
loadFromXML();
}
});
fileMenu.add(xmlLoadItem);
JMenuItem xmlsaveItem = new JMenuItem("Save to XML file");
xmlsaveItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
saveAsXML();
}
});
fileMenu.add(xmlsaveItem);
JMenuItem rsslImportItem = new JMenuItem("Import from RSSL file");
rsslImportItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
importFromRSSL();
}
});
fileMenu.add(rsslImportItem);
JMenuItem rsslExportItem = new JMenuItem("Save to RSSL file");
rsslExportItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
exportToRSSLFile();
}
});
fileMenu.add(rsslExportItem);
JMenuItem isplExportItem = new JMenuItem("Export to ISPL file");
isplExportItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { exportToISPLFile(); }
});
fileMenu.add(isplExportItem);
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
System.exit(0);
}
});
fileMenu.addSeparator();
fileMenu.add(exitItem);
JMenu helpMenu = new JMenu("Help");
menuBar.add(helpMenu);
JMenuItem helpItem = new JMenuItem("Help");
helpItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { showHelpWindow(); }
});
helpMenu.add(helpItem);
JMenuItem aboutItem = new JMenuItem("About");
aboutItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { showAboutWindow(); }
});
helpMenu.add(aboutItem);
setJMenuBar(menuBar);
}
private void createContentPane() {
modulePane = new JTabbedPane();
modulePane.setTabPlacement(JTabbedPane.NORTH);
//-----------------------------------------------------------------------------------------
// Reaction System Editor
//-----------------------------------------------------------------------------------------
reactionSystemEditor = new ReactionSystemEditor();
modulePane.addTab("Reaction System", reactionSystemEditor);
reactionSystem.addObserver(reactionSystemEditor);
//-----------------------------------------------------------------------------------------
// Context Automaton Editor
//-----------------------------------------------------------------------------------------
contextAutomatonEditor = new ContextAutomatonEditor(getSize());
modulePane.addTab("Context Automaton", contextAutomatonEditor);
reactionSystem.addObserver(contextAutomatonEditor);
//-----------------------------------------------------------------------------------------
// Transition System Viewer
//-----------------------------------------------------------------------------------------
JPanel transitionSystemPanel = new JPanel(new BorderLayout());
transitionSystemViewer = new TransitionSystemViewer(getSize(), false);
transitionSystemPanel.add(transitionSystemViewer, BorderLayout.CENTER);
reactionSystem.addObserver(transitionSystemViewer);
JPanel tsCtrlPanel = new JPanel();
JButton tsUpdateBtn = new JButton("Update transition system");
tsUpdateBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { updateTransitionSystem(); }
});
tsCtrlPanel.add(tsUpdateBtn);
JCheckBox tsLockCBox = new JCheckBox("Lock relative nodes positions");
tsLockCBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
transitionSystemViewer.lockNodesPositions(tsLockCBox.isSelected());
}
});
tsCtrlPanel.add(tsLockCBox);
transitionSystemPanel.add(tsCtrlPanel, BorderLayout.NORTH);
modulePane.addTab("Transition System", transitionSystemPanel);
//-----------------------------------------------------------------------------------------
// Compressed Transition System Viewer
//-----------------------------------------------------------------------------------------
JPanel compressedTransitionSystemPanel = new JPanel(new BorderLayout());
compressedTransitionSystemViewer = new TransitionSystemViewer(getSize(), true);
compressedTransitionSystemPanel.add(compressedTransitionSystemViewer, BorderLayout.CENTER);
reactionSystem.addObserver(compressedTransitionSystemViewer);
JPanel ctsCtrlPanel = new JPanel();
JButton ctsUpdateBtn = new JButton("Update transition system");
ctsUpdateBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { updateTransitionSystem(); }
});
ctsCtrlPanel.add(ctsUpdateBtn);
JCheckBox ctsLockCBox = new JCheckBox("Lock relative nodes positions");
ctsLockCBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
compressedTransitionSystemViewer.lockNodesPositions(ctsLockCBox.isSelected());
}
});
ctsCtrlPanel.add(ctsLockCBox);
compressedTransitionSystemPanel.add(ctsCtrlPanel, BorderLayout.NORTH);
modulePane.addTab("Compressed Transition System", compressedTransitionSystemPanel);
//-----------------------------------------------------------------------------------------
// Formula Editor
//-----------------------------------------------------------------------------------------
JPanel formulaEditorPanel = new JPanel();
formulaEditorPanel.setLayout(new BorderLayout());
formulaEditor = new FormulaEditor(reactionSystem);
reactionSystem.addObserver(formulaEditor);
formulaEditorPanel.add(formulaEditor, BorderLayout.CENTER);
JPanel formulaCtrlPanel = new JPanel();
JButton addButton = new JButton("Add formula");
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { formulaEditor.addFormula(window); }
});
formulaCtrlPanel.add(addButton);
JButton edtButton = new JButton("Edit formula");
edtButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
formulaEditor.editFormula(window);
}
});
formulaCtrlPanel.add(edtButton);
JButton rmButton = new JButton("Remove formulas");
rmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
formulaEditor.removeFormulas();
}
});
formulaCtrlPanel.add(rmButton);
JButton evalButton = new JButton("Evaluate");
evalButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
evaluateFormulas();
}
});
formulaCtrlPanel.add(evalButton);
JButton resetButton = new JButton("Reset");
resetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
formulaEditor.resetFormulasStatus();
}
});
formulaCtrlPanel.add(resetButton);
formulaEditorPanel.add(formulaCtrlPanel, BorderLayout.NORTH);
//-----------------------------------------------------------------------------------------
// Split the main window into two parts. The upper one contains details of the reaction
// system. The bottom part contains the list of formulas for model checking.
//-----------------------------------------------------------------------------------------
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, modulePane, formulaEditorPanel);
splitPane.setResizeWeight(0.75);
// splitPane.setOneTouchExpandable(true);
splitPane.setDividerSize(8);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(splitPane, BorderLayout.CENTER);
//-----------------------------------------------------------------------------------------
// Update button + Reactant Set Viewer
//-----------------------------------------------------------------------------------------
JPanel topPanel = new JPanel();
topPanel.setLayout(new BorderLayout());
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
JButton updateButton = new JButton("<html><center>Update<br>Reaction System</center></html>");
updateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
updateReactionSystem();
}
});
buttonPanel.add(updateButton);
topPanel.add(buttonPanel, BorderLayout.WEST);
reactantSetPanel = new ReactantSetPanel();
reactionSystem.addObserver(reactantSetPanel);
topPanel.add(reactantSetPanel, BorderLayout.CENTER);
getContentPane().add(topPanel, BorderLayout.NORTH);
}
private boolean isModified() {
return reactionSystemEditor.isModified() || contextAutomatonEditor.isModified();
}
private void clearModificationStatus() {
reactionSystemEditor.clearModificationStatus();
contextAutomatonEditor.clearModificationStatus();
transitionSystemViewer.clearModificationStatus();
compressedTransitionSystemViewer.clearModificationStatus();
}
private void updateReactionSystem() {
System.out.println("[ReactICS] Update reaction system structure");
Path rsslFile = reactics.getRSSLFile();
try {
Files.writeString(rsslFile, "");
PrintWriter rsslStream = new PrintWriter(Files.newBufferedWriter(rsslFile));
printRSStructure(rsslStream);
rsslStream.close();
}
catch (IOException ie) {
System.err.println("[ReactICS] Could not read transition system structure: " + ie.getMessage());
JOptionPane.showMessageDialog(this,
"Could not read transition system structure\n" + ie.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
reactionSystem.notifyObservers();
updateReactantSet();
clearModificationStatus();
}
private void updateReactantSet() {
TreeSet<String> rset = new TreeSet<String>();
rset.addAll(reactionSystemEditor.getReactantsSet());
rset.addAll(contextAutomatonEditor.getReactantsSet());
rset.remove("");
reactantSetPanel.updateReactants(rset);
}
private void updateTransitionSystem() {
if (isModified()) {
updateReactionSystem();
}
else if (transitionSystemViewer.isComputed()) {
// Skip re-computing transition system structure
return;
}
try {
String tsStructure = reactics.getTransitionSystemStructure();
transitionSystemViewer.updateTransitionSystemStructure(tsStructure);
compressedTransitionSystemViewer.updateTransitionSystemStructure(tsStructure);
}
catch (IOException ioe) {
System.out.println("[ReactICS] I/O Error: " + ioe.getMessage());
JOptionPane.showMessageDialog(this,
"Could not write reaction system structure to a temporary file\n" + ioe.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
catch (ReacticsRuntimeException rre) {
System.out.println("[ReactICS] Runtime Error: " + rre.getMessage());
JOptionPane.showMessageDialog(this,
rre.getMessage(),
"Reactics Runtime Error", JOptionPane.ERROR_MESSAGE);
}
}
private void evaluateFormulas() {
Collection<Formula> formulas = formulaEditor.getSelectedFormulas();
if (isModified())
updateReactionSystem();
Path rsslFile = reactics.getRSSLFile();
long originalSize = -1;
try {
originalSize = Files.size(rsslFile);
}
catch (IOException ioe) {
System.err.println("[ReactICS] Error: " + ioe.getMessage());
JOptionPane.showMessageDialog(this, ioe.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
for (Formula ff : formulas) {
try {
System.out.println("[ReactICS] Evaluate formula: " + ff.label);
Files.writeString(rsslFile, ff.toRSSLString() + "\n", StandardCharsets.UTF_8, StandardOpenOption.APPEND);
ReacticsRuntime.EvalResult result = reactics.evaluateFormula(ff.label);
ff.status = result.result();
ff.mcTime = result.mcTime() + " s";
ff.totalTime = result.totalTime() + " s";
ff.memory = result.memory() + " MB";
formulaEditor.refreshStatus();
}
catch(IOException ioe) {
System.err.println("[ReactICS] Error: " + ioe.getMessage());
JOptionPane.showMessageDialog(this, ioe.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
catch(ReacticsRuntimeException rre) {
System.err.println("[ReactICS] Runtime error: " + rre.getMessage());
JOptionPane.showMessageDialog(this,
rre.getMessage(),
"Reactics Runtime Error", JOptionPane.ERROR_MESSAGE);
ff.status = Formula.FormulaStatus.Invalid;
}
finally {
try {
RandomAccessFile raf = new RandomAccessFile(rsslFile.toFile(), "rw");
raf.setLength(originalSize);
}
catch (IOException ioe) {
System.err.println("[ReactICS] Error: " + ioe.getMessage());
JOptionPane.showMessageDialog(this, ioe.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
}
}
}
private void saveAsXML() {
File outFile = fileSelector.selectOutputFile(this, new File(System.getProperty("user.dir")),
new FileNameExtensionFilter("Reaction System (XML)", "xml"));
if(outFile == null)
return;
System.out.println("[ReactICS] Save to XML file: " + outFile.getName());
try {
PrintWriter xmlOut = new PrintWriter(new FileWriter(outFile));
xmlOut.println("<xml version=\"1.0\">");
reactionSystemEditor.exportToXML(xmlOut);
contextAutomatonEditor.exportToXML(xmlOut);
formulaEditor.exportToXML(xmlOut);
xmlOut.println("</xml>");
xmlOut.flush();
xmlOut.close();
}
catch(IOException ioe) {
JOptionPane.showMessageDialog(this, ioe.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
}
private void loadFromXML() {
FileNameExtensionFilter fileTypeFilter = new FileNameExtensionFilter("Reaction System (XML)", "xml");
JFileChooser fc = new JFileChooser();
fc.addChoosableFileFilter(fileTypeFilter);
fc.setAcceptAllFileFilterUsed(true);
fc.setCurrentDirectory(new File(System.getProperty("user.dir")));
if(fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File xmlFile = fc.getSelectedFile();
loadFromXMLFile(xmlFile);
setTitle("ReactICS GUI : " + xmlFile.getName());
}
modulePane.setSelectedIndex(0);
clearModificationStatus();
}
private void loadFromXMLFile(File xmlFile) {
reactionSystemEditor.clear();
contextAutomatonEditor.clear();
reactantSetPanel.clear();
transitionSystemViewer.clear();
compressedTransitionSystemViewer.clear();
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
reactionSystemEditor.loadFromXML(doc);
contextAutomatonEditor.loadFromXML(doc);
formulaEditor.loadFromXML(doc);
updateReactionSystem();
}
catch(IOException ioe) {
System.err.println("[ReactICS] Error: " + ioe.getMessage());
JOptionPane.showMessageDialog(this, "Error reading file: " + xmlFile.getName() + "\n" + ioe.getMessage(),
"Input error", JOptionPane.ERROR_MESSAGE);
reactionSystemEditor.clear();
contextAutomatonEditor.clear();
reactantSetPanel.clear();
}
catch(ParserConfigurationException pce) {
System.err.println("[ReactICS] Parse Configuration Error: " + pce.getMessage());
JOptionPane.showMessageDialog(this, pce.getMessage(),
"Parse Configuration Error", JOptionPane.ERROR_MESSAGE);
reactionSystemEditor.clear();
contextAutomatonEditor.clear();
reactantSetPanel.clear();
}
catch(SAXException se) {
System.err.println("[ReactICS] SAXException: " + se.getMessage());
JOptionPane.showMessageDialog(this, se.getMessage(),
"Parse error", JOptionPane.ERROR_MESSAGE);
reactionSystemEditor.clear();
contextAutomatonEditor.clear();
reactantSetPanel.clear();
}
catch(FileStructureError err) {
System.err.println("[ReactICS]: File Structure Error: " + err.getMessage());
JOptionPane.showMessageDialog(this, err.getMessage(),
"XML file structure error", JOptionPane.ERROR_MESSAGE);
reactionSystemEditor.clear();
contextAutomatonEditor.clear();
reactantSetPanel.clear();
}
catch(Exception e) {
System.out.println("[ReactICS] Error: " + e.getMessage());
JOptionPane.showMessageDialog(this, "Unexpected error reading file: " + xmlFile.getName() +
" " + e.getMessage(),
"Input error", JOptionPane.ERROR_MESSAGE);
reactionSystemEditor.clear();
contextAutomatonEditor.clear();
reactantSetPanel.clear();
}
}
private void importFromRSSL() {
FileNameExtensionFilter fileTypeFilter = new FileNameExtensionFilter("Reaction System Specification Language (rs)", "rs");
JFileChooser fc = new JFileChooser();
fc.addChoosableFileFilter(fileTypeFilter);
fc.setAcceptAllFileFilterUsed(true);
fc.setCurrentDirectory(new File(System.getProperty("user.dir")));
if(fc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File rsslFile = fc.getSelectedFile();
try {
File xmlFile = reactics.convertToXMLFile(rsslFile);
loadFromXMLFile(xmlFile);
} catch (IOException e) {
System.err.println("IOException: " + e.getMessage());
e.printStackTrace();
} catch (ReacticsRuntimeException e) {
System.err.println("ReacticsRuntimeException: " + e.getMessage());
e.printStackTrace();
}
setTitle("ReactICS GUI : " + rsslFile.getName());
contextAutomatonEditor.recalculateCoordinates();
}
modulePane.setSelectedIndex(0);
clearModificationStatus();
}
private void exportToRSSLFile() {
File outFile = fileSelector.selectOutputFile(this, new File(System.getProperty("user.dir")),
new FileNameExtensionFilter("Reaction System Specification Language (RSSL)", "rs"));
if(outFile == null)
return;
System.out.println("[ReactICS] Export to RSSL file: " + outFile.getName());
try {
PrintWriter rsslOut = new PrintWriter(new FileWriter(outFile));
printRSStructure(rsslOut);
rsslOut.close();
}
catch(IOException ioe) {
System.err.println("[ReactICS] Error: " + ioe.getMessage());
JOptionPane.showMessageDialog(this, ioe.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
}
private void exportToISPLFile() {
updateReactionSystem();
if (!reactionSystem.isplTranslationAllowed()) {
JOptionPane.showMessageDialog(this,
"Context automaton contains guards for some transitions.\n" +
"Current version of ReactICS does not support translation to ISPL format in this case.\n",
"Translation is not possible", JOptionPane.INFORMATION_MESSAGE);
return;
}
File outFile = fileSelector.selectOutputFile(this, new File(System.getProperty("user.dir")),
new FileNameExtensionFilter("Interpreted System Programming Language (ISPL)", "ispl"));
if (outFile == null)
return;
System.out.println("[ReactICS] Export to ISPL file: " + outFile.getAbsolutePath());
try {
if (!outFile.exists() && !outFile.createNewFile()) {
System.err.println("[ReactICS] Error: The file "+ outFile.getName() + " could not be created.");
JOptionPane.showMessageDialog(this,
"The file " + outFile.getName() + " could not be created.",
"Error", JOptionPane.ERROR_MESSAGE);
return;
}
if (!outFile.canWrite()){
System.err.println("[ReactICS] Error: Cannot write to the file " + outFile.getName());
JOptionPane.showMessageDialog(this,
"Cannot write to the file " + outFile.getName(),
"Error", JOptionPane.ERROR_MESSAGE);
return;
}
reactics.exportToISPLFile(outFile);
}
catch(IOException ioe) {
System.err.println("[ReactICS] Error: " + ioe.getMessage());
JOptionPane.showMessageDialog(this, ioe.getMessage(),
"Error", JOptionPane.ERROR_MESSAGE);
}
catch(ReacticsRuntimeException rre) {
System.err.println("[ReactICS] Runtime error: " + rre.getMessage());
JOptionPane.showMessageDialog(this,
rre.getMessage(),
"ReactICS Runtime Error", JOptionPane.ERROR_MESSAGE);
}
}
private void printRSStructure(PrintWriter outStream) {
outStream.println("options { use-context-automaton; make-progressive; };\n");
outStream.println(reactionSystemEditor.toRSSLString());
outStream.println(contextAutomatonEditor.toRSSLString());
}
private void showAboutWindow() {
AboutWindow awin = AboutWindow.getInstance();
awin.show(this);
}
private void showHelpWindow() {
HelpWindow hwin = HelpWindow.getInstance();
hwin.show(this);
}
public static void main(String args[]) {
ReacticsGUI wnd = new ReacticsGUI();
wnd.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
wnd.setLocationRelativeTo(null);
wnd.setVisible(true);
}
}
//-------------------------------------------------------------------------------------------------
// Class responsible for selecting a file to load / save the reaction system structure
//-------------------------------------------------------------------------------------------------
class FileSelector {
private enum Status {SELECT, APPROVE, CANCEL}
private static FileSelector instance = null;
public static synchronized FileSelector getInstance() {
if (instance == null)
instance = new FileSelector();
return instance;
}
private FileSelector() { }
public File selecInputFile(Component parent, File rootDir, FileNameExtensionFilter filter) {
Status opStatus = Status.SELECT;
JFileChooser fc = new JFileChooser();
fc.addChoosableFileFilter(filter);
fc.setAcceptAllFileFilterUsed(true);
fc.setCurrentDirectory(rootDir);
File outFile = null;
do {
if (fc.showOpenDialog(parent) != JFileChooser.APPROVE_OPTION) {
opStatus = Status.CANCEL;
break;
}
outFile = fc.getSelectedFile();
opStatus = Status.APPROVE;
if(outFile.exists()) {
if (JOptionPane.showConfirmDialog(parent,
"The file " + outFile.getName() + " already exists.\n" +
"Do you wish to overwrite it?", "Warning",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.NO_OPTION) {
opStatus = Status.SELECT;
}
}
} while(opStatus == Status.SELECT);
if(opStatus != Status.APPROVE)
outFile = null;
return outFile;
}
public File selectOutputFile(Component parent, File rootDir, FileNameExtensionFilter filter) {
Status opStatus = Status.SELECT;
JFileChooser fc = new JFileChooser();
fc.addChoosableFileFilter(filter);
fc.setAcceptAllFileFilterUsed(true);
fc.setCurrentDirectory(rootDir);
File outFile = null;
do {
if (fc.showSaveDialog(parent) != JFileChooser.APPROVE_OPTION) {
opStatus = Status.CANCEL;
break;
}
outFile = fc.getSelectedFile();
opStatus = Status.APPROVE;
if(outFile.exists()) {
if (JOptionPane.showConfirmDialog(parent,
"The file " + outFile.getName() + " already exists.\n" +
"Do you wish to overwrite it?", "Warning",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.NO_OPTION) {
opStatus = Status.SELECT;
}
}
} while(opStatus == Status.SELECT);
if(opStatus != Status.APPROVE)
outFile = null;
return outFile;
}
}
/**
* General exception class for any error related to input XML file
*/
class FileStructureError extends Exception {
public FileStructureError(String message) {
super(message);
}
}

View File

@@ -0,0 +1,198 @@
package pl.umk.mat.martinp.reactics;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
public class ReacticsRuntime {
private static ReacticsRuntime instance = null;
private String rctPath = "./";
private String rctRuntime = "reactics";
private Path rsslFile;
public static synchronized ReacticsRuntime getInstance() throws ReacticsRuntimeException {
if (instance == null)
instance = new ReacticsRuntime();
return instance;
}
private ReacticsRuntime() throws ReacticsRuntimeException {
try {
rsslFile = Files.createTempFile("reaction_system_", ".rs");
rsslFile.toFile().deleteOnExit();
System.out.println("[ReactICS] Created temporary file: " + rsslFile.toAbsolutePath());
}
catch (IOException e) {
System.err.println("[ReactICS] Problem creating temporary file: + e.getMessage()");
throw new ReacticsRuntimeException("Problem creating temporary file:\n" + e.getMessage());
}
}
public Path getRSSLFile() {
return rsslFile;
}
public void loadConfig(String configFileName) throws ConfigReadingError, InvalidRuntimeException {
System.out.println("[ReactICS] Loading configuration from: " + configFileName);
try {
BufferedReader inputStream = new BufferedReader(new FileReader(configFileName));
String line;
while ((line = inputStream.readLine()) != null) {
if (line.startsWith("runtime")) {
line = line.replaceAll("\\s", "");
rctRuntime = line.substring(line.indexOf(":") + 1);
}
else if (line.startsWith("path")) {
line = line.replaceAll("\\s", "");
rctPath = line.substring(line.indexOf(":") + 1);
}
}
}
catch (IOException e) {
throw new ConfigReadingError(e.getMessage());
}
File rctRntFile = new File(rctPath + rctRuntime);
if (! (rctRntFile.exists() && rctRntFile.canExecute()) ) {
throw new InvalidRuntimeException(rctPath + rctRuntime + " cannot be executed");
}
System.out.println("[ReactICS] Using runtime: " + rctPath + rctRuntime);
}
public EvalResult evaluateFormula(String fLabel) throws IOException, ReacticsRuntimeException {
// Drop "-B" option if verification time should not be measured
Process proc = Runtime.getRuntime().exec(rctPath + rctRuntime + " -B -c " + fLabel + " " + rsslFile.toAbsolutePath(),
null, new File(rctPath));
BufferedReader formResultStream = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
Formula.FormulaStatus result = Formula.FormulaStatus.None;
String mcTime = "";
String totalTime = "";
String memory = "";
while ((line = formResultStream.readLine()) != null) {
if (line.contains("holds")) {
result = Formula.FormulaStatus.True;
}
else if (line.contains("not hold")) {
result = Formula.FormulaStatus.False;
}
else if (line.startsWith("STAT")) {
String[] tokens = line.split(";");
mcTime = tokens[2];
totalTime = tokens[5];
memory = tokens[4];
}
//TODO: Handle incorrect formulas
}
StringBuilder errMsg = new StringBuilder();
BufferedReader procErrStr = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
while ((line = procErrStr.readLine()) != null) {
errMsg.append(line).append("\n");
}
if (!errMsg.isEmpty())
throw new ReacticsRuntimeException(errMsg.toString());
return new EvalResult(result, mcTime, totalTime, memory);
}
/** Complete Transition System. Context automaton state included. */
public String getTransitionSystemStructure() throws IOException, ReacticsRuntimeException {
Process proc = Runtime.getRuntime().exec(rctPath + rctRuntime + " -t -X " + rsslFile.toAbsolutePath(),
null, new File(rctPath));
String line;
StringBuilder tsString = new StringBuilder();
BufferedReader procOutStr = new BufferedReader(new InputStreamReader(proc.getInputStream()));
while ((line = procOutStr.readLine()) != null) {
tsString.append(line).append("\n");
}
StringBuilder errMsg = new StringBuilder();
BufferedReader procErrStr = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
while ((line = procErrStr.readLine()) != null) {
errMsg.append(line).append("\n");
}
if (!errMsg.isEmpty())
throw new ReacticsRuntimeException(errMsg.toString());
return tsString.toString();
}
public void exportToISPLFile(File outFile) throws IOException, ReacticsRuntimeException {
Process proc = Runtime.getRuntime().exec(rctPath + rctRuntime + " -e " + rsslFile.toAbsolutePath() + " > " + outFile.getAbsolutePath(),
null, new File(rctPath));
String line;
BufferedReader procOutStr = new BufferedReader(new InputStreamReader(proc.getInputStream()));
PrintWriter isplOutStr = new PrintWriter(new FileWriter(outFile));
while ((line = procOutStr.readLine()) != null) {
isplOutStr.println(line);
}
isplOutStr.close();
StringBuilder errMsg = new StringBuilder();
BufferedReader procErrStr = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
while ((line = procErrStr.readLine()) != null) {
errMsg.append(line).append("\n");
}
if (!errMsg.isEmpty())
throw new ReacticsRuntimeException(errMsg.toString());
}
public File convertToXMLFile(File rsslInputFile) throws IOException, ReacticsRuntimeException {
File xmlFile = Files.createTempFile("_" + rsslInputFile.getName(), ".xml").toFile();
xmlFile.deleteOnExit();
ProcessBuilder procBuilder = new ProcessBuilder(rctPath + rctRuntime, "-y", rsslInputFile.getAbsolutePath());
procBuilder.redirectOutput(new File(xmlFile.getAbsolutePath()));
Process proc = procBuilder.start();
String line;
StringBuilder errMsg = new StringBuilder();
BufferedReader procErrStr = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
while ((line = procErrStr.readLine()) != null) {
errMsg.append(line).append("\n");
}
if (!errMsg.isEmpty())
throw new ReacticsRuntimeException(errMsg.toString());
return xmlFile;
}
record EvalResult(Formula.FormulaStatus result, String mcTime, String totalTime, String memory) {}
}
class ConfigReadingError extends Exception {
public ConfigReadingError(String message) {
super(message);
}
}
class InvalidRuntimeException extends Exception {
public InvalidRuntimeException(String description) {
super(description);
}
}
class ReacticsRuntimeException extends Exception {
public ReacticsRuntimeException(String description) {
super(description);
}
}

View File

@@ -0,0 +1,409 @@
/** A component for editing the reaction system details */
package pl.umk.mat.martinp.reactics;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.Vector;
//-------------------------------------------------------------------------------------------------
/** A graphical component allowing edition and display of a distributed reaction system.
* A distributed reaction system contains a number of processes.
* Each process contains a list of reactions.
*/
public class ReactionSystemEditor extends JPanel implements RSObserver {
ReactionSystem rs;
private Vector<ProcessEditor> procEditors = new Vector<ProcessEditor>();
private JPanel processPanel = new JPanel();
public ReactionSystemEditor() {
rs = ReactionSystem.getInstance();
processPanel.setLayout(new BoxLayout(processPanel, BoxLayout.Y_AXIS));
final Dimension buttonSize = new Dimension(150, 25);
JButton addButton = new JButton("New process");
addButton.setMaximumSize(buttonSize);
addButton.setPreferredSize(buttonSize);
addButton.setMaximumSize(buttonSize);
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
createProcess();
}
});
JButton rmButton = new JButton("Remove");
rmButton.setMaximumSize(buttonSize);
rmButton.setPreferredSize(buttonSize);
rmButton.setMaximumSize(buttonSize);
rmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
removeProcesses();
}
});
JButton copyButton = new JButton("Copy");
copyButton.setMaximumSize(buttonSize);
copyButton.setPreferredSize(buttonSize);
copyButton.setMaximumSize(buttonSize);
copyButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
copyProcesses();
}
});
JButton renameButton = new JButton("Rename");
renameButton.setMaximumSize(buttonSize);
renameButton.setPreferredSize(buttonSize);
renameButton.setMaximumSize(buttonSize);
renameButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
renameProcess();
}
});
JButton upButton = new JButton("Move up");
upButton.setMaximumSize(buttonSize);
upButton.setPreferredSize(buttonSize);
upButton.setMaximumSize(buttonSize);
upButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
moveSelectedUp();
}
});
JButton downButton = new JButton("Move down");
downButton.setMaximumSize(buttonSize);
downButton.setPreferredSize(buttonSize);
downButton.setMaximumSize(buttonSize);
downButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
moveSelectedDown();
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.Y_AXIS));
buttonPanel.add(addButton);
buttonPanel.add(rmButton);
buttonPanel.add(copyButton);
buttonPanel.add(renameButton);
buttonPanel.add(upButton);
buttonPanel.add(downButton);
this.setLayout(new BorderLayout());
this.add(new JScrollPane(processPanel), BorderLayout.CENTER);
this.add(buttonPanel, BorderLayout.WEST);
createProcess();
}
public boolean isModified() {
boolean procModified = false;
for (ProcessEditor pe : procEditors)
procModified |= pe.isModified();
return rs.modified | procModified;
}
public void clearModificationStatus() {
for (ProcessEditor pe : procEditors)
pe.clearModificationStatus();
rs.modified = false;
}
public Set<String> getReactantsSet() {
HashSet<String> rset = new HashSet<String>();
for (ProcessEditor pe : procEditors)
rset.addAll(pe.getReactantsSet());
return rset;
}
public void exportToXML(PrintWriter output) {
output.println(" <reaction-system>");
for (ProcessEditor process : procEditors)
process.exportToXML(output);
output.println(" </reaction-system>");
}
public void loadFromXML(Document input) throws ReactionSystemStructureError {
NodeList rsSections = input.getElementsByTagName("reaction-system");
if (rsSections.getLength() == 0 || rsSections.getLength() > 1) {
throw new ReactionSystemStructureError("An XML file should contain a single reaction system description.");
}
NodeList processList = rsSections.item(0).getChildNodes();
for (int idx=0; idx<processList.getLength(); ++idx) {
Node processNode = processList.item(idx);
if (processNode.getNodeType() != Node.ELEMENT_NODE)
continue;
String procName = processNode.getAttributes().getNamedItem("name").getNodeValue();
ProcessEditor processEditor = new ProcessEditor(rs.createProcess(procName));
//----------------------------------------------------------------------------------------------------------
// Reactions details
//----------------------------------------------------------------------------------------------------------
NodeList reactionList = processNode.getChildNodes();
for (int rIdx=0; rIdx<reactionList.getLength(); ++rIdx) {
Node reactionNode = reactionList.item(rIdx);
if (reactionNode.getNodeType() != Node.ELEMENT_NODE)
continue;
Reaction reaction = new Reaction();
NodeList substrateNodes = reactionNode.getChildNodes();
for (int sIdx=0; sIdx<substrateNodes.getLength(); ++sIdx) {
Node sNode = substrateNodes.item(sIdx);
if (sNode.getNodeType() != Node.ELEMENT_NODE)
continue;
String nodeName = sNode.getNodeName();
String nodeContent = sNode.getTextContent();
switch (nodeName) {
case "reactant":
reaction.reactants.add(nodeContent);
break;
case "inhibitor":
reaction.inhibitors.add(nodeContent);
break;
case "product":
reaction.products.add(nodeContent);
break;
default:
throw new ReactionSystemStructureError("Unexpected node type: " + nodeName);
}
}
processEditor.addReaction(reaction);
}
procEditors.add(processEditor);
processPanel.add(processEditor);
}
revalidate();
}
public String toRSSLString() {
StringBuilder rsString = new StringBuilder("reactions {\n");
for (ProcessEditor pe : procEditors) {
rsString.append(pe.toRSSLString());
}
rsString.append("};\n");
return rsString.toString();
}
public void clear() {
processPanel.removeAll();
procEditors.clear();
rs.clearProcesses();
}
private void createProcess() {
ProcessEditor newProcEdt = new ProcessEditor(rs.createProcess());
procEditors.add(newProcEdt);
processPanel.add(newProcEdt);
rs.modified = true;
revalidate();
}
private void createProcess(String label) {
ProcessEditor newProcEdt = new ProcessEditor(rs.createProcess(label));
procEditors.add(newProcEdt);
processPanel.add(newProcEdt);
rs.modified = true;
revalidate();
}
private void removeProcesses() {
Vector<ProcessEditor> toRemove = new Vector<ProcessEditor>();
for (ProcessEditor edt : procEditors) {
if (edt.isSelected()) {
toRemove.add(edt);
}
}
if (toRemove.size() == procEditors.size()) {
JOptionPane.showMessageDialog(this, "There should be at least a single process in the system.",
"Warning", JOptionPane.WARNING_MESSAGE);
return;
}
for (ProcessEditor edt : toRemove) {
if (rs.removeProcess(edt.getProcess())) {
processPanel.remove(edt);
procEditors.remove(edt);
}
else {
JOptionPane.showMessageDialog(this, "Process " + edt.getLabel() +
" appears in a formula or a context automaton guard.\n" +
"Update them before removing the process.",
"Warning", JOptionPane.WARNING_MESSAGE);
}
}
rs.modified = true;
revalidate();
}
private void copyProcesses() {
Vector<ProcessEditor> toBeCopied = new Vector<ProcessEditor>();
for (ProcessEditor edt : procEditors) {
if (edt.isSelected()) {
toBeCopied.add(edt);
}
}
for (ProcessEditor edt : toBeCopied) {
ProcessEditor newEdt = new ProcessEditor(rs.copyProcess(edt.getProcess()));
processPanel.add(newEdt);
procEditors.add(newEdt);
}
rs.modified = true;
revalidate();
}
private void renameProcess() {
ProcessEditor toRename = null;
boolean fail = false;
for (ProcessEditor edt : procEditors) {
if (edt.isSelected()) {
if (toRename == null) {
toRename = edt;
}
else {
fail = true;
break;
}
}
}
if (fail || toRename == null) {
JOptionPane.showMessageDialog(this, "Select a single process to rename.", "Select process", JOptionPane.WARNING_MESSAGE);
return;
}
String idRegex = "[a-zA-Z][a-zA-Z_0-9:-]*";
boolean idOk = false;
do {
String newLabel = JOptionPane.showInputDialog(this, "Process name", toRename.getProcess().label);
if (newLabel == null)
return;
newLabel = newLabel.trim();
if (!newLabel.matches(idRegex)) {
JOptionPane.showMessageDialog(this,
"<html>Process name should start with a letter and may contain only:<br/>" +
"letters, numbers, colons (:), underscores (_) and hyphens (-)</html>",
"Error", JOptionPane.ERROR_MESSAGE);
}
else {
idOk = true;
rs.renameProcess(toRename.getProcess(), newLabel);
toRename.rename(newLabel);
rs.notifyObservers();
}
}
while (!idOk);
}
private void moveSelectedUp() {
Vector<Integer> toBeMovedIds = new Vector<Integer>();
for (int i = 0; i< procEditors.size(); ++i) {
if (procEditors.elementAt(i).isSelected())
toBeMovedIds.add(i);
}
for (int pos : toBeMovedIds) {
if (pos == 0 || procEditors.elementAt(pos-1).isSelected())
continue;
Collections.swap(procEditors, pos, pos-1);
}
processPanel.removeAll();
for (ProcessEditor edt : procEditors) {
processPanel.add(edt);
}
rs.modified = true;
revalidate();
}
private void moveSelectedDown() {
Vector<Integer> toBeMovedIds = new Vector<Integer>();
for (int i = procEditors.size()-1; i>=0; --i) {
if (procEditors.elementAt(i).isSelected())
toBeMovedIds.add(i);
}
for (int pos : toBeMovedIds) {
if (pos == procEditors.size()-1 || procEditors.elementAt(pos+1).isSelected())
continue;
Collections.swap(procEditors, pos, pos+1);
}
processPanel.removeAll();
for (ProcessEditor edt : procEditors) {
processPanel.add(edt);
}
rs.modified = true;
revalidate();
}
public void onRSUpdate() {
repaint();
}
}
class ReactionSystemStructureError extends FileStructureError {
public ReactionSystemStructureError(String message) {
super(message);
}
}

View File

@@ -0,0 +1,208 @@
package pl.umk.mat.martinp.reactics;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
class TransitionEditor extends JDialog {
private JTable transitionsList;
private TransitionTableModel transitionsModel;
private Vector<Transition> transitions;
public TransitionEditor() {
super();
// Create reactions list component
transitionsModel = new TransitionTableModel();
transitionsList = new JTable(transitionsModel);
Font cellFont = transitionsList.getFont();
Font headerFont = transitionsList.getTableHeader().getFont();
transitionsList.setFont(new Font("Monospaced", 0, cellFont.getSize() + 2));
transitionsList.getTableHeader().setFont(new Font(headerFont.getFamily(), Font.BOLD, headerFont.getSize() + 2));
transitionsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
getContentPane().setLayout(new BorderLayout());
JButton addButton = new JButton("Add transition");
addButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { addTransition(); }
});
JButton edtButton = new JButton("Edit transition");
edtButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { editTransition(); }
});
JButton rmButton = new JButton("Remove transition");
rmButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { removeTransitions(); }
});
JButton closeButton = new JButton("Close");
closeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) { setVisible(false); }
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(addButton);
buttonPanel.add(edtButton);
buttonPanel.add(rmButton);
buttonPanel.add(closeButton);
getContentPane().add(buttonPanel, BorderLayout.NORTH);
getContentPane().add(new JScrollPane(transitionsList), BorderLayout.CENTER);
setPreferredSize(new Dimension(-1, 200));
setSize(new Dimension(600, 200));
setTitle("Transitions");
}
public void showTransitionEditDialog(Component parent, Collection<Transition> trans, String from, String to) {
setTitle("Transitions for (" + from + " -> " + to + ")");
transitions = (Vector<Transition>) trans;
transitionsModel.fireTableDataChanged();
setLocationRelativeTo(parent);
setVisible(true);
}
private void addTransition() {
Transition tr = new Transition("", "");
if (!showTransitionEditDialog(tr))
return;
transitions.add(tr);
transitionsModel.fireTableDataChanged();
}
private void editTransition() {
int[] selected = transitionsList.getSelectedRows();
if (selected.length != 1) {
JOptionPane.showMessageDialog(this, "Select a single transition to edit.", "Select transition", JOptionPane.WARNING_MESSAGE);
return;
}
Transition tr = transitions.get(selected[0]);
transitionsList.clearSelection();
if (!showTransitionEditDialog(tr)) {
return;
}
transitions.setElementAt(tr, selected[0]);
transitionsModel.fireTableDataChanged();
}
private void removeTransitions() {
int[] selected = transitionsList.getSelectedRows();
for (int trIdx : selected) {
transitions.remove(trIdx);
transitionsList.clearSelection();
}
transitionsModel.fireTableDataChanged();
}
private boolean showTransitionEditDialog(Transition tr) {
final int Select = 0;
final int Approve = 1;
JTextField contextInput = new JTextField(30);
JTextField guardInput = new JTextField(30);
String contextStr = tr.context;
String guardStr = tr.guard;
contextInput.setToolTipText("<html>Additional entities for processes</html>");
guardInput.setToolTipText("<html>Initial conditions for the transition in rsCTL format.</html>");
JPanel myPanel = new JPanel(new GridBagLayout());
GridBagConstraints cs = new GridBagConstraints();
cs.insets = new Insets(5, 5, 5, 5);
cs.anchor = GridBagConstraints.WEST;
cs.gridx = 0;
cs.gridy = 0;
myPanel.add(new JLabel("Context"), cs);
cs.gridx = 1;
cs.gridy = 0;
myPanel.add(contextInput, cs);
cs.gridx = 0;
cs.gridy = 1;
myPanel.add(new JLabel("Guards"), cs);
cs.gridx = 1;
cs.gridy = 1;
myPanel.add(guardInput, cs);
int opStatus = Select;
do {
contextInput.setText(contextStr);
guardInput.setText(guardStr);
int result = JOptionPane.showConfirmDialog(null, myPanel,
"Reaction details", JOptionPane.OK_CANCEL_OPTION);
if (result != JOptionPane.OK_OPTION) {
return false;
}
contextStr = contextInput.getText();
guardStr = guardInput.getText();
//TODO: Validate the data entered to the text fields
tr.context = contextStr;
tr.guard = guardStr;
opStatus = Approve;
}
while(opStatus == Select);
return true;
}
class TransitionTableModel extends AbstractTableModel {
private final String[] columnNames = {"Context", "Guard"};
public String getColumnName(int colIdx) {
return columnNames[colIdx];
}
public int getRowCount() {
return transitions.size();
}
public int getColumnCount() {
return columnNames.length;
}
public Object getValueAt(int row, int column) {
Transition tr = transitions.get(row);
return switch (column) {
case 0 -> tr.context;
case 1 -> tr.guard;
default -> "";
};
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
}
}

View File

@@ -0,0 +1,367 @@
package pl.umk.mat.martinp.reactics;
import edu.uci.ics.jung.algorithms.layout.*;
import edu.uci.ics.jung.algorithms.layout.util.Relaxer;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse;
import edu.uci.ics.jung.visualization.decorators.ToStringLabeller;
import edu.uci.ics.jung.visualization.renderers.Renderer;
import org.apache.commons.collections15.Transformer;
import javax.swing.JPanel;
import javax.swing.JToolTip;
import javax.swing.Icon;
import javax.swing.border.EtchedBorder;
import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class TransitionSystemViewer extends JPanel implements RSObserver {
//---------------------------------------------------------------
// Visual configuration settings
//---------------------------------------------------------------
private static final Color pickedNodeColor = Color.yellow;
private static final Color edgeColor = Color.black;
private static final Font nodeLabelFont = new Font("Helvetica", Font.BOLD, 20);
private static final Font toolTipFont = new Font("Helvetica", Font.PLAIN, 14);
private static final Stroke basicEdgeArrow = new BasicStroke(3.0f);
private static Dimension initialEditorSize;
private VisualizationViewer<TSState, TSTransition> graphViewer;
private Layout<TSState, TSTransition> graphLayout;
DefaultModalGraphMouse graphMouse;
//---------------------------------------------------------------
// Transition system graph
//---------------------------------------------------------------
private DirectedSparseGraph<TSState, TSTransition> tsGraph;
private boolean isCompressed;
// Is transition system already computed?
// Used to avoid unnecessary computation of the same graph.
private boolean computed = false;
// compressed == true => context automaton state is not taken into account.
public TransitionSystemViewer(Dimension size, boolean compressed) {
this.setLayout(new BorderLayout());
tsGraph = new DirectedSparseGraph<TSState, TSTransition>();
this.isCompressed = compressed;
initialEditorSize = size;
createGraphViever();
lockNodesPositions(false);
}
// Is transition system graph already computed?
boolean isComputed() { return computed; }
void clearModificationStatus() { computed = false; }
private void createGraphViever() {
graphLayout = new FRLayout<TSState, TSTransition>(tsGraph);
graphViewer = new VisualizationViewer<TSState, TSTransition>(graphLayout, initialEditorSize) {
public JToolTip createToolTip() {
JToolTip tooltip = super.createToolTip();
tooltip.setFont(toolTipFont);
return tooltip;
}
};
// Nodes labels
graphViewer.getRenderContext().setVertexLabelTransformer(
new ToStringLabeller<TSState>());
graphViewer.getRenderer().getVertexLabelRenderer()
.setPosition(Renderer.VertexLabel.Position.CNTR);
graphViewer.getRenderContext().setVertexFontTransformer(
new Transformer<TSState,Font>() {
public Font transform(TSState st) {
return nodeLabelFont;
}
});
// Nodes colour, background, etc.
graphViewer.getRenderContext().setVertexIconTransformer(new Transformer<TSState,Icon>() {
public Icon transform(final TSState v) {
Color nodeColor = null;
if(graphViewer.getPickedVertexState().isPicked(v))
nodeColor = pickedNodeColor;
else
nodeColor = v.getFillColor();
return (v.isInitial() ? new SquareIcon(nodeColor, v.getWidth()) : new CircleIcon(nodeColor, v.getWidth()));
}});
graphViewer.getRenderContext().setEdgeShapeTransformer(new ConditionalEdgeShape<>(1.5f));
// Edges
graphViewer.getRenderContext().setEdgeArrowStrokeTransformer(new Transformer<TSTransition, Stroke>() {
public Stroke transform(TSTransition tr) {
return basicEdgeArrow;
}
});
// For interactive graph editing
graphMouse = new DefaultModalGraphMouse();
graphViewer.setGraphMouse(graphMouse);
graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
graphViewer.setVertexToolTipTransformer(new Transformer<TSState, String>() {
public String transform(TSState st) {
return st.getTooltipText();
}
});
graphViewer.setBackground(Color.white);
graphViewer.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
add(graphViewer, BorderLayout.CENTER);
}
public void updateTransitionSystemStructure(String tsString) {
// Clear graph
clear();
// Load graph structure
int nextId = 1;
HashMap<String, TSState> nodes = new HashMap<>();
TSState src = null;
for (String line : tsString.split("\\R")) {
char type = line.charAt(0);
line = line.substring(2).strip();
int end = line.lastIndexOf('}');
String automatonState = line.substring(end + 1, line.length() - 1).strip();
String stateStr = line.substring(line.indexOf('{'), end + 1);
TSState state = nodes.get( isCompressed ? stateStr : line);
if (state == null) {
state = new TSState(nextId++, stateStr, isCompressed ? null : automatonState);
nodes.put(isCompressed ? stateStr : line, state);
tsGraph.addVertex(state);
}
if (type == 'G') {
src = state;
}
else if (type == 's') {
tsGraph.addEdge(new TSTransition(), src, state);
}
}
// Find the initial state
for (TSState state : tsGraph.getVertices()) {
if (tsGraph.getInEdges(state).size() == 0) {
state.setAsInitial();
break;
}
}
relax();
graphViewer.repaint();
computed = true;
}
public void lockNodesPositions(boolean lock) {
if (lock)
graphMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);
else
graphMouse.setMode(ModalGraphMouse.Mode.PICKING);
}
public void clear() {
for (TSState st : new java.util.ArrayList<TSState>(tsGraph.getVertices())) {
tsGraph.removeVertex(st);
}
repaint();
}
/** For better vertex placement */
private void relax() {
graphLayout.initialize();
graphLayout.setSize(graphViewer.getSize());
Relaxer relaxer = graphViewer.getModel().getRelaxer();
if (relaxer != null) {
relaxer.stop();
relaxer.prerelax();
relaxer.relax();
}
}
//---------------------------------------------------------------------------------------------
// For drawing the initial state
//---------------------------------------------------------------------------------------------
static class SquareIcon implements Icon {
private final Color fillColor;
private final int width;
public SquareIcon(Color fColor, int width) {
fillColor = fColor;
this.width = width;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(fillColor);
g.fillRect(x, y, width, width);
g.setColor(Color.black);
g.drawRect(x, y, width, width);
}
public int getIconWidth() {
return width;
}
public int getIconHeight() {
return width;
}
}
//---------------------------------------------------------------------------------------------
// For drawing all non-initial states
//---------------------------------------------------------------------------------------------
static class CircleIcon implements Icon {
private final Color fillColor;
private final int radius;
public CircleIcon(Color fColor, int radius) {
fillColor = fColor;
this.radius = radius;
}
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(fillColor);
g.fillOval(x, y, radius, radius);
g.setColor(Color.black);
g.drawOval(x, y, radius, radius);
}
public int getIconWidth() {
return radius;
}
public int getIconHeight() {
return radius;
}
}
public void onRSUpdate() {
clear();
}
}
//-------------------------------------------------------------------------------------------------
// Single node of the Transition system graph
//-------------------------------------------------------------------------------------------------
class TSState {
public final static Color fillColor = Color.lightGray;
public final static Color initialColor = new Color(102, 178, 255);
private static final int nodeWidth = 30;
private static final int nodeHeight = 30;
private final int id;
private final String rsDetails;
private final String toolTipText;
private final String aState;
private boolean initial = false;
public TSState(int id, String stateStr) {
this.id = id;
this.rsDetails = formatRSDetails(stateStr.substring(1, stateStr.length() - 1).strip());
this.aState = null;
this.toolTipText = formatToolTipText();
}
public TSState(int id, String stateStr, String aState) {
this.id = id;
this.rsDetails = formatRSDetails(stateStr.substring(1, stateStr.length() - 1).strip());
this.aState = aState;
this.toolTipText = formatToolTipText();
}
public boolean isInitial() {
return initial;
}
public void setAsInitial() {
initial = true;
}
public String toString() {
return String.valueOf(id);
}
public int getWidth() {
return nodeWidth;
}
public int getHeight() {
return nodeHeight;
}
Color getFillColor() {
return initial ? initialColor : fillColor;
}
public String getTooltipText() {
return toolTipText;
}
private String formatRSDetails(String rsDetails) {
return rsDetails.replaceAll("\\} (proc\\d+=\\{)", "}<br/>$1");
}
private String formatToolTipText() {
Pattern pattern = Pattern.compile("\\w+=\\{[^}]*\\}");
Matcher matcher = pattern.matcher(rsDetails);
ArrayList<String> blocks = new ArrayList<String>();
while (matcher.find()) {
blocks.add(matcher.group());
}
if (aState != null)
return "<html>" +
"<b>CA</b> " + aState+ "<br/><hr>" +
String.join("<br/>", blocks) +
"</html>";
else
return "<html>" +
String.join("<br/>", blocks) +
"</html>";
}
}
//-------------------------------------------------------------------------------------------------
// Single edge of the Transition system graph
//-------------------------------------------------------------------------------------------------
class TSTransition { }

View File

@@ -1,11 +1,11 @@
C_HEADER = '\033[95m'
C_BLUE = '\033[94m'
C_GREEN = '\033[92m'
C_SOMEOTHER = '\033[93m'
C_RED = '\033[91m'
C_ENDC = '\033[0m'
C_BOLD = '\033[1m'
C_UNDERLINE = '\033[4m'
C_HEADER = "\033[95m"
C_BLUE = "\033[94m"
C_GREEN = "\033[92m"
C_SOMEOTHER = "\033[93m"
C_RED = "\033[91m"
C_ENDC = "\033[0m"
C_BOLD = "\033[1m"
C_UNDERLINE = "\033[4m"
C_MARK_INFO = C_BOLD + "[" + C_GREEN + "*" + C_ENDC + C_BOLD + "]" + C_ENDC
C_MARK_ERROR = C_BOLD + "[" + C_RED + "!" + C_ENDC + C_BOLD + "]" + C_ENDC
@@ -30,4 +30,5 @@ def print_info(s):
def print_positive(s):
print("[" + colour_str(C_BOLD, "+") + "] {:s}".format(s))
# EOF

View File

@@ -5,19 +5,19 @@ from smt import *
from logics import *
from rsltl_shortcuts import *
def ex():
def ex():
prs = ReactionSystemWithConcentrationsParam()
ent_with_conc = [("a", 3), ("b",2), ("c",1), ("h",1)]
ent_with_conc = [("a", 3), ("b", 2), ("c", 1), ("h", 1)]
for ec in ent_with_conc:
prs.add_bg_set_entity(ec)
lda = prs.get_param("lda")
prs.add_reaction([("a",1)],[("h",1)],[("b", 2)])
prs.add_reaction(lda,[("h",1)],[("c",1)])
prs.add_reaction([("a", 1)], [("h", 1)], [("b", 2)])
prs.add_reaction(lda, [("h", 1)], [("c", 1)])
##
@@ -38,6 +38,7 @@ def ex():
checker = SmtCheckerRSCParam(crprs, optimise=True)
checker.check_rsltl(formulae_list=[f], param_constr=pc)
if __name__ == "__main__":
ex()

View File

@@ -1,10 +1,9 @@
from enum import Enum
BagDesc_oper = Enum(
'BagDesc_oper', 'entity true l_and l_or l_not lt le eq ge gt')
BagDesc_oper = Enum("BagDesc_oper", "entity true l_and l_or l_not lt le eq ge gt")
class BagDescription(object):
def __init__(self, f_type, L_oper=None, R_oper=None, entity=""):
self.f_type = f_type
self.left_operand = L_oper
@@ -19,9 +18,13 @@ class BagDescription(object):
if self.f_type == BagDesc_oper.true:
return "TRUE"
if self.f_type == BagDesc_oper.l_and:
return "(" + repr(self.left_operand) + " & " + repr(self.right_operand) + ")"
return (
"(" + repr(self.left_operand) + " & " + repr(self.right_operand) + ")"
)
if self.f_type == BagDesc_oper.l_or:
return "(" + repr(self.left_operand) + " | " + repr(self.right_operand) + ")"
return (
"(" + repr(self.left_operand) + " | " + repr(self.right_operand) + ")"
)
if self.f_type == BagDesc_oper.l_not:
return "~(" + repr(self.left_operand) + ")"
if self.f_type == BagDesc_oper.lt:
@@ -39,12 +42,14 @@ class BagDescription(object):
"""Sanity checks"""
for operand in (self.left_operand, self.right_operand):
if operand:
if not(
isinstance(operand, BagDescription)
or isinstance(operand, int)):
if not (
isinstance(operand, BagDescription) or isinstance(operand, int)
):
raise RuntimeError(
"Unexpected operand type for a bag: {:s} (type: {:s})".format(
str(operand), str(type(operand))))
str(operand), str(type(operand))
)
)
@classmethod
def f_entity(cls, entity_name):
@@ -86,4 +91,5 @@ class BagDescription(object):
def __invert__(self):
return BagDescription(BagDesc_oper.l_not, L_oper=self)
# EOF

View File

@@ -1,11 +1,11 @@
from enum import Enum
ParamConstraint_oper = Enum(
'ParamConstraint_oper',
'param_entity true l_and l_or l_not lt le eq ge gt')
"ParamConstraint_oper", "param_entity true l_and l_or l_not lt le eq ge gt"
)
class ParamConstraint(object):
def __init__(self, f_type, L_oper=None, R_oper=None, param=None, entity=""):
self.f_type = f_type
self.left_operand = L_oper
@@ -21,9 +21,13 @@ class ParamConstraint(object):
if self.f_type == ParamConstraint_oper.true:
return "TRUE"
if self.f_type == ParamConstraint_oper.l_and:
return "(" + repr(self.left_operand) + " & " + repr(self.right_operand) + ")"
return (
"(" + repr(self.left_operand) + " & " + repr(self.right_operand) + ")"
)
if self.f_type == ParamConstraint_oper.l_or:
return "(" + repr(self.left_operand) + " | " + repr(self.right_operand) + ")"
return (
"(" + repr(self.left_operand) + " | " + repr(self.right_operand) + ")"
)
if self.f_type == ParamConstraint_oper.l_not:
return "~(" + repr(self.left_operand) + ")"
if self.f_type == ParamConstraint_oper.lt:
@@ -41,17 +45,18 @@ class ParamConstraint(object):
"""Sanity checks"""
for operand in (self.left_operand, self.right_operand):
if operand:
if not(
isinstance(operand, ParamConstraint)
or isinstance(operand, int)):
if not (
isinstance(operand, ParamConstraint) or isinstance(operand, int)
):
raise RuntimeError(
"Unexpected operand type for a bag: {:s} (type: {:s})".format(
str(operand), str(type(operand))))
str(operand), str(type(operand))
)
)
@classmethod
def f_param_ent(cls, param, entity_name):
return cls(ParamConstraint_oper.param_entity, param=param,
entity=entity_name)
return cls(ParamConstraint_oper.param_entity, param=param, entity=entity_name)
@classmethod
def f_TRUE(cls):
@@ -66,34 +71,28 @@ class ParamConstraint(object):
return cls(ParamConstraint_oper.l_not, L_oper=arg)
def __lt__(self, other):
return ParamConstraint(
ParamConstraint_oper.lt, L_oper=self, R_oper=other)
return ParamConstraint(ParamConstraint_oper.lt, L_oper=self, R_oper=other)
def __le__(self, other):
return ParamConstraint(
ParamConstraint_oper.le, L_oper=self, R_oper=other)
return ParamConstraint(ParamConstraint_oper.le, L_oper=self, R_oper=other)
def __eq__(self, other):
return ParamConstraint(
ParamConstraint_oper.eq, L_oper=self, R_oper=other)
return ParamConstraint(ParamConstraint_oper.eq, L_oper=self, R_oper=other)
def __ge__(self, other):
return ParamConstraint(
ParamConstraint_oper.ge, L_oper=self, R_oper=other)
return ParamConstraint(ParamConstraint_oper.ge, L_oper=self, R_oper=other)
def __gt__(self, other):
return ParamConstraint(
ParamConstraint_oper.gt, L_oper=self, R_oper=other)
return ParamConstraint(ParamConstraint_oper.gt, L_oper=self, R_oper=other)
def __and__(self, other):
return ParamConstraint(
ParamConstraint_oper.l_and, L_oper=self, R_oper=other)
return ParamConstraint(ParamConstraint_oper.l_and, L_oper=self, R_oper=other)
def __or__(self, other):
return ParamConstraint(
ParamConstraint_oper.l_or, L_oper=self, R_oper=other)
return ParamConstraint(ParamConstraint_oper.l_or, L_oper=self, R_oper=other)
def __invert__(self):
return ParamConstraint(ParamConstraint_oper.l_not, L_oper=self)
# EOF

View File

@@ -14,57 +14,60 @@ class ParamConstr_Encoder(object):
# self.loop_position = None
def load_variables(self, var_rs, var_ctx, var_loop_pos):
self.v = var_rs
self.v_ctx = var_ctx
self.loop_position = var_loop_pos
def encode(self, param_constr):
if not param_constr:
raise RuntimeError("param_constr is None")
if param_constr.f_type == ParamConstraint_oper.param_entity:
return self.smt_checker.get_enc_param(
param_constr.param.name, param_constr.entity)
param_constr.param.name, param_constr.entity
)
if param_constr.f_type == ParamConstraint_oper.true:
return True
if param_constr.f_type == ParamConstraint_oper.l_and:
return And(self.encode(param_constr.left_operand),
self.encode(param_constr.right_operand))
return And(
self.encode(param_constr.left_operand),
self.encode(param_constr.right_operand),
)
if param_constr.f_type == ParamConstraint_oper.l_or:
return Or(self.encode(param_constr.left_operand),
self.encode(param_constr.right_operand))
return Or(
self.encode(param_constr.left_operand),
self.encode(param_constr.right_operand),
)
if param_constr.f_type == ParamConstraint_oper.l_not:
return Not(self.encode(param_constr.left_operand))
if param_constr.f_type == ParamConstraint_oper.lt:
return self.encode(
param_constr.left_operand) < int(
param_constr.right_operand)
return self.encode(param_constr.left_operand) < int(
param_constr.right_operand
)
if param_constr.f_type == ParamConstraint_oper.le:
return self.encode(
param_constr.left_operand) <= int(
param_constr.right_operand)
return self.encode(param_constr.left_operand) <= int(
param_constr.right_operand
)
if param_constr.f_type == ParamConstraint_oper.eq:
return self.encode(
param_constr.left_operand) == int(
param_constr.right_operand)
return self.encode(param_constr.left_operand) == int(
param_constr.right_operand
)
if param_constr.f_type == ParamConstraint_oper.ge:
return self.encode(
param_constr.left_operand) >= int(
param_constr.right_operand)
return self.encode(param_constr.left_operand) >= int(
param_constr.right_operand
)
if param_constr.f_type == ParamConstraint_oper.gt:
return self.encode(
param_constr.left_operand) > int(
param_constr.right_operand)
return self.encode(param_constr.left_operand) > int(
param_constr.right_operand
)
assert False, "Unsupported case {:s}".format(param_constr.f_type)

View File

@@ -4,14 +4,13 @@ from enum import Enum
from logics.bags import *
rsLTL_form_type = Enum(
'rsLTL_form_type',
'bag l_and l_or l_not l_implies t_globally t_finally t_next t_until t_release')
"rsLTL_form_type",
"bag l_and l_or l_not l_implies t_globally t_finally t_next t_until t_release",
)
class Formula_rsLTL(object):
def __init__(
self, f_type, L_oper=None, R_oper=None, sub_oper=None, bag=None):
def __init__(self, f_type, L_oper=None, R_oper=None, sub_oper=None, bag=None):
self.f_type = f_type
self.left_operand = L_oper
self.right_operand = R_oper
@@ -21,7 +20,10 @@ class Formula_rsLTL(object):
# it's silly, but it's a frequent mistake
if callable(sub_oper):
raise RuntimeError(
"sub_oper should not be a function. Missing () for {0}?".format(sub_oper))
"sub_oper should not be a function. Missing () for {0}?".format(
sub_oper
)
)
if isinstance(self.left_operand, BagDescription):
self.left_operand = Formula_rsLTL.f_bag(self.left_operand)
@@ -43,21 +45,37 @@ class Formula_rsLTL(object):
if self.f_type == rsLTL_form_type.t_next:
return "X[" + repr(self.sub_operand) + "](" + repr(self.left_operand) + ")"
if self.f_type == rsLTL_form_type.l_and:
return "(" + repr(self.left_operand) + " & " + repr(self.right_operand) + ")"
return (
"(" + repr(self.left_operand) + " & " + repr(self.right_operand) + ")"
)
if self.f_type == rsLTL_form_type.l_or:
return "(" + repr(self.left_operand) + " | " + repr(self.right_operand) + ")"
return (
"(" + repr(self.left_operand) + " | " + repr(self.right_operand) + ")"
)
if self.f_type == rsLTL_form_type.l_implies:
return "(" + repr(self.left_operand) + " => " + repr(self.right_operand) + ")"
return (
"(" + repr(self.left_operand) + " => " + repr(self.right_operand) + ")"
)
if self.f_type == rsLTL_form_type.t_until:
return "(" + repr(
self.left_operand) + " U[" + repr(
self.sub_operand) + "] " + repr(
self.right_operand) + ")"
return (
"("
+ repr(self.left_operand)
+ " U["
+ repr(self.sub_operand)
+ "] "
+ repr(self.right_operand)
+ ")"
)
if self.f_type == rsLTL_form_type.t_release:
return "(" + repr(
self.left_operand) + " R[" + repr(
self.sub_operand) + "] " + repr(
self.right_operand) + ")"
return (
"("
+ repr(self.left_operand)
+ " R["
+ repr(self.sub_operand)
+ "] "
+ repr(self.right_operand)
+ ")"
)
@property
def is_bag(self):
@@ -93,8 +111,7 @@ class Formula_rsLTL(object):
@classmethod
def f_U(cls, sub, arg_L, arg_R):
return cls(
rsLTL_form_type.t_until, L_oper=arg_L, R_oper=arg_R, sub_oper=sub)
return cls(rsLTL_form_type.t_until, L_oper=arg_L, R_oper=arg_R, sub_oper=sub)
@classmethod
def f_F(cls, sub, arg_L):
@@ -102,9 +119,7 @@ class Formula_rsLTL(object):
@classmethod
def f_R(cls, sub, arg_L, arg_R):
return cls(
rsLTL_form_type.t_release, L_oper=arg_L, R_oper=arg_R,
sub_oper=sub)
return cls(rsLTL_form_type.t_release, L_oper=arg_L, R_oper=arg_R, sub_oper=sub)
def __and__(self, other):
return Formula_rsLTL(rsLTL_form_type.l_and, L_oper=self, R_oper=other)

View File

@@ -24,13 +24,11 @@ class rsLTL_Encoder(object):
self.init_ncalls()
def load_variables(self, var_rs, var_ctx, var_loop_pos):
self.v = var_rs
self.v_ctx = var_ctx
self.loop_position = var_loop_pos
def get_encoding(self, formula, bound):
assert self.v is not None
assert self.v_ctx is not None
assert self.loop_position is not None
@@ -49,8 +47,8 @@ class rsLTL_Encoder(object):
Cache for formulae encodings
"""
self.cache_hits = 0
self.enc_fcache = [{} for level in range(0, bound+1)]
self.enc_fcache_approx = [{} for level in range(0, bound+1)]
self.enc_fcache = [{} for level in range(0, bound + 1)]
self.enc_fcache_approx = [{} for level in range(0, bound + 1)]
def cache_save(self, formula, level, formula_encoding):
self.enc_fcache[level][formula] = formula_encoding
@@ -83,7 +81,6 @@ class rsLTL_Encoder(object):
return (self.ncalls_encode, self.ncalls_encode_approx)
def encode_bag(self, bag_formula, level, context=False):
if not bag_formula:
raise RuntimeError("bag_formula is None")
@@ -100,41 +97,42 @@ class rsLTL_Encoder(object):
if bag_formula.f_type == BagDesc_oper.l_and:
return And(
self.encode_bag(bag_formula.left_operand, level, context),
self.encode_bag(bag_formula.right_operand, level, context))
self.encode_bag(bag_formula.right_operand, level, context),
)
if bag_formula.f_type == BagDesc_oper.l_or:
return Or(
self.encode_bag(bag_formula.left_operand, level, context),
self.encode_bag(bag_formula.right_operand, level, context))
self.encode_bag(bag_formula.right_operand, level, context),
)
if bag_formula.f_type == BagDesc_oper.l_not:
return Not(self.encode_bag(
bag_formula.left_operand, level, context))
return Not(self.encode_bag(bag_formula.left_operand, level, context))
if bag_formula.f_type == BagDesc_oper.lt:
return self.encode_bag(
bag_formula.left_operand, level, context) < int(
bag_formula.right_operand)
return self.encode_bag(bag_formula.left_operand, level, context) < int(
bag_formula.right_operand
)
if bag_formula.f_type == BagDesc_oper.le:
return self.encode_bag(
bag_formula.left_operand, level, context) <= int(
bag_formula.right_operand)
return self.encode_bag(bag_formula.left_operand, level, context) <= int(
bag_formula.right_operand
)
if bag_formula.f_type == BagDesc_oper.eq:
return self.encode_bag(
bag_formula.left_operand, level, context) == int(
bag_formula.right_operand)
return self.encode_bag(bag_formula.left_operand, level, context) == int(
bag_formula.right_operand
)
if bag_formula.f_type == BagDesc_oper.ge:
return self.encode_bag(
bag_formula.left_operand, level, context) >= int(
bag_formula.right_operand)
return self.encode_bag(bag_formula.left_operand, level, context) >= int(
bag_formula.right_operand
)
if bag_formula.f_type == BagDesc_oper.gt:
return self.encode_bag(
bag_formula.left_operand, level, context) > int(
bag_formula.right_operand)
return self.encode_bag(bag_formula.left_operand, level, context) > int(
bag_formula.right_operand
)
assert False, "Unsupported case {:s}".format(bag_formula.f_type)
@@ -149,7 +147,6 @@ class rsLTL_Encoder(object):
return res
def encode(self, formula, level, bound):
self.ncalls_encode += 1
from_cache = self.cache_query(formula, level)
@@ -159,12 +156,12 @@ class rsLTL_Encoder(object):
enc = None
if not isinstance(formula, Formula_rsLTL):
raise NotImplementedError(
"Unsupported formula type: " + str(type(formula)))
raise NotImplementedError("Unsupported formula type: " + str(type(formula)))
if level > bound:
raise RuntimeError(
"level > bound. Unexpected behaviour. The encoding does not support levels higher than a bound.")
"level > bound. Unexpected behaviour. The encoding does not support levels higher than a bound."
)
if formula.f_type == rsLTL_form_type.bag:
enc = self.encode_bag_state(formula.bag_descr, level)
@@ -179,33 +176,40 @@ class rsLTL_Encoder(object):
elif formula.f_type == rsLTL_form_type.l_and:
enc = And(
self.encode(formula.left_operand, level, bound),
self.encode(formula.right_operand, level, bound)
self.encode(formula.right_operand, level, bound),
)
elif formula.f_type == rsLTL_form_type.l_or:
enc = Or(
self.encode(formula.left_operand, level, bound),
self.encode(formula.right_operand, level, bound)
self.encode(formula.right_operand, level, bound),
)
elif formula.f_type == rsLTL_form_type.l_implies:
enc = Implies(
self.encode(formula.left_operand, level, bound),
self.encode(formula.right_operand, level, bound)
self.encode(formula.right_operand, level, bound),
)
elif formula.f_type == rsLTL_form_type.t_next:
if level < bound:
enc = And(
self.encode(formula.left_operand, level + 1, bound),
self.encode_bag_ctx(formula.sub_operand, level)
self.encode_bag_ctx(formula.sub_operand, level),
)
else:
# level == bound
enc = False
for loop_level in range(1, bound+1):
enc = simplify(Or(enc, And(self.loop_position == loop_level, self.encode(
formula.left_operand, loop_level, bound))))
for loop_level in range(1, bound + 1):
enc = simplify(
Or(
enc,
And(
self.loop_position == loop_level,
self.encode(formula.left_operand, loop_level, bound),
),
)
)
enc = And(enc, self.encode_bag_ctx(formula.sub_operand, level))
enc = simplify(enc)
@@ -214,22 +218,25 @@ class rsLTL_Encoder(object):
enc = And(
self.encode(formula.left_operand, level, bound),
self.encode_bag_ctx(formula.sub_operand, level),
self.encode(formula, level + 1, bound)
self.encode(formula, level + 1, bound),
)
else:
# level == bound
enc_loops = False
for loop_level in range(1, bound+1):
enc_loops = simplify(Or(enc_loops,
for loop_level in range(1, bound + 1):
enc_loops = simplify(
Or(
enc_loops,
And(
self.loop_position == loop_level,
self.encode_approx(formula, loop_level, bound),
),
)
)
))
enc = And(
self.encode(formula.left_operand, bound, bound),
enc_loops,
self.encode_bag_ctx(formula.sub_operand, level)
self.encode_bag_ctx(formula.sub_operand, level),
)
enc = simplify(enc)
@@ -239,25 +246,26 @@ class rsLTL_Encoder(object):
self.encode(formula.left_operand, level, bound),
And(
self.encode_bag_ctx(formula.sub_operand, level),
self.encode(formula, level + 1, bound)
)
self.encode(formula, level + 1, bound),
),
)
else:
# level == bound
enc_loops = False
for loop_level in range(1, bound+1):
enc_loops = simplify(Or(enc_loops,
for loop_level in range(1, bound + 1):
enc_loops = simplify(
Or(
enc_loops,
And(
self.loop_position == loop_level,
self.encode_approx(formula, loop_level, bound),
),
)
)
))
# print(enc)
enc = Or(self.encode(formula.left_operand, bound, bound),
And(
enc_loops,
self.encode_bag_ctx(formula.sub_operand, level)
)
enc = Or(
self.encode(formula.left_operand, bound, bound),
And(enc_loops, self.encode_bag_ctx(formula.sub_operand, level)),
)
enc = simplify(enc)
@@ -268,21 +276,24 @@ class rsLTL_Encoder(object):
else:
# level == bound
inner_enc = False
for loop_level in range(1, bound+1):
inner_enc = simplify(Or(inner_enc,
for loop_level in range(1, bound + 1):
inner_enc = simplify(
Or(
inner_enc,
And(
self.loop_position == loop_level,
self.encode_approx(formula, loop_level, bound)
self.encode_approx(formula, loop_level, bound),
),
)
)
))
enc = Or(
self.encode(formula.right_operand, level, bound),
And(
self.encode(formula.left_operand, level, bound),
inner_enc,
self.encode_bag_ctx(formula.sub_operand, level)
)
self.encode_bag_ctx(formula.sub_operand, level),
),
)
elif formula.f_type == rsLTL_form_type.t_release:
@@ -291,23 +302,23 @@ class rsLTL_Encoder(object):
else:
# level == bound
inner_enc = False
for loop_level in range(1, bound+1):
inner_enc = simplify(Or(inner_enc,
for loop_level in range(1, bound + 1):
inner_enc = simplify(
Or(
inner_enc,
And(
self.loop_position == loop_level,
self.encode_approx(formula, loop_level, bound)
self.encode_approx(formula, loop_level, bound),
),
)
)
))
enc = And(
self.encode(formula.right_operand, level, bound),
Or(
self.encode(formula.left_operand, level, bound),
And(
inner_enc,
self.encode_bag_ctx(formula.sub_operand, level)
)
)
And(inner_enc, self.encode_bag_ctx(formula.sub_operand, level)),
),
)
else:
@@ -341,8 +352,8 @@ class rsLTL_Encoder(object):
And(
self.encode(formula.left_operand, level, bound),
self.encode_approx(formula, level + 1, bound),
self.encode_bag_ctx(formula.sub_operand, level)
)
self.encode_bag_ctx(formula.sub_operand, level),
),
)
else:
# level == bound
@@ -356,9 +367,9 @@ class rsLTL_Encoder(object):
self.encode(formula.left_operand, level, bound),
And(
self.encode_approx(formula, level + 1, bound),
self.encode_bag_ctx(formula.sub_operand, level)
)
)
self.encode_bag_ctx(formula.sub_operand, level),
),
),
)
else:
# level == bound
@@ -369,7 +380,7 @@ class rsLTL_Encoder(object):
enc = And(
self.encode(formula.left_operand, level, bound),
self.encode_bag_ctx(formula.sub_operand, level),
self.encode_approx(formula, level + 1, bound)
self.encode_approx(formula, level + 1, bound),
)
else:
# level == bound
@@ -381,16 +392,15 @@ class rsLTL_Encoder(object):
self.encode(formula.left_operand, level, bound),
And(
self.encode_bag_ctx(formula.sub_operand, level),
self.encode_approx(formula, level + 1, bound)
)
self.encode_approx(formula, level + 1, bound),
),
)
else:
# level == bound
enc = self.encode(formula.left_operand, bound, bound)
else:
raise NotImplementedError(
"Unsupported operator in approximation encoding")
raise NotImplementedError("Unsupported operator in approximation encoding")
if enc is None:
raise RuntimeError("Encoding is NONE. Should never happen")

View File

@@ -2,7 +2,11 @@ from rs.reaction_system import ReactionSystem
from rs.context_automaton import ContextAutomaton
from rs.reaction_system_with_concentrations import ReactionSystemWithConcentrations
from rs.reaction_system_with_concentrations_param import ReactionSystemWithConcentrationsParam, ParameterObj, is_param
from rs.reaction_system_with_concentrations_param import (
ReactionSystemWithConcentrationsParam,
ParameterObj,
is_param,
)
from rs.context_automaton_with_concentrations import ContextAutomatonWithConcentrations
from rs.extended_context_automaton import ExtendedContextAutomaton

View File

@@ -3,7 +3,6 @@ from colour import *
class ContextAutomaton(object):
def __init__(self, reaction_system):
self._states = []
self._transitions = []
@@ -40,7 +39,7 @@ class ContextAutomaton(object):
if name not in self._states:
self._states.append(name)
else:
print("\'%s\' already added. skipping..." % (name,))
print("'%s' already added. skipping..." % (name,))
def add_states(self, states_set):
for st in states_set:
@@ -56,10 +55,7 @@ class ContextAutomaton(object):
return self._states[self._init_state]
def is_state(self, name):
if name in self._states:
return True
else:
return False
return name in self._states
def get_state_id(self, name):
try:
@@ -79,10 +75,7 @@ class ContextAutomaton(object):
print(state)
def is_valid_rs_set(self, elements):
if set(elements).issubset(self._reaction_system.background_set):
return True
else:
return False
return set(elements).issubset(self._reaction_system.background_set)
def is_valid_context(self, context):
return self.is_valid_rs_set(context)
@@ -96,20 +89,19 @@ class ContextAutomaton(object):
return new_set
def add_transition(self, src, context_set, dst):
if not type(context_set) is set and not type(context_set) is list:
if not isinstance(context_set, (set, list)):
print("Contexts set must be of type set or list")
if not self.is_valid_context(context_set):
raise RuntimeError(
"one of the entities in the context set is unknown (undefined)!")
"one of the entities in the context set is unknown (undefined)!"
)
if not self.is_state(src):
raise RuntimeError(
"\"" + src + "\" is an unknown (undefined) state")
raise RuntimeError('"' + src + '" is an unknown (undefined) state')
if not self.is_state(dst):
raise RuntimeError(
"\"" + dst + "\" is an unknown (undefined) state")
raise RuntimeError('"' + dst + '" is an unknown (undefined) state')
new_context_set = set()
for e in set(context_set):
@@ -118,8 +110,8 @@ class ContextAutomaton(object):
self._prod_entities |= new_context_set
self._transitions.append(
(self.get_state_id(src),
new_context_set, self.get_state_id(dst)))
(self.get_state_id(src), new_context_set, self.get_state_id(dst))
)
def rsset2str(self, elements):
"""Converts the set of entities ids into the string with their names"""
@@ -168,4 +160,5 @@ class ContextAutomaton(object):
self.show_transitions()
self.show_prod_entities()
# EOF

View File

@@ -5,18 +5,13 @@ from rs.context_automaton import ContextAutomaton
class ContextAutomatonWithConcentrations(ContextAutomaton):
def __init__(self, reaction_system):
super(ContextAutomatonWithConcentrations,
self).__init__(reaction_system)
super(ContextAutomatonWithConcentrations, self).__init__(reaction_system)
def is_valid_context(self, context):
if set(
[e for e, lvl in context]).issubset(
self._reaction_system.background_set):
return True
else:
return False
return set(e for e, lvl in context).issubset(
self._reaction_system.background_set
)
def context2str(self, ctx):
if len(ctx) == 0:
@@ -28,50 +23,43 @@ class ContextAutomatonWithConcentrations(ContextAutomaton):
return s
def add_transition(self, src, context_set, dst):
if not type(context_set) is set and not type(context_set) is list:
if not isinstance(context_set, (set, list)):
print("Contexts set must be of type set or list")
if not self.is_valid_context(context_set):
raise RuntimeError(
"one of the entities in the context set is unknown (undefined)!")
"one of the entities in the context set is unknown (undefined)!"
)
if not self.is_state(src):
raise RuntimeError(
"\"" + src + "\" is an unknown (undefined) state")
raise RuntimeError('"' + src + '" is an unknown (undefined) state')
if not self.is_state(dst):
raise RuntimeError(
"\"" + dst + "\" is an unknown (undefined) state")
raise RuntimeError('"' + dst + '" is an unknown (undefined) state')
new_context_set = set()
for ent, lvl in set(context_set):
new_context_set.add(
(self._reaction_system.get_entity_id(ent), lvl))
new_context_set.add((self._reaction_system.get_entity_id(ent), lvl))
self._transitions.append(
(self.get_state_id(src),
new_context_set, self.get_state_id(dst)))
(self.get_state_id(src), new_context_set, self.get_state_id(dst))
)
def get_automaton_with_flat_contexts(self, ordinary_reaction_system):
ca = ContextAutomaton(ordinary_reaction_system)
ca._states = self._states
ca._init_state = self._init_state
for src, ctx, dst in self._transitions:
new_ctx = set()
for ent, conc in ctx:
for i in range(1, conc+1):
n = self._reaction_system.get_entity_name(
ent) + "#" + str(i)
for i in range(1, conc + 1):
n = self._reaction_system.get_entity_name(ent) + "#" + str(i)
ca._reaction_system.ensure_bg_set_entity(n)
new_ctx.add(n)
ca.add_transition(
ca.get_state_name(src),
new_ctx, ca.get_state_name(dst))
ca.add_transition(ca.get_state_name(src), new_ctx, ca.get_state_name(dst))
return ca
@@ -80,4 +68,5 @@ class ContextAutomatonWithConcentrations(ContextAutomaton):
self.show_states()
self.show_transitions()
# EOF

View File

@@ -70,28 +70,29 @@ class ExtendedContextAutomaton(ContextAutomaton):
ctx_reactants, ctx_inhibitors, ctx_products = ctx_reaction
if not type(ctx_products) is set and not type(ctx_products) is list:
if not isinstance(ctx_products, (set, list)):
print("Contexts set (context products) must be of type set or list")
if not self.is_valid_rs_set(ctx_reactants):
raise RuntimeError(
"one of the entities in the reactants set is unknown (undefined)!")
"one of the entities in the reactants set is unknown (undefined)!"
)
if not self.is_valid_rs_set(ctx_inhibitors):
raise RuntimeError(
"one of the entities in the inhibitors set is unknown (undefined)!")
"one of the entities in the inhibitors set is unknown (undefined)!"
)
if not self.is_valid_rs_set(ctx_products):
raise RuntimeError(
"one of the entities in the context set is unknown (undefined)!")
"one of the entities in the context set is unknown (undefined)!"
)
if not self.is_state(src):
raise RuntimeError(
"\"" + src + "\" is an unknown (undefined) state")
raise RuntimeError('"' + src + '" is an unknown (undefined) state')
if not self.is_state(dst):
raise RuntimeError(
"\"" + dst + "\" is an unknown (undefined) state")
raise RuntimeError('"' + dst + '" is an unknown (undefined) state')
src_id = self.get_state_id(src)
dst_id = self.get_state_id(dst)
@@ -119,8 +120,15 @@ class ExtendedContextAutomaton(ContextAutomaton):
for src_id, act_id, reaction, dst_id in self._transitions:
str_transition = self.get_state_name(src_id) + " --( "
str_transition += "<" + self.get_actions_str(act_id) + "> | "
str_transition += "( " + self.rsset2str(reaction[0]) + "," + self.rsset2str(
reaction[1]) + "," + self.rsset2str(reaction[2]) + " )"
str_transition += (
"( "
+ self.rsset2str(reaction[0])
+ ","
+ self.rsset2str(reaction[1])
+ ","
+ self.rsset2str(reaction[2])
+ " )"
)
str_transition += " )--> " + self.get_state_name(dst_id)
print(" - " + str_transition)
@@ -130,7 +138,7 @@ class ExtendedContextAutomaton(ContextAutomaton):
if action_name not in self._actions:
self._actions.append(action_name)
else:
print("\'%s\' already added. skipping..." % (action_name,))
print("'%s' already added. skipping..." % (action_name,))
def get_action_id(self, action_name):
"""For an action name returns its id"""
@@ -138,8 +146,7 @@ class ExtendedContextAutomaton(ContextAutomaton):
try:
return self._actions.index(action_name)
except ValueError:
print_error("Undefined context automaton action: " +
repr(action_name))
print_error("Undefined context automaton action: " + repr(action_name))
exit(1)
def get_action_name(self, action_id):
@@ -173,4 +180,5 @@ class ExtendedContextAutomaton(ContextAutomaton):
super(ExtendedContextAutomaton, self).show()
self.show_actions()
# EOF

View File

@@ -3,7 +3,6 @@ from colour import *
class NetworkOfContextAutomata(object):
def __init__(self, reaction_system, context_automata):
self.automata = []
self._reaction_system = reaction_system
@@ -44,14 +43,14 @@ class NetworkOfContextAutomata(object):
for automaton in self.automata:
if automaton.reaction_system != self._reaction_system:
print_error(
"Mismatching reaction system used in \"" +
str(automaton.name) + "\"!!!")
'Mismatching reaction system used in "'
+ str(automaton.name)
+ '"!!!'
)
exit(1)
def show_prod_entities(self):
print(
C_MARK_INFO +
" Possible context-products for the network of automata:")
print(C_MARK_INFO + " Possible context-products for the network of automata:")
for entity in self.prod_entities:
print(" - " + self._reaction_system.get_entity_name(entity))
@@ -96,7 +95,8 @@ class NetworkOfContextAutomata(object):
for entity in aut.prod_entities:
self._actions_for_products.setdefault(entity, set())
self._actions_for_products[entity] |= aut.get_actions_producing_entity(
entity)
entity
)
def show(self):
print()
@@ -108,4 +108,5 @@ class NetworkOfContextAutomata(object):
self.show_prod_entities()
self.show_actions()
# EOF

View File

@@ -3,9 +3,7 @@ from colour import *
class ReactionSystem(object):
def __init__(self):
self.reactions = []
self.background_set = []
@@ -30,8 +28,7 @@ class ReactionSystem(object):
def assume_not_in_bgset(self, name):
if self.is_in_background_set(name):
raise RuntimeError(
"The entity " + name + " is already on the list")
raise RuntimeError("The entity " + name + " is already on the list")
def add_bg_set_entity(self, name):
self.assume_not_in_bgset(name)
@@ -46,11 +43,8 @@ class ReactionSystem(object):
self.add_bg_set_entity(e)
def is_in_background_set(self, entity):
"""Checks if the given name is valid wrt the background set="""
if entity in self.background_set:
return True
else:
return False
"""Checks if the given name is valid wrt the background set"""
return entity in self.background_set
def get_entity_id(self, name):
try:
@@ -106,7 +100,6 @@ class ReactionSystem(object):
self.init_contexts.append(integers)
def set_context_entities(self, entities):
for entity in entities:
entity_id = self.get_entity_id(entity)
self.context_entities.append(entity_id)
@@ -131,20 +124,36 @@ class ReactionSystem(object):
def show_reactions(self, soft=False):
print(C_MARK_INFO + " Reactions:")
if soft and len(self.reactions) > 50:
print(" -> there are more than 50 reactions (" +
str(len(self.reactions)) + ")")
print(
" -> there are more than 50 reactions ("
+ str(len(self.reactions))
+ ")"
)
else:
print(
" "*4 + "{0: ^35}{1: ^25}{2: ^15}".format("reactants", " inhibitors", " products"))
" " * 4
+ "{0: ^35}{1: ^25}{2: ^15}".format(
"reactants", " inhibitors", " products"
)
)
for reaction in self.reactions:
# print("\t( R={" + self.state_to_str(reaction[0]) + "}, I={" + self.state_to_str(reaction[1]) + "}, P={" + self.state_to_str(reaction[2]) + "} )")
print(" " + "- {0: ^35}{1: ^25}{2: ^15}".format("{ " + self.state_to_str(reaction[0]) + " }",
print(
" "
+ "- {0: ^35}{1: ^25}{2: ^15}".format(
"{ " + self.state_to_str(reaction[0]) + " }",
" { " + self.state_to_str(reaction[1]) + " }",
" { " + self.state_to_str(reaction[2]) + " }"))
" { " + self.state_to_str(reaction[2]) + " }",
)
)
def show_background_set(self):
print(
C_MARK_INFO + " Background set: {" + self.entities_names_set_to_str(self.background_set) + "}")
C_MARK_INFO
+ " Background set: {"
+ self.entities_names_set_to_str(self.background_set)
+ "}"
)
def show_initial_contexts(self):
if len(self.init_contexts) > 0:
@@ -155,10 +164,12 @@ class ReactionSystem(object):
def show_context_entities(self):
if len(self.context_entities) > 0:
print(
C_MARK_INFO + " Context entities: " + self.entities_ids_set_to_str(self.context_entities))
C_MARK_INFO
+ " Context entities: "
+ self.entities_ids_set_to_str(self.context_entities)
)
def show(self, soft=False):
self.show_background_set()
self.show_initial_contexts()
self.show_reactions(soft)
@@ -181,8 +192,7 @@ class ReactionSystem(object):
reactions_by_prod[prod_entity] = []
for reaction in self.reactions:
if prod_entity in reaction[2]:
reactions_by_prod[prod_entity].append(
[reaction[0], reaction[1]])
reactions_by_prod[prod_entity].append([reaction[0], reaction[1]])
# save in cache
self.reactions_by_prod = reactions_by_prod
@@ -200,4 +210,5 @@ class ReactionSystem(object):
print("Empty background set")
exit(1)
# EOF

View File

@@ -1,6 +1,4 @@
class ReactionSystemWithNetworkOfAutomata(object):
def __init__(self, reaction_system, context_automata):
self.rs = reaction_system
self.cas = context_automata
@@ -9,4 +7,5 @@ class ReactionSystemWithNetworkOfAutomata(object):
self.rs.show(soft)
self.cas.show()
# EOF

View File

@@ -1,10 +1,11 @@
from rs.reaction_system_with_concentrations import ReactionSystemWithConcentrations
from rs.reaction_system_with_concentrations_param import ReactionSystemWithConcentrationsParam
from rs.reaction_system_with_concentrations_param import (
ReactionSystemWithConcentrationsParam,
)
from rs.context_automaton_with_concentrations import ContextAutomatonWithConcentrations
class ReactionSystemWithAutomaton(object):
def __init__(self, reaction_system, context_automaton):
self.rs = reaction_system
self.ca = context_automaton
@@ -35,7 +36,6 @@ class ReactionSystemWithAutomaton(object):
pass
def get_ordinary_reaction_system_with_automaton(self):
if not self.is_with_concentrations():
raise RuntimeError("Not RS/CA with concentrations")

View File

@@ -5,9 +5,7 @@ from rs.reaction_system import ReactionSystem
class ReactionSystemWithConcentrations(ReactionSystem):
def __init__(self):
self.reactions = []
self.meta_reactions = dict()
self.permanent_entities = dict()
@@ -20,14 +18,13 @@ class ReactionSystemWithConcentrations(ReactionSystem):
def add_bg_set_entity(self, e):
name = ""
def_max_conc = -1
if type(e) is tuple and len(e) == 2:
if isinstance(e, tuple) and len(e) == 2:
name, def_max_conc = e
elif type(e) is str:
elif isinstance(e, str):
name = e
print("\nWARNING: no maximal concentration level specified for:", e, "\n")
else:
raise RuntimeError(
"Bad entity type when adding background set element")
raise RuntimeError("Bad entity type when adding background set element")
self.assume_not_in_bgset(name)
self.background_set.append(name)
@@ -41,7 +38,6 @@ class ReactionSystemWithConcentrations(ReactionSystem):
self.max_concentration = def_max_conc
def get_max_concentration_level(self, e):
if e in self.max_conc_per_ent:
return self.max_conc_per_ent[e]
else:
@@ -50,18 +46,10 @@ class ReactionSystemWithConcentrations(ReactionSystem):
def is_valid_entity_with_concentration(self, e):
"""Sanity check for entities with concentration"""
if type(e) is tuple:
if len(e) == 2 and type(e[1]) is int:
if isinstance(e, (tuple, list)) and len(e) == 2 and isinstance(e[1], int):
return True
if type(e) is list:
if len(e) == 2 and type(e[1]) is int:
return True
print("FATAL. Invalid entity+concentration: {:s}".format(e))
exit(1)
return False
raise RuntimeError("Invalid entity+concentration: " + repr(e))
def get_state_ids(self, state):
"""Returns entities of the given state without levels"""
@@ -69,8 +57,7 @@ class ReactionSystemWithConcentrations(ReactionSystem):
def has_non_zero_concentration(self, elem):
if elem[1] < 1:
raise RuntimeError(
"Unexpected concentration level in state: " + str(elem))
raise RuntimeError("Unexpected concentration level in state: " + str(elem))
def process_rip(self, R, I, P, ignore_empty_R=False):
"""Chcecks concentration levels and converts entities names into their ids"""
@@ -123,21 +110,25 @@ class ReactionSystemWithConcentrations(ReactionSystem):
"""Adds a macro/meta reaction for increasing the value of incr_entity"""
reactants, inhibitors, products = self.process_rip(
R, I, [], ignore_empty_R=True)
R, I, [], ignore_empty_R=True
)
incr_entity_id = self.get_entity_id(incr_entity)
self.meta_reactions.setdefault(incr_entity_id, [])
self.meta_reactions[incr_entity_id].append(
("inc", self.get_entity_id(incrementer), reactants, inhibitors))
("inc", self.get_entity_id(incrementer), reactants, inhibitors)
)
def add_reaction_dec(self, decr_entity, decrementer, R, I):
"""Adds a macro/meta reaction for decreasing the value of incr_entity"""
reactants, inhibitors, products = self.process_rip(
R, I, [], ignore_empty_R=True)
R, I, [], ignore_empty_R=True
)
decr_entity_id = self.get_entity_id(decr_entity)
self.meta_reactions.setdefault(decr_entity_id, [])
self.meta_reactions[decr_entity_id].append(
("dec", self.get_entity_id(decrementer), reactants, inhibitors))
("dec", self.get_entity_id(decrementer), reactants, inhibitors)
)
def add_permanency(self, ent, I):
"""Sets entity to be permanent unless it is inhibited"""
@@ -145,8 +136,7 @@ class ReactionSystemWithConcentrations(ReactionSystem):
ent_id = self.get_entity_id(ent)
if ent_id in self.permanent_entities:
raise RuntimeError(
"Permanency for {0} already defined.".format(ent))
raise RuntimeError("Permanency for {0} already defined.".format(ent))
inhibitors = self.process_rip([], I, [], ignore_empty_R=True)[1]
self.permanent_entities[ent_id] = inhibitors
@@ -177,31 +167,50 @@ class ReactionSystemWithConcentrations(ReactionSystem):
def show_background_set(self):
print(
C_MARK_INFO + " Background set: {" + self.entities_names_set_to_str(self.background_set) + "}")
C_MARK_INFO
+ " Background set: {"
+ self.entities_names_set_to_str(self.background_set)
+ "}"
)
def show_meta_reactions(self):
print(C_MARK_INFO + " Meta reactions:")
for param_ent, reactions in self.meta_reactions.items():
for r_type, command, reactants, inhibitors in reactions:
if r_type == "inc" or r_type == "dec":
print(" - [ Type=" + repr(r_type) + " Operand=( " + self.get_entity_name(param_ent) + " ) Command=( " + self.get_entity_name(
command) + " ) ] -- ( R={" + self.state_to_str(reactants) + "}, I={" + self.state_to_str(inhibitors) + "} )")
print(
" - [ Type="
+ repr(r_type)
+ " Operand=( "
+ self.get_entity_name(param_ent)
+ " ) Command=( "
+ self.get_entity_name(command)
+ " ) ] -- ( R={"
+ self.state_to_str(reactants)
+ "}, I={"
+ self.state_to_str(inhibitors)
+ "} )"
)
else:
raise RuntimeError(
"Unknown meta-reaction type: " + repr(r_type))
raise RuntimeError("Unknown meta-reaction type: " + repr(r_type))
def show_max_concentrations(self):
print(
C_MARK_INFO +
" Maximal allowed concentration levels (for optimized translation to RS):")
C_MARK_INFO
+ " Maximal allowed concentration levels (for optimized translation to RS):"
)
for e, max_conc in self.max_conc_per_ent.items():
print(" - {0:^20} = {1:<6}".format(self.get_entity_name(e), max_conc))
def show_permanent_entities(self):
print(C_MARK_INFO + " Permanent entities:")
for e, inhibitors in self.permanent_entities.items():
print(" - {0:^20}{1:<6}".format(self.get_entity_name(e) + ": ",
"I={" + self.state_to_str(inhibitors) + "}"))
print(
" - {0:^20}{1:<6}".format(
self.get_entity_name(e) + ": ",
"I={" + self.state_to_str(inhibitors) + "}",
)
)
def show(self, soft=False):
self.show_background_set()
@@ -220,8 +229,7 @@ class ReactionSystemWithConcentrations(ReactionSystem):
for reaction in self.reactions:
product_entities = [e for e, c in reaction[2]]
producible_entities = producible_entities.union(
set(product_entities))
producible_entities = producible_entities.union(set(product_entities))
reactions_by_prod = {}
@@ -242,18 +250,20 @@ class ReactionSystemWithConcentrations(ReactionSystem):
# we need to order the reactions w.r.t. the concentration levels produced (increasing order)
for i in range(0, len(rcts_for_p_e)):
checked_conc = rcts_for_p_e[i][2][0][1]
if prod_conc <= checked_conc:
insert_place = i
break
if insert_place == None: # empty or the is only one element which is smaller than the element being added
if (
insert_place == None
): # empty or the is only one element which is smaller than the element being added
# we append (to the end)
rcts_for_p_e.append((reactants, inhibitors, products))
else:
rcts_for_p_e.insert(
insert_place, (reactants, inhibitors, products))
insert_place, (reactants, inhibitors, products)
)
# save in cache
self.reactions_by_prod = reactions_by_prod
@@ -261,11 +271,9 @@ class ReactionSystemWithConcentrations(ReactionSystem):
return reactions_by_prod
def get_reaction_system(self):
rs = ReactionSystem()
for reactants, inhibitors, products in self.reactions:
new_reactants = []
new_inhibitors = []
new_products = []
@@ -281,7 +289,7 @@ class ReactionSystemWithConcentrations(ReactionSystem):
new_inhibitors.append(n)
for ent, conc in products:
for i in range(1, conc+1):
for i in range(1, conc + 1):
n = self.get_entity_name(ent) + "#" + str(i)
rs.ensure_bg_set_entity(n)
new_products.append(n)
@@ -290,7 +298,6 @@ class ReactionSystemWithConcentrations(ReactionSystem):
for param_ent, reactions in self.meta_reactions.items():
for r_type, command, reactants, inhibitors in reactions:
param_ent_name = self.get_entity_name(param_ent)
new_reactants = []
@@ -312,16 +319,15 @@ class ReactionSystemWithConcentrations(ReactionSystem):
else:
print(
"WARNING:\n\tThere is no maximal concentration level defined for "
+ self.get_entity_name(command))
+ self.get_entity_name(command)
)
print("\tThis is a very bad idea -- expect degraded performance\n")
for l in range(1, max_cmd_c+1):
for l in range(1, max_cmd_c + 1):
cmd_ent = self.get_entity_name(command) + "#" + str(l)
rs.ensure_bg_set_entity(cmd_ent)
if r_type == "inc":
# pre_conc -- predecessor concentration
# succ_conc -- successor concentration concentration
@@ -329,8 +335,8 @@ class ReactionSystemWithConcentrations(ReactionSystem):
pre_conc = param_ent_name + "#" + str(i)
rs.ensure_bg_set_entity(pre_conc)
new_products = []
succ_value = i+l
for j in range(1, succ_value+1):
succ_value = i + l
for j in range(1, succ_value + 1):
if j > self.max_concentration:
break
new_p = param_ent_name + "#" + str(j)
@@ -340,15 +346,16 @@ class ReactionSystemWithConcentrations(ReactionSystem):
rs.add_reaction(
set(new_reactants + [pre_conc, cmd_ent]),
set(new_inhibitors),
set(new_products))
set(new_products),
)
elif r_type == "dec":
for i in range(1, self.max_concentration+1):
for i in range(1, self.max_concentration + 1):
pre_conc = param_ent_name + "#" + str(i)
rs.ensure_bg_set_entity(pre_conc)
new_products = []
succ_value = i-l
for j in range(1, succ_value+1):
succ_value = i - l
for j in range(1, succ_value + 1):
if j > self.max_concentration:
break
new_p = param_ent_name + "#" + str(j)
@@ -358,28 +365,29 @@ class ReactionSystemWithConcentrations(ReactionSystem):
rs.add_reaction(
set(new_reactants + [pre_conc, cmd_ent]),
set(new_inhibitors),
set(new_products))
set(new_products),
)
else:
raise RuntimeError(
"Unknown meta-reaction type: " + repr(r_type))
"Unknown meta-reaction type: " + repr(r_type)
)
for ent, inhibitors in self.permanent_entities.items():
max_c = self.max_concentration
if ent in self.max_conc_per_ent:
max_c = self.max_conc_per_ent[ent]
else:
print(
"WARNING:\n\tThere is no maximal concentration level defined for "
+ self.get_entity_name(ent))
+ self.get_entity_name(ent)
)
print("\tThis is a very bad idea -- expect degraded performance\n")
def e_value(i):
return self.get_entity_name(ent) + "#" + str(i)
for value in range(1, max_c+1):
for value in range(1, max_c + 1):
new_reactants = []
new_inhibitors = []
new_products = []
@@ -391,7 +399,7 @@ class ReactionSystemWithConcentrations(ReactionSystem):
rs.ensure_bg_set_entity(n)
new_inhibitors.append(n)
for i in range(1, value+1):
for i in range(1, value + 1):
new_products.append(e_value(i))
rs.add_reaction(new_reactants, new_inhibitors, new_products)
@@ -399,35 +407,4 @@ class ReactionSystemWithConcentrations(ReactionSystem):
return rs
class ReactionSystemWithAutomaton(object):
def __init__(self, reaction_system, context_automaton):
self.rs = reaction_system
self.ca = context_automaton
def show(self, soft=False):
self.rs.show(soft)
self.ca.show()
def is_with_concentrations(self):
if not isinstance(self.rs, ReactionSystemWithConcentrations):
return False
if not isinstance(self.ca, ContextAutomatonWithConcentrations):
return False
return True
def sanity_check(self):
pass
def get_ordinary_reaction_system_with_automaton(self):
if not self.is_with_concentrations():
raise RuntimeError("Not RS/CA with concentrations")
ors = self.rs.get_reaction_system()
oca = self.ca.get_automaton_with_flat_contexts(ors)
return ReactionSystemWithAutomaton(ors, oca)
# EOF

View File

@@ -5,7 +5,6 @@ from rs.reaction_system import ReactionSystem
class ParameterObj(object):
def __init__(self, name):
self.name = name
@@ -21,9 +20,7 @@ def is_param(some_object):
class ReactionSystemWithConcentrationsParam(ReactionSystem):
def __init__(self):
self.reactions = []
self.parameters = dict()
self.meta_reactions = dict()
@@ -37,14 +34,13 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
def add_bg_set_entity(self, e):
name = ""
def_max_conc = -1
if type(e) is tuple and len(e) == 2:
if isinstance(e, tuple) and len(e) == 2:
name, def_max_conc = e
elif type(e) is str:
elif isinstance(e, str):
name = e
print("\nWARNING: no maximal concentration level specified for:", e, "\n")
else:
raise RuntimeError(
"Bad entity type when adding background set element")
raise RuntimeError("Bad entity type when adding background set element")
self.assume_not_in_bgset(name)
self.background_set.append(name)
@@ -76,7 +72,6 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
self.parameters[param_key].idx = len(self.parameters)
def get_max_concentration_level(self, e):
if e in self.max_conc_per_ent:
return self.max_conc_per_ent[e]
else:
@@ -85,18 +80,10 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
def is_valid_entity_with_concentration(self, e):
"""Sanity check for entities with concentration"""
if type(e) is tuple:
if len(e) == 2 and type(e[1]) is int:
if isinstance(e, (tuple, list)) and len(e) == 2 and isinstance(e[1], int):
return True
if type(e) is list:
if len(e) == 2 and type(e[1]) is int:
return True
print("FATAL. Invalid entity+concentration: {:s}".format(e))
exit(1)
return False
raise RuntimeError("Invalid entity+concentration: " + repr(e))
def is_valid_concentration_for_entity(self, entity, level):
"""Checks the concentration level for entity"""
@@ -113,7 +100,9 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
def terminate_on_invalid_concentration(self, entity, level):
if not self.is_valid_concentration_for_entity(entity, level):
print("FATAL. Invalid entity concentration: {:s}={:d}".format(entity, level))
print(
"FATAL. Invalid entity concentration: {:s}={:d}".format(entity, level)
)
exit(1)
def get_state_ids(self, state):
@@ -122,8 +111,7 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
def has_non_zero_concentration(self, elem):
if elem[1] < 1:
raise RuntimeError(
"Unexpected concentration level in state: " + str(elem))
raise RuntimeError("Unexpected concentration level in state: " + str(elem))
def process_rip(self, R, I, P, ignore_empty_R=False):
"""Chcecks concentration levels and converts entities names into their ids"""
@@ -207,21 +195,25 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
"""Adds a macro/meta reaction for increasing the value of incr_entity"""
reactants, inhibitors, products = self.process_rip(
R, I, [], ignore_empty_R=True)
R, I, [], ignore_empty_R=True
)
incr_entity_id = self.get_entity_id(incr_entity)
self.meta_reactions.setdefault(incr_entity_id, [])
self.meta_reactions[incr_entity_id].append(
("inc", self.get_entity_id(incrementer), reactants, inhibitors))
("inc", self.get_entity_id(incrementer), reactants, inhibitors)
)
def add_reaction_dec(self, decr_entity, decrementer, R, I):
"""Adds a macro/meta reaction for decreasing the value of incr_entity"""
reactants, inhibitors, products = self.process_rip(
R, I, [], ignore_empty_R=True)
R, I, [], ignore_empty_R=True
)
decr_entity_id = self.get_entity_id(decr_entity)
self.meta_reactions.setdefault(decr_entity_id, [])
self.meta_reactions[decr_entity_id].append(
("dec", self.get_entity_id(decrementer), reactants, inhibitors))
("dec", self.get_entity_id(decrementer), reactants, inhibitors)
)
def add_permanency(self, ent, I):
"""Sets entity to be permanent unless it is inhibited"""
@@ -229,8 +221,7 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
ent_id = self.get_entity_id(ent)
if ent_id in self.permanent_entities:
raise RuntimeError(
"Permanency for {0} already defined.".format(ent))
raise RuntimeError("Permanency for {0} already defined.".format(ent))
inhibitors = self.process_rip([], I, [], ignore_empty_R=True)[1]
self.permanent_entities[ent_id] = inhibitors
@@ -269,18 +260,32 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
def show_background_set(self):
print(
C_MARK_INFO + " Background set: {" + self.entities_names_set_to_str(self.background_set) + "}")
C_MARK_INFO
+ " Background set: {"
+ self.entities_names_set_to_str(self.background_set)
+ "}"
)
def show_meta_reactions(self):
print(C_MARK_INFO + " Meta reactions:")
for param_ent, reactions in self.meta_reactions.items():
for r_type, command, reactants, inhibitors in reactions:
if r_type == "inc" or r_type == "dec":
print(" - [ Type=" + repr(r_type) + " Operand=( " + self.get_entity_name(param_ent) + " ) Command=( " + self.get_entity_name(
command) + " ) ] -- ( R={" + self.state_to_str(reactants) + "}, I={" + self.state_to_str(inhibitors) + "} )")
print(
" - [ Type="
+ repr(r_type)
+ " Operand=( "
+ self.get_entity_name(param_ent)
+ " ) Command=( "
+ self.get_entity_name(command)
+ " ) ] -- ( R={"
+ self.state_to_str(reactants)
+ "}, I={"
+ self.state_to_str(inhibitors)
+ "} )"
)
else:
raise RuntimeError(
"Unknown meta-reaction type: " + repr(r_type))
raise RuntimeError("Unknown meta-reaction type: " + repr(r_type))
def show_max_concentrations(self):
print(C_MARK_INFO + " Maximal allowed concentration levels:")
@@ -290,8 +295,12 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
def show_permanent_entities(self):
print(C_MARK_INFO + " Permanent entities:")
for e, inhibitors in self.permanent_entities.items():
print(" - {0:^20}{1:<6}".format(self.get_entity_name(e) + ": ",
"I={" + self.state_to_str(inhibitors) + "}"))
print(
" - {0:^20}{1:<6}".format(
self.get_entity_name(e) + ": ",
"I={" + self.state_to_str(inhibitors) + "}",
)
)
def show(self, soft=False):
self.show_background_set()
@@ -311,8 +320,7 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
for reaction in self.reactions:
product_entities = [e for e, c in reaction[2] if c > 0]
producible_entities = producible_entities.union(
set(product_entities))
producible_entities = producible_entities.union(set(product_entities))
return producible_entities
@@ -324,7 +332,6 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
rs = ReactionSystem()
for reactants, inhibitors, products in self.reactions:
new_reactants = []
new_inhibitors = []
new_products = []
@@ -349,7 +356,6 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
for param_ent, reactions in self.meta_reactions.items():
for r_type, command, reactants, inhibitors in reactions:
param_ent_name = self.get_entity_name(param_ent)
new_reactants = []
@@ -371,16 +377,15 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
else:
print(
"WARNING:\n\tThere is no maximal concentration level defined for "
+ self.get_entity_name(command))
+ self.get_entity_name(command)
)
print("\tThis is a very bad idea -- expect degraded performance\n")
for l in range(1, max_cmd_c + 1):
cmd_ent = self.get_entity_name(command) + "#" + str(l)
rs.ensure_bg_set_entity(cmd_ent)
if r_type == "inc":
# pre_conc -- predecessor concentration
# succ_conc -- successor concentration concentration
@@ -399,7 +404,8 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
rs.add_reaction(
set(new_reactants + [pre_conc, cmd_ent]),
set(new_inhibitors),
set(new_products))
set(new_products),
)
elif r_type == "dec":
for i in range(1, self.max_concentration + 1):
@@ -417,28 +423,29 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
rs.add_reaction(
set(new_reactants + [pre_conc, cmd_ent]),
set(new_inhibitors),
set(new_products))
set(new_products),
)
else:
raise RuntimeError(
"Unknown meta-reaction type: " + repr(r_type))
"Unknown meta-reaction type: " + repr(r_type)
)
for ent, inhibitors in self.permanent_entities.items():
max_c = self.max_concentration
if ent in self.max_conc_per_ent:
max_c = self.max_conc_per_ent[ent]
else:
print(
"WARNING:\n\tThere is no maximal concentration level defined for "
+ self.get_entity_name(ent))
+ self.get_entity_name(ent)
)
print("\tThis is a very bad idea -- expect degraded performance\n")
def e_value(i):
return self.get_entity_name(ent) + "#" + str(i)
for value in range(1, max_c + 1):
new_reactants = []
new_inhibitors = []
new_products = []
@@ -457,4 +464,5 @@ class ReactionSystemWithConcentrationsParam(ReactionSystem):
return rs
# EOF

View File

@@ -1,12 +1,10 @@
from rs import *
from smt import *
import rs_examples
from logics import *
from rsltl_shortcuts import *
from itertools import chain, combinations
import sys
import resource
def powerset(iterable,N=None):

Some files were not shown because too many files have changed in this diff Show More