Compare commits
18 Commits
oncogenic_
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ae419e5e0e | |||
| f0019619b3 | |||
|
|
363446821e | ||
|
|
90c8e4f4c0 | ||
| fafe8dbe07 | |||
|
|
3237c2eae5 | ||
|
|
092fd94b56 | ||
|
|
f86316cdbd | ||
|
|
a864329883 | ||
|
|
48b4f1bb4d | ||
|
|
af26ca543b | ||
|
|
888ed4e68e | ||
|
|
a1fb5836a5 | ||
|
|
8be615b293 | ||
|
|
b4d58b94be | ||
|
|
33ca0fd6e9 | ||
|
|
632286ec7f | ||
|
|
98894fc6e1 |
112
.github/workflows/tests.yml
vendored
Normal file
112
.github/workflows/tests.yml
vendored
Normal 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
107
README.md
@@ -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
65
TESTING.md
Normal 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.
|
||||
103
examples/bdd/generators/gen_asm.py
Normal file
103
examples/bdd/generators/gen_asm.py
Normal file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generator for the Assembly-line (ASM) benchmark.
|
||||
|
||||
Produces a distributed reaction system modelling an assembly line
|
||||
where N sequential processes pass activation tokens. Each process
|
||||
cycles through entities a -> y,b -> c -> d, and the final process
|
||||
signals 'done'. Uses a context automaton for scheduling.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
|
||||
|
||||
OPTIONS = "options { use-context-automaton; make-progressive; };\n"
|
||||
|
||||
PROC_TEMPLATE = """
|
||||
proc{i} {{
|
||||
{{{{a}}, {{s}} -> {{y}}}};
|
||||
{{{{y}}, {{s}} -> {{y}}}};
|
||||
{{{{a}}, {{s}} -> {{b}}}};
|
||||
{{{{b}}, {{s}} -> {{c}}}};
|
||||
{{{{c}}, {{s}} -> {{d}}}};
|
||||
{{{{d,y}}, {{s}} -> {{dy}}}};
|
||||
}};
|
||||
"""
|
||||
|
||||
FINAL_PROC = """
|
||||
procFinal {
|
||||
{{done}, {s} -> {done}};
|
||||
};
|
||||
"""
|
||||
|
||||
CA_TEMPLATE = """
|
||||
context-automaton {{
|
||||
states {{ init, act }};
|
||||
init-state {{ init }};
|
||||
transitions {{
|
||||
{transitions}
|
||||
}};
|
||||
}};
|
||||
"""
|
||||
|
||||
PROPERTY_TEMPLATE = '\nrsctlk-property {{ {name} : {formula} }};\n'
|
||||
|
||||
|
||||
def generate(n):
|
||||
out = OPTIONS
|
||||
out += "\nreactions {\n"
|
||||
for i in range(1, n + 1):
|
||||
out += PROC_TEMPLATE.format(i=i)
|
||||
out += FINAL_PROC
|
||||
out += "};\n"
|
||||
|
||||
indent = 8 * " "
|
||||
transitions = ""
|
||||
|
||||
# init -> act: first process gets activated
|
||||
transitions += "{indent}{{ proc1={{a}} }}: init -> act;\n".format(indent=indent)
|
||||
|
||||
# act -> act: process stays idle (dy not produced)
|
||||
for i in range(1, n + 1):
|
||||
transitions += "{indent}{{ proc{i}={{}} }}: act -> act : ~proc{i}.dy;\n".format(
|
||||
indent=indent, i=i)
|
||||
|
||||
# act -> act: next process gets activated when previous produces 'dy'
|
||||
for i in range(2, n + 1):
|
||||
transitions += "{indent}{{ proc{i}={{a}} }}: act -> act : proc{prev}.dy;\n".format(
|
||||
indent=indent, i=i, prev=i - 1)
|
||||
|
||||
# act -> act: final process signals done when all have produced 'dy'
|
||||
all_dy = " AND ".join("proc{}.dy".format(i) for i in range(1, n + 1))
|
||||
transitions += "{indent}{{ procFinal={{done}} }}: act -> act : {guard};\n".format(
|
||||
indent=indent, guard=all_dy)
|
||||
|
||||
out += CA_TEMPLATE.format(transitions=transitions)
|
||||
|
||||
# f1: the assembly line eventually completes
|
||||
out += PROPERTY_TEMPLATE.format(name="f1", formula="EF( procFinal.done )")
|
||||
|
||||
# f2: last process knows its predecessor has produced 'y'
|
||||
f2 = "AG( proc{n}.d IMPLIES K[proc{n}]( proc{prev}.y ) )".format(n=n, prev=n - 1)
|
||||
out += PROPERTY_TEMPLATE.format(name="f2", formula=f2)
|
||||
|
||||
# x1: negation of f1 (sanity check -- should also hold)
|
||||
out += PROPERTY_TEMPLATE.format(name="x1", formula="EF( ~procFinal.done )")
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
parser.add_argument("n", type=int, help="number of processes (must be > 1)")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.n < 2:
|
||||
parser.error("number of processes must be > 1")
|
||||
|
||||
print(generate(args.n))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
301
examples/bdd/generators/gen_drs.py
Executable file
301
examples/bdd/generators/gen_drs.py
Executable 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()
|
||||
@@ -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])
|
||||
|
||||
assert n > 1, "number of proc must be > 1"
|
||||
|
||||
out = ""
|
||||
|
||||
out += OPTIONS_STR
|
||||
out += "reactions {\n"
|
||||
def generate(n):
|
||||
out = OPTIONS
|
||||
out += "\nreactions {\n"
|
||||
for i in range(n):
|
||||
out += PROC_STR.format(i)
|
||||
out += PROC_TEMPLATE.format(i=i)
|
||||
out += "};\n"
|
||||
|
||||
indent = 8 * " "
|
||||
transitions = ""
|
||||
|
||||
init_trans = 8*" " + "{ "
|
||||
# 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"
|
||||
|
||||
# green -> red: a process requests
|
||||
for i in range(n):
|
||||
init_trans += "proc{:d}={{out}} ".format(i)
|
||||
init_trans += "}: init -> green;\n"
|
||||
transitions += init_trans
|
||||
transitions += "{indent}{{ proc{i}={{allowed}} }}: green -> red : proc{i}.req;\n".format(
|
||||
indent=indent, i=i)
|
||||
|
||||
# green -> green: no requests pending
|
||||
no_req = conj("~proc{i}.req", range(n))
|
||||
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)
|
||||
transitions += "{indent}{{ proc{i}={{}} }}: green -> green : {guard};\n".format(
|
||||
indent=indent, i=i, guard=no_req)
|
||||
|
||||
# red -> green: a process leaves
|
||||
for i in range(n):
|
||||
transitions += "{:s}{{ proc{:d}={{}} }}: green -> green : {:s};\n".format(8*" ", i, no_req_cond)
|
||||
transitions += "{indent}{{ proc{i}={{}} }}: red -> green : proc{i}.leave;\n".format(
|
||||
indent=indent, i=i)
|
||||
|
||||
# red -> red: no process leaves
|
||||
no_leave = conj("~proc{i}.leave", range(n))
|
||||
for i in range(n):
|
||||
transitions += "{:s}{{ proc{:d}={{}} }}: red -> green : proc{:d}.leave;\n".format(8*" ", i, i)
|
||||
transitions += "{indent}{{ proc{i}={{}} }}: red -> red : {guard};\n".format(
|
||||
indent=indent, i=i, guard=no_leave)
|
||||
|
||||
no_leave_cond = "~proc0.leave"
|
||||
for i in range(1, n):
|
||||
no_leave_cond += " AND ~proc{:d}.leave".format(i)
|
||||
out += CA_TEMPLATE.format(transitions=transitions)
|
||||
|
||||
for i in range(n):
|
||||
transitions += "{:s}{{ proc{:d}={{}} }}: red -> red : {:s};\n".format(8*" ", i, no_leave_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)
|
||||
|
||||
out += CA_STR.format(transitions)
|
||||
# f2: all processes can simultaneously approach
|
||||
f2 = "EF( " + conj("proc{i}.approach", range(n)) + " )"
|
||||
out += PROPERTY_TEMPLATE.format(name="f2", formula=f2)
|
||||
|
||||
## f1
|
||||
#formula = "EF( proc0.in )"
|
||||
#out += PROPERTY_STR.format("f1",formula)
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
# 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)
|
||||
|
||||
# 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)
|
||||
return out
|
||||
|
||||
# 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)
|
||||
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()
|
||||
|
||||
print(out)
|
||||
if args.n < 2:
|
||||
parser.error("number of processes must be > 1")
|
||||
|
||||
print(generate(args.n))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
62
examples/bdd/generators/old_syntax/gen_abstract.py
Normal file
62
examples/bdd/generators/old_syntax/gen_abstract.py
Normal 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()
|
||||
88
examples/bdd/generators/old_syntax/gen_bc.py
Normal file
88
examples/bdd/generators/old_syntax/gen_bc.py
Normal 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()
|
||||
71
examples/bdd/generators/old_syntax/gen_mutex.py
Normal file
71
examples/bdd/generators/old_syntax/gen_mutex.py
Normal 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
70
examples/bdd/tgc4.drs
Normal 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
2
examples/smt/chain_reaction.py
Normal file → Executable 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()
|
||||
|
||||
|
||||
|
||||
19
examples/smt/heat_shock_response.py
Normal file → Executable file
19
examples/smt/heat_shock_response.py
Normal file → Executable file
@@ -28,7 +28,6 @@ import resource
|
||||
|
||||
|
||||
def heat_shock_response(print_system=True, verify_rsc=True):
|
||||
|
||||
if len(sys.argv) < 1 + 1:
|
||||
print("{source} <type>".format(source=sys.argv[0]))
|
||||
print("type:")
|
||||
@@ -62,15 +61,23 @@ def heat_shock_response(print_system=True, verify_rsc=True):
|
||||
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(
|
||||
[("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(
|
||||
[("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)], [], [("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(
|
||||
[("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)])
|
||||
@@ -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
7
examples/smt/mutex_param.py
Normal file → Executable 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)",
|
||||
)
|
||||
|
||||
|
||||
54
examples/smt/scalable_chain.py
Normal file → Executable file
54
examples/smt/scalable_chain.py
Normal file → Executable 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
|
||||
@@ -54,7 +55,11 @@ def generate_system(chainLen, maxConc):
|
||||
if i < chainLen:
|
||||
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")
|
||||
@@ -66,6 +71,7 @@ def generate_system(chainLen, maxConc):
|
||||
|
||||
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) )
|
||||
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,
|
||||
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
|
||||
@@ -116,12 +142,12 @@ def save_statistics(smt_rsc, formula_number, chainLen, maxConc):
|
||||
filename_m = "bench_rsc_F" + str(formula_number) + "_mem.log"
|
||||
time = smt_rsc.get_verification_time()
|
||||
|
||||
f=open(filename_t, 'a')
|
||||
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')
|
||||
f = open(filename_m, "a")
|
||||
log_str = "(" + str(chainLen) + "," + str(maxConc) + "," + str(mem_usage) + ")\n"
|
||||
f.write(log_str)
|
||||
f.close()
|
||||
@@ -168,6 +194,6 @@ def scalable_chain(print_system=False):
|
||||
def main():
|
||||
scalable_chain(print_system=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
97
experiments/drs_cell_signal/run.sh
Executable file
97
experiments/drs_cell_signal/run.sh
Executable 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
|
||||
454
experiments/reaction_mining_mutex/pmutex.py
Executable file
454
experiments/reaction_mining_mutex/pmutex.py
Executable 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
|
||||
26
experiments/reaction_mining_mutex/run_mutex_param.sh
Executable file
26
experiments/reaction_mining_mutex/run_mutex_param.sh
Executable 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
|
||||
|
||||
14
reactics
14
reactics
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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,6 +70,7 @@ 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;
|
||||
|
||||
@@ -82,6 +78,7 @@ void CtxAut::showStates(void)
|
||||
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 **/
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
913
reactics-bdd/export.cc
Normal 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 += "<";
|
||||
else if (ch =='>')
|
||||
fStr += ">";
|
||||
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
57
reactics-bdd/export.hh
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }"
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
BIN
reactics-gui/resources/help/img/ctx-automaton-edge-details.png
Normal file
BIN
reactics-gui/resources/help/img/ctx-automaton-edge-details.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.7 KiB |
BIN
reactics-gui/resources/help/img/ctx-automaton-panel.png
Normal file
BIN
reactics-gui/resources/help/img/ctx-automaton-panel.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
BIN
reactics-gui/resources/help/img/ctx-automaton-state.png
Normal file
BIN
reactics-gui/resources/help/img/ctx-automaton-state.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
321
reactics-gui/resources/help/index.html
Normal file
321
reactics-gui/resources/help/index.html
Normal 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>
|
||||
3
reactics-gui/src/META-INF/MANIFEST.MF
Normal file
3
reactics-gui/src/META-INF/MANIFEST.MF
Normal file
@@ -0,0 +1,3 @@
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: pl.umk.mat.martinp.reactics.ReacticsGUI
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
410
reactics-gui/src/pl/umk/mat/martinp/reactics/FormulaEditor.java
Normal file
410
reactics-gui/src/pl/umk/mat/martinp/reactics/FormulaEditor.java
Normal 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("<", "<").replaceAll(">", ">") +
|
||||
"</formula>";
|
||||
}
|
||||
}
|
||||
|
||||
125
reactics-gui/src/pl/umk/mat/martinp/reactics/HelpWindow.java
Normal file
125
reactics-gui/src/pl/umk/mat/martinp/reactics/HelpWindow.java
Normal 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);
|
||||
}
|
||||
}
|
||||
427
reactics-gui/src/pl/umk/mat/martinp/reactics/ProcessEditor.java
Normal file
427
reactics-gui/src/pl/umk/mat/martinp/reactics/ProcessEditor.java
Normal 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>");
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
791
reactics-gui/src/pl/umk/mat/martinp/reactics/ReacticsGUI.java
Normal file
791
reactics-gui/src/pl/umk/mat/martinp/reactics/ReacticsGUI.java
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 { }
|
||||
@@ -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
|
||||
|
||||
@@ -5,8 +5,8 @@ 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)]
|
||||
@@ -38,6 +38,7 @@ def ex():
|
||||
checker = SmtCheckerRSCParam(crprs, optimise=True)
|
||||
checker.check_rsltl(formulae_list=[f], param_constr=pc)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
ex()
|
||||
|
||||
|
||||
@@ -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:
|
||||
@@ -40,11 +43,13 @@ class BagDescription(object):
|
||||
for operand in (self.left_operand, self.right_operand):
|
||||
if operand:
|
||||
if not (
|
||||
isinstance(operand, BagDescription)
|
||||
or isinstance(operand, int)):
|
||||
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
|
||||
|
||||
@@ -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:
|
||||
@@ -42,16 +46,17 @@ class ParamConstraint(object):
|
||||
for operand in (self.left_operand, self.right_operand):
|
||||
if operand:
|
||||
if not (
|
||||
isinstance(operand, ParamConstraint)
|
||||
or isinstance(operand, int)):
|
||||
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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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))))
|
||||
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,
|
||||
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,
|
||||
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)
|
||||
@@ -269,20 +277,23 @@ class rsLTL_Encoder(object):
|
||||
# level == bound
|
||||
inner_enc = False
|
||||
for loop_level in range(1, bound + 1):
|
||||
inner_enc = simplify(Or(inner_enc,
|
||||
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:
|
||||
@@ -292,22 +303,22 @@ class rsLTL_Encoder(object):
|
||||
# level == bound
|
||||
inner_enc = False
|
||||
for loop_level in range(1, bound + 1):
|
||||
inner_enc = simplify(Or(inner_enc,
|
||||
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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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 = []
|
||||
@@ -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):
|
||||
|
||||
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
|
||||
|
||||
@@ -340,7 +346,8 @@ 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):
|
||||
@@ -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):
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user