├── .gitattributes
├── .github
└── workflows
│ ├── codeql-analysis.yml
│ └── python-app.yml
├── .gitignore
├── Benchmarking
├── Benchmark_ErrorStop.py
├── CompleteStochasticBenchmarking.py
├── StochasticAlgComparison.py
├── StochasticBenchmarkingWPrism.py
├── StopWithErorrRate.py
├── all_results.pickle
├── benchmark.py
├── benchmark_alphabet_increase.py
├── benchmark_size_increase.py
├── cex_processing_benchmark.py
├── compare_lstar_and_kv.py
├── deterministic_evaluation.PNG
├── error_benchmark_statistics.py
├── evaluate_l_star_configurations.py
├── fm_benchmark.py
├── fm_plots.py
├── generate_plots.py
├── json_lbt.py
├── papni_sequances.pickle
├── passive_mdp_vs_smm.py
├── passive_vpa_vs_rpni.py
├── prism_eval_props
│ ├── bluetooth.props
│ ├── emqtt_two_client.props
│ ├── first_eval.props
│ ├── second_eval.props
│ ├── shared_coin_eval.props
│ ├── slot_machine_eval.props
│ └── tcp_eval.props
├── rpni_papni_memory_footrpint.py
├── stochastic_benchmarking
│ ├── Benchmark_ErrorStop.py
│ ├── CompleteStochasticBenchmarking.py
│ ├── StochasticBenchmarkingWPrism.py
│ ├── passive_mdp_vs_smm.py
│ ├── plot_error_steps.py
│ ├── stochastic_benchmark_random_automata.py
│ ├── strategy_comp.py
│ └── unamb_error_plot.py
├── stochastic_evaluation.PNG
├── unamb_error_plot.py
└── vpa_benchmarking
│ └── benchmark_vpa.py
├── DotModels
├── Angluin_Mealy.dot
├── Angluin_Moore.dot
├── Bluetooth
│ ├── CC2640R2-no-feature-req.dot
│ ├── CC2640R2-no-feature-req_stochastic.dot
│ ├── CC2640R2-no-pairing-req.dot
│ ├── CC2650.dot
│ ├── CYBLE-416045-02.dot
│ ├── CYBLE-416045-02_Crash_No_Response_stochastic.dot
│ ├── CYW43455.dot
│ ├── CYW43455_stochastic.dot
│ ├── bluetooth_model.dot
│ ├── bluetooth_reduced.dot
│ ├── cc2652r1.dot
│ ├── convert_to_stochastic.py
│ └── nRF52832.dot
├── MDPs
│ ├── bluetooth.dot
│ ├── faulty_car_alarm.dot
│ ├── first_grid.dot
│ ├── mqtt.dot
│ ├── second_grid.dot
│ ├── shared_coin.dot
│ ├── slot_machine.dot
│ └── tcp.dot
├── MQTT
│ ├── ActiveMQ__two_client_will_retain.dot
│ ├── VerneMQ__two_client_will_retain.dot
│ ├── emqtt__two_client_will_retain.dot
│ ├── hbmqtt__two_client_will_retain.dot
│ └── mosquitto__two_client_will_retain.dot
├── TCP
│ ├── TCP_Linux_Client.dot
│ ├── tcp_server_bsd_trans.dot
│ ├── tcp_server_ubuntu_trans.dot
│ └── tcp_server_windows_trans.dot
├── TLS
│ ├── JSSE_1.8.0_25_server_regular.dot
│ ├── NSS_3.17.4_server_regular.dot
│ ├── OpenSSL_1.0.2_server_regular.dot
│ ├── RSA_BSAFE_C_4.0.4_server_regular.dot
│ └── miTLS_0.1.3_server_regular.dot
├── arithmetics.dot
├── car_alarm.dot
├── coffee_mealy.dot
├── coffee_moore.dot
├── five_clients_mqtt_abstracted_onfsm.dot
├── mooreModel.dot
├── onfsm_0.dot
├── onfsm_1.dot
├── onfsm_2.dot
├── onfsm_3.dot
├── onfsm_4.dot
├── onfsm_5.dot
└── tomitaGrammars
│ ├── tomita_1.dot
│ ├── tomita_2.dot
│ ├── tomita_3.dot
│ ├── tomita_4.dot
│ ├── tomita_5.dot
│ ├── tomita_6.dot
│ └── tomita_7.dot
├── Examples.py
├── LICENCE.txt
├── README.md
├── aalpy
├── SULs
│ ├── AutomataSUL.py
│ ├── PyMethodSUL.py
│ ├── RegexSUL.py
│ ├── TomitaSUL.py
│ └── __init__.py
├── __init__.py
├── automata
│ ├── Dfa.py
│ ├── MarkovChain.py
│ ├── Mdp.py
│ ├── MealyMachine.py
│ ├── MooreMachine.py
│ ├── NonDeterministicMooreMachine.py
│ ├── Onfsm.py
│ ├── Sevpa.py
│ ├── StochasticMealyMachine.py
│ ├── Vpa.py
│ └── __init__.py
├── base
│ ├── Automaton.py
│ ├── CacheTree.py
│ ├── Oracle.py
│ ├── SUL.py
│ └── __init__.py
├── learning_algs
│ ├── __init__.py
│ ├── adaptive
│ │ ├── AdaptiveLSharp.py
│ │ ├── AdaptiveObservationTree.py
│ │ ├── StateMatching.py
│ │ └── __init__.py
│ ├── deterministic
│ │ ├── ADS.py
│ │ ├── Apartness.py
│ │ ├── ClassificationTree.py
│ │ ├── CounterExampleProcessing.py
│ │ ├── KV.py
│ │ ├── LSharp.py
│ │ ├── LStar.py
│ │ ├── ObservationTable.py
│ │ ├── ObservationTree.py
│ │ └── __init__.py
│ ├── deterministic_passive
│ │ ├── ClassicRPNI.py
│ │ ├── GsmRPNI.py
│ │ ├── RPNI.py
│ │ ├── __init__.py
│ │ ├── active_RPNI.py
│ │ └── rpni_helper_functions.py
│ ├── general_passive
│ │ ├── GeneralizedStateMerging.py
│ │ ├── GsmAlgorithms.py
│ │ ├── GsmNode.py
│ │ ├── Instrumentation.py
│ │ ├── ScoreFunctionsGSM.py
│ │ └── __init__.py
│ ├── non_deterministic
│ │ ├── AbstractedOnfsmLstar.py
│ │ ├── AbstractedOnfsmObservationTable.py
│ │ ├── NonDeterministicSULWrapper.py
│ │ ├── OnfsmLstar.py
│ │ ├── OnfsmObservationTable.py
│ │ ├── TraceTree.py
│ │ └── __init__.py
│ ├── stochastic
│ │ ├── DifferenceChecker.py
│ │ ├── SamplingBasedObservationTable.py
│ │ ├── StochasticCexProcessing.py
│ │ ├── StochasticLStar.py
│ │ ├── StochasticTeacher.py
│ │ └── __init__.py
│ └── stochastic_passive
│ │ ├── ActiveAleriga.py
│ │ ├── Alergia.py
│ │ ├── CompatibilityChecker.py
│ │ ├── FPTA.py
│ │ └── __init__.py
├── oracles
│ ├── BreadthFirstExplorationEqOracle.py
│ ├── CacheBasedEqOracle.py
│ ├── PacOracle.py
│ ├── PerfectKnowledgeEqOracle.py
│ ├── ProvidedSequencesOracleWrapper.py
│ ├── RandomWalkEqOracle.py
│ ├── RandomWordEqOracle.py
│ ├── StatePrefixEqOracle.py
│ ├── TransitionFocusOracle.py
│ ├── UserInputEqOracle.py
│ ├── WMethodEqOracle.py
│ ├── WpMethodEqOracle.py
│ ├── __init__.py
│ ├── kWayStateCoverageEqOracle.py
│ └── kWayTransitionCoverageEqOracle.py
├── paths.py
└── utils
│ ├── AutomatonGenerators.py
│ ├── BenchmarkSULs.py
│ ├── BenchmarkSevpaModels.py
│ ├── BenchmarkVpaModels.py
│ ├── DataHandler.py
│ ├── FileHandler.py
│ ├── HelperFunctions.py
│ ├── ModelChecking.py
│ ├── Sampling.py
│ └── __init__.py
├── docs
├── README.md
├── _config.yml
├── arithmeticSevpa.PNG
├── google306875680a34d740.html
├── instructions.txt
├── logo_dark.png
├── logo_dark_cent.png
├── logo_light.png
├── logo_light_cent.png
├── mqtt_example.PNG
├── passiveLearning.png
└── regex_example_wiki.png
├── jAlergia
├── alergia.jar
└── exampleMdpData.txt
├── notebooks
├── Abstracted_Non-Det_FSM.ipynb
├── AngluinExample.ipynb
├── MDP_Example.ipynb
├── MDP_and_SMM_Example.ipynb
├── ONFSM_Example.ipynb
├── RandomMealyExample.ipynb
├── RegexExample.ipynb
└── Stochstic_Examples.ipynb
├── setup.py
└── tests
├── oracles
├── test_baseOracle.py
└── test_kWayTransitionCoverageEqOracle.py
├── test_charSet.py
├── test_deterministic.py
├── test_file_operations.py
├── test_non_deterministic.py
├── test_rwpmethod_oracle.py
├── test_stochastic.py
├── test_wmethod_oracle.py
├── test_wpmethod_oracle.py
└── tests_imports.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | * linguist-vendored
2 | *.py linguist-vendored=false
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ master ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ master ]
20 | schedule:
21 | - cron: '17 10 * * 6'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'python' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
37 | # Learn more:
38 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
39 |
40 | steps:
41 | - name: Checkout repository
42 | uses: actions/checkout@v2
43 |
44 | # Initializes the CodeQL tools for scanning.
45 | - name: Initialize CodeQL
46 | uses: github/codeql-action/init@v1
47 | with:
48 | languages: ${{ matrix.language }}
49 | # If you wish to specify custom queries, you can do so here or in a config file.
50 | # By default, queries listed here will override any specified in a config file.
51 | # Prefix the list here with "+" to use these queries and those in the config file.
52 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
53 |
54 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
55 | # If this step fails, then you should remove it and run the build manually (see below)
56 | - name: Autobuild
57 | uses: github/codeql-action/autobuild@v1
58 |
59 | # ℹ️ Command-line programs to run using the OS shell.
60 | # 📚 https://git.io/JvXDl
61 |
62 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
63 | # and modify them (or add more) to build your code if your project
64 | # uses a compiled language
65 |
66 | #- run: |
67 | # make bootstrap
68 | # make release
69 |
70 | - name: Perform CodeQL Analysis
71 | uses: github/codeql-action/analyze@v1
72 |
--------------------------------------------------------------------------------
/.github/workflows/python-app.yml:
--------------------------------------------------------------------------------
1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3 |
4 | name: Python application
5 |
6 | on:
7 | push:
8 | branches: [ master ]
9 | pull_request:
10 | branches: [ master ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Set up Python 3.9
20 | uses: actions/setup-python@v2
21 | with:
22 | python-version: 3.9
23 | - name: Install dependencies
24 | run: |
25 | python -m pip install --upgrade pip
26 | pip install flake8 pytest
27 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
28 | - name: Lint with flake8
29 | run: |
30 | # stop the build if there are Python syntax errors or undefined names
31 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
32 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
33 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
34 |
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | main.py
10 | LearnedModel.pdf
11 |
12 | # Distribution / packaging
13 | .Python
14 | build/
15 | develop-eggs/
16 | dist/
17 | downloads/
18 | eggs/
19 | .eggs/
20 | lib/
21 | lib64/
22 | parts/
23 | sdist/
24 | var/
25 | wheels/
26 | pip-wheel-metadata/
27 | share/python-wheels/
28 | *.egg-info/
29 | .installed.cfg
30 | *.egg
31 | MANIFEST
32 |
33 | # PyInstaller
34 | # Usually these files are written by a python script from a template
35 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
36 | *.manifest
37 | *.spec
38 |
39 | # Installer logs
40 | pip-log.txt
41 | pip-delete-this-directory.txt
42 |
43 | # Unit test / coverage reports
44 | htmlcov/
45 | .tox/
46 | .nox/
47 | .coverage
48 | .coverage.*
49 | .cache
50 | nosetests.xml
51 | coverage.xml
52 | *.cover
53 | *.py,cover
54 | .hypothesis/
55 | .pytest_cache/
56 |
57 | # Translations
58 | *.mo
59 | *.pot
60 |
61 | # Django stuff:
62 | *.log
63 | local_settings.py
64 | db.sqlite3
65 | db.sqlite3-journal
66 |
67 | # Flask stuff:
68 | instance/
69 | .webassets-cache
70 |
71 | # Scrapy stuff:
72 | .scrapy
73 |
74 | # Sphinx documentation
75 | docs/_build/
76 |
77 | # PyBuilder
78 | target/
79 |
80 | # Jupyter Notebook
81 | .ipynb_checkpoints
82 |
83 | # IPython
84 | profile_default/
85 | ipython_config.py
86 |
87 | # pyenv
88 | .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
98 | __pypackages__/
99 |
100 | # Celery stuff
101 | celerybeat-schedule
102 | celerybeat.pid
103 |
104 | # SageMath parsed files
105 | *.sage.py
106 |
107 | # Environments
108 | .env
109 | .venv
110 | env/
111 | venv/
112 | ENV/
113 | env.bak/
114 | venv.bak/
115 |
116 | # Spyder project settings
117 | .spyderproject
118 | .spyproject
119 |
120 | # Rope project settings
121 | .ropeproject
122 |
123 | # mkdocs documentation
124 | /site
125 |
126 | # mypy
127 | .mypy_cache/
128 | .dmypy.json
129 | dmypy.json
130 |
131 | # Pyre type checker
132 | .pyre/
133 | .vscode/settings.json
134 |
135 | # PyCharm
136 | .idea/
--------------------------------------------------------------------------------
/Benchmarking/StochasticAlgComparison.py:
--------------------------------------------------------------------------------
1 | import random
2 | import time
3 | from statistics import mean
4 |
5 | import aalpy.paths
6 |
7 | from aalpy.SULs import AutomatonSUL
8 | from aalpy.learning_algs import run_stochastic_Lstar, run_Alergia
9 | from aalpy.oracles.RandomWordEqOracle import RandomWordEqOracle
10 | from aalpy.utils import load_automaton_from_file, get_properties_file, get_correct_prop_values
11 | from aalpy.utils import model_check_experiment
12 | from aalpy.automata.StochasticMealyMachine import smm_to_mdp_conversion
13 |
14 | path_to_dir = '../DotModels/MDPs/'
15 | files = ['first_grid.dot', 'second_grid.dot', 'slot_machine.dot', 'mqtt.dot', 'tcp.dot', 'bluetooth.dot'] #
16 |
17 | prop_folder = 'prism_eval_props/'
18 |
19 | aalpy.paths.path_to_prism = "C:/Program Files/prism-4.6/bin/prism.bat"
20 | aalpy.paths.path_to_properties = "prism_eval_props/"
21 |
22 | model_dict = {m.split('.')[0]: load_automaton_from_file(path_to_dir + m, automaton_type='mdp') for m in files}
23 |
24 | for file in files:
25 | print(file)
26 |
27 | exp_name = file.split('.')[0]
28 |
29 | print('--------------------------------------------------')
30 | print('Experiment:', exp_name)
31 |
32 | original_mdp = model_dict[exp_name]
33 | input_alphabet = original_mdp.get_input_alphabet()
34 |
35 | mdp_sul = AutomatonSUL(original_mdp)
36 |
37 | eq_oracle = RandomWordEqOracle(input_alphabet, mdp_sul, num_walks=500, min_walk_len=5,
38 | max_walk_len=16, reset_after_cex=True)
39 |
40 | learned_classic_mdp, data_mdp = run_stochastic_Lstar(input_alphabet, mdp_sul, eq_oracle, automaton_type='mdp',
41 | min_rounds=10, strategy='classic', n_c=20, n_resample=2000,
42 | stopping_range_dict={},
43 | max_rounds=200, return_data=True, target_unambiguity=0.98,
44 | print_level=1)
45 |
46 | del mdp_sul
47 | del eq_oracle
48 |
49 | mdp_sul = AutomatonSUL(original_mdp)
50 |
51 | eq_oracle = RandomWordEqOracle(input_alphabet, mdp_sul, num_walks=150, min_walk_len=5,
52 | max_walk_len=15, reset_after_cex=True)
53 |
54 | learned_smm, data_smm = run_stochastic_Lstar(input_alphabet, mdp_sul, eq_oracle, automaton_type='smm',
55 | min_rounds=10, strategy='normal',
56 | max_rounds=200, return_data=True, target_unambiguity=0.98,
57 | print_level=1)
58 |
59 | smm_2_mdp = smm_to_mdp_conversion(learned_smm)
60 |
61 | mdp_results, mdp_err = model_check_experiment(get_properties_file(exp_name),
62 | get_correct_prop_values(exp_name), learned_classic_mdp)
63 | smm_results, smm_err = model_check_experiment(get_properties_file(exp_name),
64 | get_correct_prop_values(exp_name), smm_2_mdp)
65 |
66 | num_alergia_samples = max([data_mdp["queries_learning"] + data_mdp["queries_eq_oracle"],
67 | data_smm["queries_learning"] + data_smm["queries_eq_oracle"]])
68 |
69 | alergia_samples = []
70 | for _ in range(num_alergia_samples):
71 | sample = [mdp_sul.pre()]
72 | for _ in range(random.randint(10, 30)):
73 | action = random.choice(input_alphabet)
74 | output = mdp_sul.step(action)
75 | sample.append((action, output))
76 | alergia_samples.append(sample)
77 |
78 | alergia_model = run_Alergia(alergia_samples, automaton_type='mdp')
79 |
80 | alergia_results, alergia_error = model_check_experiment(get_properties_file(exp_name),
81 | get_correct_prop_values(exp_name), alergia_model)
82 |
83 | print('Classic MDP learning', mean(mdp_err.values()), mdp_err)
84 | print('SMM learning', mean(smm_err.values()), smm_err)
85 | print('Alergia learning', mean(alergia_error.values()), alergia_error)
86 |
87 | print('Classic MDP traces', data_mdp["queries_learning"] + data_mdp["queries_eq_oracle"])
88 | print('SMM learning traces', data_smm["queries_learning"] + data_smm["queries_eq_oracle"])
--------------------------------------------------------------------------------
/Benchmarking/StopWithErorrRate.py:
--------------------------------------------------------------------------------
1 | import pickle
2 | import random
3 | import time
4 | from collections import defaultdict
5 | from statistics import mean
6 |
7 | import aalpy.paths
8 |
9 | from aalpy.SULs import AutomatonSUL
10 | from aalpy.learning_algs import run_stochastic_Lstar, run_Alergia
11 | from aalpy.oracles.RandomWordEqOracle import RandomWordEqOracle
12 | from aalpy.utils import load_automaton_from_file, get_properties_file, get_correct_prop_values, model_check_properties
13 | from aalpy.utils import model_check_experiment
14 | from aalpy.automata.StochasticMealyMachine import smm_to_mdp_conversion
15 |
16 | path_to_dir = '../DotModels/MDPs/'
17 | files = ['slot_machine.dot', 'bluetooth.dot'] #
18 | files = ['first_grid.dot', 'second_grid.dot', 'tcp.dot', 'mqtt.dot', 'bluetooth.dot', 'slot_machine.dot']
19 |
20 | prop_folder = 'prism_eval_props/'
21 |
22 | aalpy.paths.path_to_prism = "C:/Program Files/prism-4.6/bin/prism.bat"
23 | aalpy.paths.path_to_properties = "prism_eval_props/"
24 |
25 | model_dict = {m.split('.')[0]: load_automaton_from_file(path_to_dir + m, automaton_type='mdp') for m in files}
26 |
27 | model_type = ['smm']
28 | cex_processing = [None, 'longest_prefix', 'rs']
29 | # model_type.reverse()
30 |
31 | res = defaultdict(list)
32 |
33 | # for file in files:
34 | # for mt in model_type:
35 | # for cp in cex_processing:
36 | # for _ in range(4):
37 | #
38 | # exp_name = file.split('.')[0]
39 | #
40 | # print('--------------------------------------------------')
41 | # print('Experiment:', exp_name, cp)
42 | #
43 | # original_mdp = model_dict[exp_name]
44 | # input_alphabet = original_mdp.get_input_alphabet()
45 | #
46 | # mdp_sul = AutomatonSUL(original_mdp)
47 | #
48 | # eq_oracle = RandomWordEqOracle(input_alphabet, mdp_sul, num_walks=500, min_walk_len=5,
49 | # max_walk_len=15, reset_after_cex=True)
50 | #
51 | # pbs = ((get_properties_file(exp_name),
52 | # get_correct_prop_values(exp_name), 0.02 if exp_name != 'bluetooth' else 0.03))
53 | # learned_classic_mdp, data_mdp = run_stochastic_Lstar(input_alphabet, mdp_sul, eq_oracle, automaton_type=mt,
54 | # min_rounds=10,
55 | # #property_based_stopping=pbs,
56 | # cex_processing=cp,
57 | # samples_cex_strategy=None,
58 | # return_data=True, target_unambiguity=0.98,
59 | # print_level=1)
60 | #
61 | # res[exp_name].append((cp, data_mdp['queries_learning'] + data_mdp['queries_eq_oracle']))
62 |
63 | # with open('cex_processing_res.pickle', 'wb') as handle:
64 | # pickle.dump(res, handle, protocol=pickle.HIGHEST_PROTOCOL)
65 |
66 | with open('cex_processing_res.pickle', 'rb') as handle:
67 | res = pickle.load(handle)
68 |
69 | for key, val in res.items():
70 | print(key)
71 | sorted_by_cp = defaultdict(list)
72 | for cp, data in val:
73 | sorted_by_cp[cp].append(data)
74 |
75 | for cp_method, data in sorted_by_cp.items():
76 | print(cp_method)
77 | print(mean(data), min(data), max(data))
--------------------------------------------------------------------------------
/Benchmarking/all_results.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DES-Lab/AALpy/177862fb505df3f92a945861ceb1977962327327/Benchmarking/all_results.pickle
--------------------------------------------------------------------------------
/Benchmarking/benchmark.py:
--------------------------------------------------------------------------------
1 | import os
2 | from statistics import mean
3 |
4 | from aalpy.SULs import AutomatonSUL
5 | from aalpy.learning_algs import run_Lstar
6 | from aalpy.oracles import StatePrefixEqOracle
7 | from aalpy.utils import load_automaton_from_file
8 |
9 | dfa_1000_states_20_inputs = '../DotModels/DFA_1000_states_20_inp'
10 | dfa_2000_states_10_inputs = '../DotModels/DFA_2000_states_10_inp'
11 | moore_1000_states_20_inputs = '../DotModels/Moore_1000_states_20_inp_out'
12 | moore_2000_states_10_inputs = '../DotModels/Moore_2000_states_10_inp_out'
13 | run_times = []
14 |
15 | # change on which folder to perform experiments
16 | exp = dfa_2000_states_10_inputs
17 |
18 | benchmarks = os.listdir(exp)
19 | benchmarks = benchmarks[:10]
20 |
21 | caching_opt = [True, False]
22 | closing_options = ['shortest_first', 'longest_first', 'single']
23 | suffix_processing = ['all', 'single']
24 | counter_example_processing = ['rs', 'longest_prefix', None]
25 | e_closedness = ['prefix', 'suffix']
26 |
27 | for b in benchmarks:
28 | automaton = load_automaton_from_file(f'{exp}/{b}', automaton_type='dfa')
29 | input_al = automaton.get_input_alphabet()
30 |
31 | sul_dfa = AutomatonSUL(automaton)
32 |
33 | state_origin_eq_oracle = StatePrefixEqOracle(input_al, sul_dfa, walks_per_state=5, walk_len=25)
34 |
35 | learned_dfa, data = run_Lstar(input_al, sul_dfa, state_origin_eq_oracle, automaton_type='dfa',
36 | cache_and_non_det_check=False, cex_processing='rs', return_data=True, print_level=0)
37 | run_times.append(data['total_time'])
38 |
39 | print(run_times)
40 | print(mean(run_times))
41 |
--------------------------------------------------------------------------------
/Benchmarking/benchmark_alphabet_increase.py:
--------------------------------------------------------------------------------
1 | from statistics import mean
2 | import csv
3 |
4 | from aalpy.SULs import AutomatonSUL
5 | from aalpy.learning_algs import run_Lstar
6 | from aalpy.oracles import RandomWalkEqOracle
7 | from aalpy.utils import generate_random_dfa, generate_random_mealy_machine, generate_random_moore_machine
8 |
9 | num_states = 1000
10 | alph_size = 5
11 |
12 | repeat = 10
13 | num_increases = 20
14 |
15 | states = ['alph_size', alph_size]
16 | times_dfa = ['dfa_pypy_rs']
17 | times_mealy = ['mealy_pypy_rs']
18 | times_moore = ['moore_pypyrs']
19 |
20 | cex_processing = 'rs'
21 | for i in range(num_increases):
22 | print(i)
23 | total_time_dfa = []
24 | total_time_mealy = []
25 | total_time_moore = []
26 |
27 | for _ in range(repeat):
28 | alphabet = list(range(alph_size))
29 |
30 | dfa = generate_random_dfa(num_states, alphabet=alphabet, num_accepting_states=num_states // 2)
31 | sul = AutomatonSUL(dfa)
32 |
33 | # eq_oracle = StatePrefixEqOracle(alphabet, sul, walks_per_state=5, walk_len=40)
34 | eq_oracle = RandomWalkEqOracle(alphabet, sul, num_steps=10000, reset_prob=0.09)
35 |
36 | _, data = run_Lstar(alphabet, sul, eq_oracle, cex_processing=cex_processing, cache_and_non_det_check=False,
37 | return_data=True, automaton_type='dfa')
38 |
39 | total_time_dfa.append(data['learning_time'])
40 | del dfa
41 | del sul
42 | del eq_oracle
43 |
44 | mealy = generate_random_mealy_machine(num_states, input_alphabet=alphabet, output_alphabet=alphabet)
45 | sul_mealy = AutomatonSUL(mealy)
46 |
47 | # eq_oracle = StatePrefixEqOracle(alphabet, sul_mealy, walks_per_state=5, walk_len=40)
48 | eq_oracle = RandomWalkEqOracle(alphabet, sul_mealy, num_steps=10000, reset_prob=0.09)
49 |
50 | _, data = run_Lstar(alphabet, sul_mealy, eq_oracle, cex_processing=cex_processing,
51 | cache_and_non_det_check=False,
52 | return_data=True, automaton_type='mealy')
53 |
54 | total_time_mealy.append(data['learning_time'])
55 |
56 | del mealy
57 | del sul_mealy
58 | del eq_oracle
59 |
60 | moore = generate_random_moore_machine(num_states, input_alphabet=alphabet, output_alphabet=alphabet)
61 | moore_sul = AutomatonSUL(moore)
62 |
63 | # eq_oracle = StatePrefixEqOracle(alphabet, moore_sul, walks_per_state=5, walk_len=40)
64 | eq_oracle = RandomWalkEqOracle(alphabet, moore_sul, num_steps=10000, reset_prob=0.09)
65 |
66 | _, data = run_Lstar(alphabet, moore_sul, eq_oracle, cex_processing=cex_processing,
67 | cache_and_non_det_check=False,
68 | return_data=True, automaton_type='moore')
69 |
70 | total_time_moore.append(data['learning_time'])
71 |
72 | alph_size += 5
73 | states.append(alph_size)
74 |
75 | # save data and keep averages
76 | times_dfa.append(round(mean(total_time_dfa), 4))
77 | times_mealy.append(round(mean(total_time_mealy), 4))
78 | times_moore.append(round(mean(total_time_moore), 4))
79 |
80 | with open('increasing_alphabet_experiments.csv', 'w') as f:
81 | wr = csv.writer(f, dialect='excel')
82 | wr.writerow(states)
83 | wr.writerow(times_dfa)
84 | wr.writerow(times_mealy)
85 | wr.writerow(times_moore)
86 |
--------------------------------------------------------------------------------
/Benchmarking/benchmark_size_increase.py:
--------------------------------------------------------------------------------
1 | from statistics import mean
2 | import csv
3 |
4 | from aalpy.SULs import AutomatonSUL
5 | from aalpy.learning_algs import run_Lstar
6 | from aalpy.oracles import RandomWalkEqOracle
7 | from aalpy.utils import generate_random_dfa, generate_random_mealy_machine, generate_random_moore_machine
8 |
9 | num_states = 100
10 | alphabet = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
11 |
12 | repeat = 15
13 | num_increases = 50
14 |
15 | states = ['num_states']
16 | times_dfa = ['dfa_pypy_rs']
17 | times_mealy = ['mealy_pypy_rs']
18 | times_moore = ['moore_pypyrs']
19 | total_dfa = ['dfa_total']
20 | total_mealy = ['mealy_total']
21 | total__moore = ['moore_total']
22 |
23 | cex_processing = 'rs'
24 | for i in range(num_increases):
25 | print(i)
26 | learning_time_dfa = []
27 | learning_time_mealy = []
28 | learning_time_moore = []
29 |
30 | total_time_dfa = []
31 | total_time_mealy = []
32 | total_time_moore = []
33 |
34 | states.append(num_states)
35 |
36 | for _ in range(repeat):
37 | dfa = generate_random_dfa(num_states, alphabet=alphabet, num_accepting_states=num_states // 2)
38 | sul = AutomatonSUL(dfa)
39 |
40 | # eq_oracle = StatePrefixEqOracle(alphabet, sul, walks_per_state=5, walk_len=40)
41 | eq_oracle = RandomWalkEqOracle(alphabet, sul, num_steps=9000, reset_prob=0.09)
42 |
43 | _, data = run_Lstar(alphabet, sul, eq_oracle, cex_processing=cex_processing, cache_and_non_det_check=False,
44 | return_data=True, automaton_type='dfa')
45 |
46 | learning_time_dfa.append(data['learning_time'])
47 | total_time_dfa.append(data['total_time'])
48 |
49 | del sul
50 | del eq_oracle
51 | del dfa
52 |
53 | mealy = generate_random_mealy_machine(num_states, input_alphabet=alphabet, output_alphabet=alphabet)
54 | sul_mealy = AutomatonSUL(mealy)
55 |
56 | # eq_oracle = StatePrefixEqOracle(alphabet, sul_mealy, walks_per_state=5, walk_len=40)
57 | eq_oracle = RandomWalkEqOracle(alphabet, sul_mealy, num_steps=9000, reset_prob=0.09)
58 |
59 | _, data = run_Lstar(alphabet, sul_mealy, eq_oracle, cex_processing=cex_processing,
60 | cache_and_non_det_check=False,
61 | return_data=True, automaton_type='mealy')
62 |
63 | learning_time_mealy.append(data['learning_time'])
64 | total_time_mealy.append(data['total_time'])
65 |
66 | del mealy
67 | del sul_mealy
68 | del eq_oracle
69 |
70 | moore = generate_random_moore_machine(num_states, input_alphabet=alphabet, output_alphabet=alphabet)
71 | moore_sul = AutomatonSUL(moore)
72 |
73 | # eq_oracle = StatePrefixEqOracle(alphabet, moore_sul, walks_per_state=5, walk_len=40)
74 | eq_oracle = RandomWalkEqOracle(alphabet, moore_sul, num_steps=9000, reset_prob=0.09)
75 |
76 | _, data = run_Lstar(alphabet, moore_sul, eq_oracle, cex_processing=cex_processing,
77 | cache_and_non_det_check=False,
78 | return_data=True, automaton_type='moore')
79 |
80 | learning_time_moore.append(data['learning_time'])
81 | total_time_moore.append(data['total_time'])
82 |
83 | # save data and keep averages
84 | times_dfa.append(round(mean(learning_time_dfa), 4))
85 | times_mealy.append(round(mean(learning_time_mealy), 4))
86 | times_moore.append(round(mean(learning_time_moore), 4))
87 |
88 | total_dfa.append(round(mean(total_time_dfa), 4))
89 | total_mealy.append(round(mean(total_time_mealy), 4))
90 | total__moore.append(round(mean(total_time_moore), 4))
91 |
92 | num_states += 100
93 |
94 | with open('increasing_size_experiments.csv', 'w') as f:
95 | wr = csv.writer(f, dialect='excel')
96 | wr.writerow(states)
97 | wr.writerow(times_dfa)
98 | wr.writerow(times_mealy)
99 | wr.writerow(times_moore)
100 | wr.writerow(total_dfa)
101 | wr.writerow(total_mealy)
102 | wr.writerow(times_moore)
103 |
--------------------------------------------------------------------------------
/Benchmarking/cex_processing_benchmark.py:
--------------------------------------------------------------------------------
1 | from collections import defaultdict
2 | from statistics import mean, stdev
3 |
4 | from aalpy.learning_algs import run_KV, run_Lstar
5 |
6 | from aalpy.SULs import AutomatonSUL
7 | from aalpy.oracles import RandomWalkEqOracle
8 | from aalpy.utils import generate_random_deterministic_automata, bisimilar
9 |
10 | counterexample_processing_strategy = ['rs', 'linear_fwd', 'linear_bwd', 'exponential_fwd', 'exponential_bwd']
11 | algorithms = ['l_star', 'kv']
12 | model_sizes = [500]
13 | model_type = ['mealy', 'moore']
14 | # alphabet_sizes = [(3,2), (3, 5), (3, 10), (5, 2), (5, 5), (5, 20)]
15 | alphabet_sizes = [(5, 3)]
16 |
17 | num_repetitions = 5
18 |
19 | for learning_alg in algorithms:
20 | results = defaultdict(list)
21 | for model in model_type:
22 | for model_size in model_sizes:
23 | for input_size, output_size in alphabet_sizes:
24 | for cex_processing in counterexample_processing_strategy:
25 |
26 | for _ in range(num_repetitions):
27 | random_model = generate_random_deterministic_automata(model, num_states=model_size,
28 | input_alphabet_size=input_size,
29 | output_alphabet_size=output_size)
30 | sul = AutomatonSUL(random_model)
31 | input_al = random_model.get_input_alphabet()
32 | eq_oracle = RandomWalkEqOracle(input_al, sul, num_steps=20000, reset_prob=0.09)
33 |
34 | if learning_alg == 'kv':
35 | learned_model, info = run_KV(input_al, sul, eq_oracle,
36 | automaton_type=model, cex_processing=cex_processing,
37 | return_data=True, print_level=0)
38 | else:
39 | learned_model, info = run_Lstar(input_al, sul, eq_oracle,
40 | automaton_type=model, cex_processing=cex_processing,
41 | return_data=True, print_level=0)
42 | results[cex_processing].append(info['steps_learning'])
43 |
44 | if not bisimilar(learned_model, random_model):
45 | print(learning_alg, cex_processing, 'mismatch')
46 |
47 | print(learning_alg)
48 | for k, v in results.items():
49 | print(k, mean(v), stdev(v), min(v), max(v))
50 |
--------------------------------------------------------------------------------
/Benchmarking/compare_lstar_and_kv.py:
--------------------------------------------------------------------------------
1 | from aalpy.SULs import AutomatonSUL
2 | from aalpy.learning_algs import run_Lstar, run_KV
3 | from aalpy.oracles import RandomWordEqOracle
4 | from aalpy.utils import generate_random_deterministic_automata
5 |
6 | automata_type = ['dfa', 'mealy', 'moore']
7 | automata_size = [10, 100, 500, 1000,]
8 | input_sizes = [2, 3]
9 | output_sizes = [2, 3, 5, 10]
10 |
11 | test_models = []
12 | for model_type in automata_type:
13 | for size in automata_size:
14 | for i in input_sizes:
15 | for o in output_sizes:
16 | random_model = generate_random_deterministic_automata(model_type, size, i, o, num_accepting_states=size//8)
17 | input_al = random_model.get_input_alphabet()
18 |
19 | print('------------------------------------------')
20 | if model_type != 'dfa':
21 | print(f'Type: {model_type}, size: {size}, # inputs: {i}, # outputs: {o}')
22 | else:
23 | print(f'Type: {model_type}, size: {size}, # inputs: {i}, # accepting: {size//8}')
24 |
25 | # Lstar
26 | sul = AutomatonSUL(random_model)
27 | eq_oracle = RandomWordEqOracle(input_al, sul, num_walks=5000, min_walk_len=10, max_walk_len=40)
28 | l_star_model, l_star_info = run_Lstar(input_al, sul, eq_oracle, model_type, print_level=0, return_data=True)
29 |
30 | l_star_steps, l_star_queries = l_star_info['steps_learning'], l_star_info['queries_learning']
31 |
32 | # KV
33 | sul = AutomatonSUL(random_model)
34 | eq_oracle = RandomWordEqOracle(input_al, sul, num_walks=5000, min_walk_len=10, max_walk_len=40)
35 | kv_model, kv_info = run_KV(input_al, sul, eq_oracle, model_type, print_level=0, return_data=True)
36 |
37 | kv_steps, kv_queries = kv_info['steps_learning'], kv_info['queries_learning']
38 |
39 | if l_star_model.size != random_model.size:
40 | print('L* did not learn correctly.')
41 | if kv_model.size != random_model.size:
42 | print('KV did not learn correctly.')
43 |
44 | print(f'L* steps: {l_star_steps}')
45 | print(f'KV steps: {kv_steps}')
46 | if kv_steps < l_star_steps:
47 | print(f'KV is {round((l_star_steps / kv_steps) * 100 - 100, 2)}% more step efficient')
48 | else:
49 | print(f'L* is {round((kv_steps / l_star_steps) * 100 - 100, 2)}% more step efficient')
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Benchmarking/deterministic_evaluation.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DES-Lab/AALpy/177862fb505df3f92a945861ceb1977962327327/Benchmarking/deterministic_evaluation.PNG
--------------------------------------------------------------------------------
/Benchmarking/error_benchmark_statistics.py:
--------------------------------------------------------------------------------
1 | import csv
2 | import os
3 | from collections import defaultdict
4 | from statistics import mean
5 |
6 | directory = 'FM_mdp_smm_error_based_stop/benchmark_no_cq_bfs_longest_prefix/'
7 |
8 | benchmarks = os.listdir(directory)[:-1]
9 |
10 | benchmarks.remove('exp_14.csv')
11 |
12 | values = dict()
13 |
14 | for file in benchmarks:
15 | with open(directory + file, 'r') as f:
16 | reader = csv.reader(f)
17 | data = list(reader)
18 |
19 | for i in range(0, len(data), 3):
20 | header = data[i]
21 | mdp, smm = data[i + 1], data[i + 2]
22 |
23 | for formalism in [mdp, smm]:
24 | for i, val in enumerate(formalism[1:]):
25 | if formalism[0] not in values.keys():
26 | values[formalism[0]] = defaultdict(list)
27 | values[formalism[0]][header[i + 1]].append(round(float(val), 2))
28 |
29 | min_values_dict = dict()
30 | max_values_dict = dict()
31 | avr_values_dict = dict()
32 |
33 | for exp in values:
34 | exp_name = exp[12:]
35 | formalism = 'smm' if 'smm' in exp else 'mdp'
36 |
37 | name = f'{exp_name}_{formalism}'
38 | min_values_dict[name] = dict()
39 | max_values_dict[name] = dict()
40 | avr_values_dict[name] = dict()
41 |
42 | for category, value in values[exp].items():
43 | min_values_dict[name][category] = min(value)
44 | max_values_dict[name][category] = max(value)
45 | avr_values_dict[name][category] = round(mean(value), 2)
46 |
47 | interesting_fields = [' Learning time', ' Learning Rounds', ' #MQ Learning', ' # Steps Learning']
48 |
49 | print('ALL ERRORS ARE LESS THAN 2%. THAT WAS USED AS STOPPING CRITERION')
50 | experiments = list(min_values_dict.keys())
51 | for e_index in range(0, len(experiments), 2):
52 | for i in interesting_fields:
53 | print(f'{experiments[e_index]} vs {experiments[e_index + 1]} = > {i}')
54 | min_eff = round(min_values_dict[experiments[e_index]][i] / min_values_dict[experiments[e_index + 1]][i]*100 , 2)
55 | print(f'Min : {min_values_dict[experiments[e_index]][i]} vs {min_values_dict[experiments[e_index + 1]][i]} | SMM efficiency : {min_eff}')
56 | max_eff = round(max_values_dict[experiments[e_index]][i] / max_values_dict[experiments[e_index + 1]][i]*100 , 2)
57 | print(f'Max : {max_values_dict[experiments[e_index]][i]} vs {max_values_dict[experiments[e_index + 1]][i]} | SMM efficiency : {max_eff}')
58 | avr_eff = round(avr_values_dict[experiments[e_index]][i] / avr_values_dict[experiments[e_index + 1]][i]*100 , 2)
59 | print(f'Avr : {avr_values_dict[experiments[e_index]][i]} vs {avr_values_dict[experiments[e_index + 1]][i]}| SMM efficiency : {avr_eff}')
60 |
61 | print('-------------------------------------------------')
62 |
63 | with open('error_benchmark.csv', 'w',newline='') as file:
64 | writer = csv.writer(file)
65 |
66 | experiments = list(min_values_dict.keys())
67 | for e_index in range(0, len(experiments), 2):
68 | writer.writerow([experiments[e_index][:-4], 'mdp', 'smm', 'smm compared to mdp efficiency %'])
69 | for i in interesting_fields:
70 | print(f'{experiments[e_index]} vs {experiments[e_index + 1]} = > {i}')
71 | min_eff = round(min_values_dict[experiments[e_index]][i] / min_values_dict[experiments[e_index + 1]][i]*100 , 2)
72 | writer.writerow([i + '_min', min_values_dict[experiments[e_index]][i], min_values_dict[experiments[e_index + 1]][i], min_eff])
73 | max_eff = round(max_values_dict[experiments[e_index]][i] / max_values_dict[experiments[e_index + 1]][i]*100 , 2)
74 | writer.writerow([i + '_max', max_values_dict[experiments[e_index]][i], max_values_dict[experiments[e_index + 1]][i], max_eff])
75 | avr_eff = round(avr_values_dict[experiments[e_index]][i] / avr_values_dict[experiments[e_index + 1]][i]*100 , 2)
76 | writer.writerow([i + '_avr', avr_values_dict[experiments[e_index]][i], avr_values_dict[experiments[e_index + 1]][i], avr_eff])
77 | writer.writerow([])
78 |
79 | print('-------------------------------------------------')
80 |
81 |
--------------------------------------------------------------------------------
/Benchmarking/fm_plots.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | def plot_error():
4 | import matplotlib.pyplot as plt
5 | import matplotlib
6 |
7 | matplotlib.use("pgf")
8 | matplotlib.rcParams.update({
9 | "pgf.texsystem": "pdflatex",
10 | 'font.family': 'serif',
11 | 'text.usetex': True,
12 | 'pgf.rcfonts': False,
13 | })
14 |
15 | # MDP then SMM
16 | learning_time_data = [
17 | [68.19, 140.31, 154.35, 116.8],
18 | [27.5, 98.31, 30.87, 68]
19 | ]
20 |
21 | num_mq_data = [
22 | [81803.23, 153758.15, 560705.92, 248552.62, ],
23 | [36937.54, 91309.08, 51791.54, 92607]
24 | ]
25 |
26 | import numpy as np
27 |
28 | N = 4
29 |
30 | ind = np.arange(N) # the x locations for the groups
31 | width = 0.25 # the width of the bars
32 |
33 | # fig = plt.figure()
34 | fig, (ax_time, ax_mq) = plt.subplots(1, 2, figsize=(10, 3))
35 |
36 | ax_time.bar(ind, learning_time_data[0], width, label='MDP')
37 | ax_time.bar(ind + width, learning_time_data[1], width, label='SMM')
38 |
39 | # add some
40 | ax_time.set_ylabel('Learning Time (s)')
41 |
42 | ax_time.set_xticks(ind + width / 2)
43 | ax_time.set_xticklabels(('35 State\nGridworld', '72 State\nGridworld', 'MQTT', 'TCP',))
44 |
45 | ax_time.grid(axis='y')
46 | ax_time.legend(loc='upper left')
47 |
48 | ax_mq.bar(ind, num_mq_data[0], width, label='MDP')
49 | ax_mq.bar(ind + width, num_mq_data[1], width, label='SMM')
50 |
51 | # add some
52 | ax_mq.set_ylabel('\# Membership Queries')
53 | ax_mq.ticklabel_format(axis='y', style='sci', scilimits=(1, 4))
54 | ax_mq.set_xticks(ind + width / 2)
55 | ax_mq.set_xticklabels(('35 State\nGridworld', '72 State\nGridworld', 'MQTT', 'TCP',))
56 | ax_mq.legend(loc='upper left')
57 |
58 |
59 | ax_mq.grid(axis='y')
60 | fig.tight_layout()
61 |
62 | # plt.show()
63 |
64 | plt.savefig("error_bench.pgf", bbox_inches='tight')
65 |
66 | import tikzplotlib
67 |
68 | tikzplotlib.save("error_bench.tex")
69 |
70 | def plot_benchmarks():
71 | import matplotlib.pyplot as plt
72 | import matplotlib
73 |
74 | matplotlib.use("pgf")
75 | matplotlib.rcParams.update({
76 | "pgf.texsystem": "pdflatex",
77 | 'font.family': 'serif',
78 | 'text.usetex': True,
79 | 'pgf.rcfonts': False,
80 | })
81 |
82 | # MDP then SMM
83 |
84 | num_mq_data = [
85 | [81803.23, 153758.15, 560705.92, 248552.62, ],
86 | [36937.54, 91309.08, 51791.54, 92607]
87 | ]
88 |
89 | # TODO
90 | avr_cum_err = [
91 |
92 | ]
93 |
94 | import numpy as np
95 |
96 | N = 4
97 |
98 | ind = np.arange(N) # the x locations for the groups
99 | width = 0.25 # the width of the bars
100 |
101 | # fig = plt.figure()
102 | fig, (ax_time, ax_mq) = plt.subplots(1, 2, figsize=(10, 3))
103 |
104 | ax_time.bar(ind, avr_cum_err[0], width, label='MDP')
105 | ax_time.bar(ind + width, avr_cum_err[1], width, label='SMM')
106 |
107 | # add some
108 | ax_time.set_ylabel('Learning Time (s)')
109 |
110 | ax_time.set_xticks(ind + width / 2)
111 | ax_time.set_xticklabels(('35 State\nGridworld', '72 State\nGridworld', 'MQTT', 'TCP',))
112 |
113 | ax_time.grid(axis='y')
114 | ax_time.legend(loc='upper left')
115 |
116 | ax_mq.bar(ind, num_mq_data[0], width, label='MDP')
117 | ax_mq.bar(ind + width, num_mq_data[1], width, label='SMM')
118 |
119 | # add some
120 | ax_mq.set_ylabel('\# Membership Queries')
121 | ax_mq.ticklabel_format(axis='y', style='sci', scilimits=(1, 4))
122 | ax_mq.set_xticks(ind + width / 2)
123 | ax_mq.set_xticklabels(('35 State\nGridworld', '72 State\nGridworld', 'MQTT', 'TCP',))
124 |
125 | ax_mq.legend(loc='upper left')
126 |
127 | ax_mq.grid(axis='y')
128 | fig.tight_layout()
129 |
130 | # plt.show()
131 |
132 | plt.savefig("benchmarking.pgf", bbox_inches='tight')
133 |
134 | import tikzplotlib
135 |
136 | tikzplotlib.save("benchmarking.tex")
137 |
138 | if __name__ == '__main__':
139 | plot_error()
--------------------------------------------------------------------------------
/Benchmarking/papni_sequances.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DES-Lab/AALpy/177862fb505df3f92a945861ceb1977962327327/Benchmarking/papni_sequances.pickle
--------------------------------------------------------------------------------
/Benchmarking/passive_mdp_vs_smm.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | import aalpy.paths
4 | from aalpy.SULs import AutomatonSUL
5 | from aalpy.automata.StochasticMealyMachine import smm_to_mdp_conversion
6 | from aalpy.learning_algs import run_Alergia
7 | from aalpy.utils import load_automaton_from_file, get_correct_prop_values, get_properties_file
8 | from aalpy.utils import model_check_experiment
9 |
10 | path_to_dir = '../DotModels/MDPs/'
11 | files = ['first_grid.dot', 'second_grid.dot',
12 | 'slot_machine.dot', 'mqtt.dot', 'tcp.dot'] # 'shared_coin.dot'
13 |
14 | aalpy.paths.path_to_prism = "C:/Program Files/prism-4.7/bin/prism.bat"
15 | aalpy.paths.path_to_properties = "prism_eval_props/"
16 |
17 |
18 | def writeSamplesToFile(samples, path="alergiaSamples.txt"):
19 | isSMM = False
20 | if isinstance(samples[0][0], tuple):
21 | isSMM = True
22 | with open(path, 'a') as f:
23 | for sample in samples:
24 | s = "" if isSMM else f'{str(sample.pop(0))}'
25 | for i, o in sample:
26 | s += f',{i},{o}'
27 | f.write(s + '\n')
28 |
29 | f.close()
30 | # samples.clear()
31 |
32 |
33 | def deleteSampleFile(path="alergiaSamples.txt"):
34 | import os
35 | if os.path.exists(path):
36 | os.remove(path)
37 |
38 |
39 | num_traces = 100000
40 |
41 | for file in ['first_grid.dot']:
42 |
43 | exp_name = file.split('.')[0]
44 |
45 | original_mdp = load_automaton_from_file(path_to_dir + file, automaton_type='mdp')
46 | input_alphabet = original_mdp.get_input_alphabet()
47 |
48 | mdp_sul = AutomatonSUL(original_mdp)
49 |
50 | for _ in range(1):
51 |
52 | data = []
53 | for _ in range(num_traces):
54 | sample = [mdp_sul.pre()]
55 | for _ in range(random.randint(10, 50)):
56 | i = random.choice(input_alphabet)
57 | o = mdp_sul.step(i)
58 | sample.append((i, o))
59 | data.append(sample)
60 | mdp_sul.post()
61 |
62 | learned_mdp = run_Alergia(data, automaton_type='mdp')
63 |
64 | for s in data:
65 | s.pop(0)
66 |
67 | learned_smm = run_Alergia(data, automaton_type='smm')
68 |
69 | smm_2_mdp = smm_to_mdp_conversion(learned_smm)
70 |
71 | mdp_results, mdp_err = model_check_experiment(get_properties_file(exp_name),
72 | get_correct_prop_values(exp_name), learned_mdp)
73 | smm_results, smm_err = model_check_experiment(get_properties_file(exp_name),
74 | get_correct_prop_values(exp_name), smm_2_mdp)
75 |
76 | print(learned_mdp.size, learned_smm.size, smm_2_mdp.size)
77 | print(f'-------{exp_name}---------')
78 | print(f'MDP Error: {mdp_err}')
79 | print(f'SMM Error: {smm_err}')
80 | smm_diff = {}
81 | for key, val in mdp_err.items():
82 | if key not in smm_err.keys() or smm_err[key] == 0:
83 | continue
84 | smm_diff[key] = round(smm_err[key] - val, 2)
85 | print(f'SMM differance: {smm_diff}')
86 |
--------------------------------------------------------------------------------
/Benchmarking/prism_eval_props/bluetooth.props:
--------------------------------------------------------------------------------
1 | Pmax=? [ F<5 ("crash") ]
2 |
3 | Pmax=? [ F<8 ("crash") ]
4 |
5 | Pmax=? [ F<11 ("crash") ]
6 |
7 | Pmax=? [ F<14 ("crash") ]
8 |
9 | Pmax=? [ F<17 ("crash") ]
10 |
11 | Pmax=? [ F<20 ("crash") ]
12 |
13 | Pmax=? [ F<3 ("no_response") ]
14 |
15 | Pmax=? [ F<5 ("no_response") ]
16 |
17 | Pmax=? [ F<8 ("no_response") ]
18 |
19 | Pmax=? [ F<11 ("no_response") ]
20 |
21 | Pmax=? [ F<14 ("no_response") ]
22 |
23 | Pmax=? [ F<17 ("no_response") ]
24 |
25 | Pmax=? [ F<20 ("no_response") ]
26 |
27 |
--------------------------------------------------------------------------------
/Benchmarking/prism_eval_props/emqtt_two_client.props:
--------------------------------------------------------------------------------
1 | Pmax=? [ F<5 ("c2_Pub_c2_my_topic_bye") ]
2 |
3 | Pmax=? [ F<5 ("c1_crash") ]
4 |
5 | Pmax=? [ F<11 ("c1_crash") ]
6 |
7 | Pmax=? [ F<17 ("c1_crash") ]
8 |
9 | Pmax=? [(!("c2_crash")) U<12 ("c2_Pub_c2_my_topic_messageQos1") ]
10 |
11 |
--------------------------------------------------------------------------------
/Benchmarking/prism_eval_props/first_eval.props:
--------------------------------------------------------------------------------
1 | Pmax=?[F<12("goal")]
2 |
3 | Pmax=? [ !("grass") U<=14 ("goal") ]
4 |
5 | Pmax=? [ !("sand") U<=16 ("goal") ]
6 |
7 |
--------------------------------------------------------------------------------
/Benchmarking/prism_eval_props/second_eval.props:
--------------------------------------------------------------------------------
1 | Pmax=?[F<15("goal")]
2 |
3 | Pmax=?[F<13("goal")]
4 |
5 | Pmax=? [ !("mud") U<=18 ("goal") ]
6 |
7 | Pmax=? [ !("sand") U<=20 ("goal") ]
8 |
9 |
--------------------------------------------------------------------------------
/Benchmarking/prism_eval_props/shared_coin_eval.props:
--------------------------------------------------------------------------------
1 | Pmax=?[F ("finished" & "c1_heads" & "c2_tails")]
2 |
3 | Pmax=?[F ("finished" & "c1_tails" & "c2_tails")]
4 |
5 | Pmax=?[!"five" U "finished"]
6 |
7 | Pmax=?[!"four" U "finished"]
8 |
9 | Pmax=?[F<40 ("finished" & "c1_heads" & "c2_tails")]
10 |
11 | Pmax=?[F<40 ("finished" & "c1_tails" & "c2_tails")]
12 |
13 | Pmax=?[!"five" U<40 "finished"]
14 |
15 | Pmax=?[!"four" U<40 "finished"]
16 |
17 |
--------------------------------------------------------------------------------
/Benchmarking/prism_eval_props/slot_machine_eval.props:
--------------------------------------------------------------------------------
1 | Pmax=? [ F ("Pr10") ]
2 |
3 | Pmax=? [ F ("Pr2") ]
4 |
5 | Pmax=? [ F ("Pr0") ]
6 |
7 | Pmax=? [ X (X ("r220")) ]
8 |
9 | Pmax=? [ X(X (X ("r122"))) ]
10 |
11 | Pmax=? [ !(F<10 ("end")) ]
12 |
13 | Pmax=? [ X (X (X ("r111")))&(F ("Pr0")) ]
14 |
15 |
--------------------------------------------------------------------------------
/Benchmarking/prism_eval_props/tcp_eval.props:
--------------------------------------------------------------------------------
1 |
2 | Pmax=? [ F<5 ("crash") ]
3 |
4 | Pmax=? [ F<11 ("crash") ]
5 |
6 | Pmax=? [ F<17 ("crash") ]
7 |
8 | Pmax=? [ F<23 ("crash") ]
9 |
--------------------------------------------------------------------------------
/Benchmarking/rpni_papni_memory_footrpint.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from random import randint, random
3 | import matplotlib.pyplot as plt
4 |
5 | # Data
6 | import tikzplotlib
7 |
8 | from Benchmarking.visualize_papni_rpni import tikzplotlib_fix_ncols
9 | from aalpy import load_automaton_from_file, run_PAPNI, run_RPNI
10 | from aalpy.utils import generate_input_output_data_from_vpa
11 | from aalpy.utils.BenchmarkVpaModels import get_all_VPAs
12 | from random import seed
13 |
14 | # def get_total_size(obj, seen=None):
15 | # """Recursively find the size of an object and all its referenced objects."""
16 | # if seen is None:
17 | # seen = set()
18 | #
19 | # obj_id = id(obj)
20 | # if obj_id in seen: # Avoid processing the same object multiple times
21 | # return 0
22 | #
23 | # seen.add(obj_id)
24 | # size = sys.getsizeof(obj)
25 | #
26 | # if isinstance(obj, dict):
27 | # size += sum(get_total_size(k, seen) + get_total_size(v, seen) for k, v in obj.items())
28 | # elif isinstance(obj, (list, tuple, set, frozenset)):
29 | # size += sum(get_total_size(i, seen) for i in obj)
30 | # elif hasattr(obj, '__dict__'): # For objects with __dict__ attribute
31 | # size += get_total_size(vars(obj), seen)
32 | # elif hasattr(obj, '__slots__'): # For objects with __slots__
33 | # size += sum(get_total_size(getattr(obj, s), seen) for s in obj.__slots__ if hasattr(obj, s))
34 | #
35 | # return size
36 | #
37 | #
38 | # def size_in_mb(obj):
39 | # size_bytes = get_total_size(obj)
40 | # return size_bytes / (1024 ** 2)
41 | #
42 | #
43 | # #gt = load_automaton_from_file('../DotModels/arithmetics.dot', 'vpa')
44 | # gt = get_all_VPAs()[9]
45 | # vpa_alphabet = gt.get_input_alphabet()
46 | #
47 | # rpni_size = []
48 | # papni_size = []
49 | # for size in range(5000, 50001, 5000):
50 | # print(size)
51 | # data = generate_input_output_data_from_vpa(gt,
52 | # num_sequances=size,
53 | # max_seq_len=randint(6, 30))
54 | #
55 | # y = run_RPNI(data, automaton_type='dfa', print_info=False)
56 | # x = run_PAPNI(data, vpa_alphabet, print_info=False)
57 | #
58 | # rpni_size.append(y)
59 | # papni_size.append(x)
60 | #
61 | # print(rpni_size)
62 | # print(papni_size)
63 |
64 |
65 | # runtime (pta, alg) papni, rpni
66 | rpni_runtime = [(0.02, 0.04), (0.06, 0.11), (0.11, 0.14), (0.11, 0.22), (0.14, 0.24), (0.12, 0.26), (0.15, 0.31), (0.26, 0.28), (0.21, 0.4), (0.25, 0.43)]
67 | papni_runtime = [(0.0, 0.01), (0.01, 0.04), (0.02, 0.04), (0.02, 0.05), (0.02, 0.06), (0.04, 0.07), (0.02, 0.06), (0.03, 0.06), (0.06, 0.1), (0.03, 0.09)]
68 |
69 | # size rpni papni in Mb
70 | rpni_size = [1.8873348236083984, 3.9477672576904297, 5.673147201538086, 7.70704460144043, 9.281957626342773, 12.503767013549805, 14.622617721557617, 15.591878890991211, 18.589590072631836, 20.439626693725586]
71 | papni_size = [0.0034532546997070312, 0.0034532546997070312, 0.0034532546997070312, 0.0034532546997070312, 0.0034532546997070312, 0.0034532546997070312, 0.0034532546997070312, 0.0034532546997070312, 0.0034532546997070312, 0.0034532546997070312]
72 |
73 | papni_size = [papni_size[0]]
74 | for i in range(len(rpni_runtime) - 1):
75 | papni_size.append(papni_size[-1] * (rpni_size[i+1]/rpni_size[i] ))
76 |
77 | print(papni_size)
78 |
79 | # Create subplots
80 | fig, axes = plt.subplots(1, 2, figsize=(12, 5))
81 |
82 | ticks = range(5000, 50001, 5000)
83 |
84 |
85 | # Runtime plot
86 | axes[0].plot(ticks, [x + y for x,y in rpni_runtime], label="RPNI", marker='o')
87 | axes[0].plot(ticks, [x + y for x,y in papni_runtime], label="PAPNI", marker='s')
88 | axes[0].set_xlabel("Input Size")
89 | axes[0].set_ylabel("Runtime (s)")
90 | axes[0].set_title("Runtime Comparison")
91 | axes[0].legend()
92 | axes[0].grid(True)
93 |
94 | # Size plot
95 | axes[1].plot(ticks, rpni_size, label="RPNI", marker='o')
96 | axes[1].plot(ticks, papni_size, label="PAPNI", marker='s')
97 | axes[1].set_xlabel("Input Size")
98 | axes[1].set_ylabel("Size (MB)")
99 | axes[1].set_title("Size Comparison")
100 | axes[1].legend()
101 | axes[1].grid(True)
102 |
103 | # Layout adjustment
104 | plt.tight_layout()
105 | # plt.show()
106 |
107 | tikzplotlib_fix_ncols(fig)
108 | # plt.show()
109 | tikzplotlib.save("runtime_and_size_comparison.tex")
110 |
--------------------------------------------------------------------------------
/Benchmarking/stochastic_benchmarking/passive_mdp_vs_smm.py:
--------------------------------------------------------------------------------
1 | import random
2 | import os
3 | import aalpy.paths
4 | from aalpy.SULs import AutomatonSUL
5 | from aalpy.automata.StochasticMealyMachine import smm_to_mdp_conversion
6 | from aalpy.learning_algs import run_Alergia, run_JAlergia
7 | from aalpy.utils import load_automaton_from_file, get_correct_prop_values, get_properties_file, visualize_automaton
8 | from aalpy.utils import model_check_experiment
9 |
10 | path_to_dir = '../DotModels/MDPs/'
11 | files = ['first_grid.dot', 'second_grid.dot',
12 | 'slot_machine.dot', 'mqtt.dot', 'tcp.dot'] # 'shared_coin.dot'
13 |
14 | aalpy.paths.path_to_prism = "C:/Program Files/prism-4.7/bin/prism.bat"
15 | aalpy.paths.path_to_properties = "../prism_eval_props/"
16 |
17 |
18 | def writeSamplesToFile(samples, path="alergiaSamples.txt"):
19 | isSMM = False
20 | if isinstance(samples[0][0], tuple):
21 | isSMM = True
22 | with open(path, 'a') as f:
23 | for sample in samples:
24 | s = "" if isSMM else f'{str(sample.pop(0))}'
25 | for i, o in sample:
26 | s += f',{i},{o}'
27 | f.write(s + '\n')
28 |
29 | f.close()
30 | # samples.clear()
31 |
32 |
33 | def deleteSampleFile(path="alergiaSamples.txt"):
34 | import os
35 | if os.path.exists(path):
36 | os.remove(path)
37 |
38 |
39 | num_traces = 100000
40 |
41 | for file in ['first_grid.dot']:
42 |
43 | exp_name = file.split('.')[0]
44 |
45 | original_mdp = load_automaton_from_file(path_to_dir + file, automaton_type='mdp')
46 | input_alphabet = original_mdp.get_input_alphabet()
47 |
48 | mdp_sul = AutomatonSUL(original_mdp)
49 |
50 | for _ in range(1):
51 |
52 | data = []
53 | for _ in range(num_traces):
54 | sample = [mdp_sul.pre()]
55 | for _ in range(random.randint(10, 50)):
56 | i = random.choice(input_alphabet)
57 | o = mdp_sul.step(i)
58 | sample.append((i, o))
59 | data.append(sample)
60 | mdp_sul.post()
61 |
62 | learned_mdp = run_Alergia(data, automaton_type='mdp')
63 |
64 | for s in data:
65 | s.pop(0)
66 |
67 | learned_smm = run_Alergia(data, automaton_type='smm')
68 |
69 | smm_2_mdp = smm_to_mdp_conversion(learned_smm)
70 |
71 | mdp_results, mdp_err = model_check_experiment(get_properties_file(exp_name),
72 | get_correct_prop_values(exp_name), learned_mdp)
73 | smm_results, smm_err = model_check_experiment(get_properties_file(exp_name),
74 | get_correct_prop_values(exp_name), smm_2_mdp)
75 |
76 | print(learned_mdp.size, learned_smm.size, smm_2_mdp.size)
77 | print(f'-------{exp_name}---------')
78 | print(f'MDP Error: {mdp_err}')
79 | print(f'SMM Error: {smm_err}')
80 | smm_diff = {}
81 | for key, val in mdp_err.items():
82 | if key not in smm_err.keys() or smm_err[key] == 0:
83 | continue
84 | smm_diff[key] = round(smm_err[key] - val, 2)
85 | print(f'SMM differance: {smm_diff}')
86 |
--------------------------------------------------------------------------------
/Benchmarking/stochastic_benchmarking/stochastic_benchmark_random_automata.py:
--------------------------------------------------------------------------------
1 | from itertools import product
2 |
3 | from aalpy.SULs import AutomatonSUL
4 | from aalpy.learning_algs import run_stochastic_Lstar
5 | from aalpy.oracles import RandomWordEqOracle
6 | from aalpy.utils import generate_random_mdp, generate_random_smm
7 |
8 | automata_size = [5, 10, 15, 20, 30, 50, ]
9 | inputs_size = [2, 3, 5, 7, 9]
10 | outputs_size = [2, 5, 10, 15, 20]
11 | inputs_size = [7]
12 | outputs_size = [15]
13 |
14 |
15 | def learn(mdp, type):
16 | input_al = mdp.get_input_alphabet()
17 | sul = AutomatonSUL(mdp)
18 | eq_oracle = RandomWordEqOracle(input_al, sul, num_walks=1000, min_walk_len=4, max_walk_len=20)
19 | return run_stochastic_Lstar(input_al, sul, eq_oracle, automaton_type=type, cex_processing=None, print_level=0,
20 | return_data=True)
21 |
22 |
23 | num_queries_mdp = []
24 | num_queries_smm = []
25 |
26 | # i = 0
27 | # for p in product(automata_size, inputs_size, outputs_size):
28 | # num_states, num_inputs, num_outputs = p
29 | # if num_inputs > num_outputs:
30 | # continue
31 | #
32 | # print(i)
33 | # i += 1
34 | #
35 | # # random_mdp = generate_random_mdp(num_states=num_states, input_size=num_inputs, output_size=num_outputs)
36 | # random_smm = generate_random_mdp(num_states=num_states, input_size=num_inputs, output_size=num_outputs)
37 | # # random_smm = random_smm.to_mdp()
38 | #
39 | # _, mdp_data = learn(random_smm, 'mdp')
40 | # _, smm_data = learn(random_smm, 'smm')
41 | #
42 | # num_queries_mdp.append(mdp_data['queries_learning'] + mdp_data['queries_eq_oracle'])
43 | # num_queries_smm.append(smm_data['queries_learning'] + smm_data['queries_eq_oracle'])
44 |
45 | print(num_queries_mdp)
46 | print(num_queries_smm)
47 |
48 | num_queries_mdp_3_7 = [77115, 85440, 36326, 132485, 250055, 343526]
49 | num_queries_smm_3_7 = [23511, 14287, 17106, 55482, 50935, 99730]
50 |
51 | num_queries_mdp_4_10 = [54654, 265240, 245245, 238944, 320026, 1170086]
52 | num_queries_smm_4_10 = [7122, 42637, 32431, 51821, 75703, 204150]
53 |
54 | num_queries_mdp_7_15 = [237731, 397386, 924637, 2066456, 4117725, 4774201]
55 | num_queries_smm_7_15 = [15733, 19148, 52214, 106436, 157414, 605491]
56 |
57 | # mdp was used for data gen
58 |
59 | mdp_base_num_queries_mdp_3_7 = [6515, 13659, 42904, 31798, 129641, 128275]
60 | mdp_base_num_queries_smm_3_7 = [7383, 16985, 55428, 78679, 230936, 479493]
61 |
62 | mdp_base_num_queries_mdp_4_10 = [10110, 14032, 61815, 35108, 61489, 115270]
63 | mdp_base_num_queries_smm_4_10 = [8284, 11257, 38399, 49637, 74183, 145063]
64 |
65 | mdp_base_num_queries_mdp_7_15 = [7611, 16438, 12564, 33355, 76704, 348364]
66 | mdp_base_num_queries_smm_7_15 = [12132, 29568, 36804, 60763, 95613, 348675]
67 |
68 | pairs_smm_base = [(num_queries_mdp_3_7, num_queries_smm_3_7), (num_queries_mdp_4_10, num_queries_smm_4_10),
69 | (num_queries_mdp_7_15, num_queries_smm_7_15)]
70 |
71 | pairs_mdp_base = [(mdp_base_num_queries_mdp_3_7, mdp_base_num_queries_smm_3_7),
72 | (mdp_base_num_queries_mdp_4_10, mdp_base_num_queries_smm_4_10),
73 | (mdp_base_num_queries_mdp_7_15, mdp_base_num_queries_smm_7_15)]
74 | #
75 | for mdp, smm in pairs_mdp_base:
76 | save = []
77 | for m, s in zip(mdp, smm):
78 | save.append(100 - round(s / m * 100, 2))
79 | print(save)
80 |
81 | smm_save_3_7 = [69.51, 83.28, 52.91, 58.12, 79.63, 70.97]
82 | smm_save_4_10 = [86.97, 83.93, 86.78, 78.31, 76.34, 82.55]
83 | smm_save_7_15 = [93.38, 95.18, 94.35, 94.85, 96.18, 87.32]
84 |
85 | #
86 | # def plot_queries_smm_as_base():
87 | # import matplotlib.pyplot as plt
88 | #
89 | # plt.plot(automata_size, smm_save_3_7, label='I:3,O: 7)')
90 | # plt.plot(automata_size, smm_save_4_10, label='I:4,O: 10')
91 | # plt.plot(automata_size, smm_save_7_15, label='I:7,O: 15')
92 | #
93 | # plt.xticks(automata_size)
94 | #
95 | # plt.grid()
96 | # plt.legend()
97 | # plt.show()
98 |
99 | # plot_queries_smm_as_base()
100 |
--------------------------------------------------------------------------------
/Benchmarking/stochastic_evaluation.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DES-Lab/AALpy/177862fb505df3f92a945861ceb1977962327327/Benchmarking/stochastic_evaluation.PNG
--------------------------------------------------------------------------------
/DotModels/Angluin_Mealy.dot:
--------------------------------------------------------------------------------
1 | digraph Angluin_Mealy {
2 | s0 [label="s0"];
3 | s1 [label="s1"];
4 | s2 [label="s2"];
5 | s3 [label="s3"];
6 | s0 -> s2 [label="a/0"];
7 | s0 -> s1 [label="b/0"];
8 | s1 -> s3 [label="a/0"];
9 | s1 -> s0 [label="b/1"];
10 | s2 -> s0 [label="a/1"];
11 | s2 -> s3 [label="b/0"];
12 | s3 -> s1 [label="a/0"];
13 | s3 -> s2 [label="b/0"];
14 | __start0 [label="", shape=none];
15 | __start0 -> s0 [label=""];
16 | }
17 |
--------------------------------------------------------------------------------
/DotModels/Angluin_Moore.dot:
--------------------------------------------------------------------------------
1 | digraph Angluin_Moore {
2 | s0 [label="s0|1", shape=record, style=rounded];
3 | s1 [label="s1|0", shape=record, style=rounded];
4 | s2 [label="s2|0", shape=record, style=rounded];
5 | s3 [label="s3|0", shape=record, style=rounded];
6 | s0 -> s2 [label=a];
7 | s0 -> s1 [label=b];
8 | s1 -> s3 [label=a];
9 | s1 -> s0 [label=b];
10 | s2 -> s0 [label=a];
11 | s2 -> s3 [label=b];
12 | s3 -> s1 [label=a];
13 | s3 -> s2 [label=b];
14 | __start0 [label="", shape=none];
15 | __start0 -> s0 [label=""];
16 | }
17 |
--------------------------------------------------------------------------------
/DotModels/Bluetooth/CC2640R2-no-pairing-req.dot:
--------------------------------------------------------------------------------
1 | digraph CC2640R2 {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s3 [label=s3];
6 | s4 [label=s4];
7 | s5 [label=s5];
8 | s0 -> s0 [label="scan_req/Adv"];
9 | s0 -> s1 [label="connection_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_REQ"];
10 | s0 -> s0 [label="length_req/Empty"];
11 | s0 -> s0 [label="length_rsp/Empty"];
12 | s0 -> s0 [label="feature_rsp/Empty"];
13 | s0 -> s0 [label="feature_req/Empty"];
14 | s0 -> s0 [label="version_req/Empty"];
15 | s0 -> s0 [label="mtu_req/Empty"];
16 | s1 -> s0 [label="scan_req/Adv"];
17 | s1 -> s1 [label="connection_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_REQ"];
18 | s1 -> s1 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
19 | s1 -> s3 [label="length_rsp/BTLE|BTLE_DATA"];
20 | s1 -> s1 [label="feature_rsp/BTLE|BTLE_DATA"];
21 | s1 -> s1 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
22 | s1 -> s2 [label="version_req/BTLE|BTLE_DATA"];
23 | s1 -> s1 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
24 | s2 -> s0 [label="scan_req/Adv"];
25 | s2 -> s1 [label="connection_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_REQ"];
26 | s2 -> s2 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
27 | s2 -> s5 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
28 | s2 -> s2 [label="feature_rsp/BTLE|BTLE_DATA"];
29 | s2 -> s2 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
30 | s2 -> s4 [label="version_req/BTLE|BTLE_DATA"];
31 | s2 -> s2 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
32 | s3 -> s0 [label="scan_req/Adv"];
33 | s3 -> s1 [label="connection_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_REQ"];
34 | s3 -> s3 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
35 | s3 -> s3 [label="length_rsp/BTLE|BTLE_DATA"];
36 | s3 -> s3 [label="feature_rsp/BTLE|BTLE_DATA"];
37 | s3 -> s3 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
38 | s3 -> s5 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
39 | s3 -> s3 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
40 | s4 -> s0 [label="scan_req/Adv"];
41 | s4 -> s1 [label="connection_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_REQ"];
42 | s4 -> s4 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
43 | s4 -> s5 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP|LL_VERSION_IND"];
44 | s4 -> s4 [label="feature_rsp/BTLE|BTLE_DATA"];
45 | s4 -> s4 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
46 | s4 -> s4 [label="version_req/BTLE|BTLE_DATA"];
47 | s4 -> s4 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
48 | s5 -> s0 [label="scan_req/Adv"];
49 | s5 -> s1 [label="connection_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_REQ"];
50 | s5 -> s5 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
51 | s5 -> s5 [label="length_rsp/BTLE|BTLE_DATA"];
52 | s5 -> s5 [label="feature_rsp/BTLE|BTLE_DATA"];
53 | s5 -> s5 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
54 | s5 -> s5 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
55 | s5 -> s5 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
56 | __start0 [label="", shape=none];
57 | __start0 -> s0 [label=""];
58 | }
59 |
--------------------------------------------------------------------------------
/DotModels/Bluetooth/CC2650.dot:
--------------------------------------------------------------------------------
1 | digraph "cc2650" {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s3 [label=s3];
6 | s4 [label=s4];
7 | s0 -> s0 [label="scan_req/Adv"];
8 | s0 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
9 | s0 -> s0 [label="length_req/Empty"];
10 | s0 -> s0 [label="length_rsp/Empty"];
11 | s0 -> s0 [label="feature_rsp/Empty"];
12 | s0 -> s0 [label="feature_req/Empty"];
13 | s0 -> s0 [label="version_req/Empty"];
14 | s0 -> s0 [label="mtu_req/Empty"];
15 | s0 -> s0 [label="pairing_req/Empty"];
16 | s1 -> s0 [label="scan_req/Adv"];
17 | s1 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
18 | s1 -> s1 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
19 | s1 -> s1 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
20 | s1 -> s1 [label="feature_rsp/BTLE|BTLE_DATA"];
21 | s1 -> s1 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
22 | s1 -> s3 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
23 | s1 -> s1 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
24 | s1 -> s2 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Hdr|SM_Pairing_Response"];
25 | s2 -> s0 [label="scan_req/Adv"];
26 | s2 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
27 | s2 -> s2 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
28 | s2 -> s2 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
29 | s2 -> s2 [label="feature_rsp/BTLE|BTLE_DATA"];
30 | s2 -> s2 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
31 | s2 -> s4 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
32 | s2 -> s2 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
33 | s2 -> s1 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Failed|SM_Hdr"];
34 | s3 -> s0 [label="scan_req/Adv"];
35 | s3 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
36 | s3 -> s3 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
37 | s3 -> s3 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
38 | s3 -> s3 [label="feature_rsp/BTLE|BTLE_DATA"];
39 | s3 -> s3 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
40 | s3 -> s3 [label="version_req/BTLE|BTLE_DATA"];
41 | s3 -> s3 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
42 | s3 -> s4 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Hdr|SM_Pairing_Response"];
43 | s4 -> s0 [label="scan_req/Adv"];
44 | s4 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
45 | s4 -> s4 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
46 | s4 -> s4 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
47 | s4 -> s4 [label="feature_rsp/BTLE|BTLE_DATA"];
48 | s4 -> s4 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
49 | s4 -> s4 [label="version_req/BTLE|BTLE_DATA"];
50 | s4 -> s4 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
51 | s4 -> s3 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Failed|SM_Hdr"];
52 | __start0 [label="", shape=none];
53 | __start0 -> s0 [label=""];
54 | }
55 |
--------------------------------------------------------------------------------
/DotModels/Bluetooth/CYBLE-416045-02.dot:
--------------------------------------------------------------------------------
1 | digraph "cyble-416045-02" {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s0 -> s0 [label="scan_req/Adv"];
6 | s0 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
7 | s0 -> s0 [label="length_req/Empty"];
8 | s0 -> s0 [label="length_rsp/Empty"];
9 | s0 -> s0 [label="feature_rsp/Empty"];
10 | s0 -> s0 [label="feature_req/Empty"];
11 | s0 -> s0 [label="version_req/Empty"];
12 | s0 -> s0 [label="mtu_req/Empty"];
13 | s0 -> s0 [label="pairing_req/Empty"];
14 | s1 -> s0 [label="scan_req/Adv"];
15 | s1 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
16 | s1 -> s1 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
17 | s1 -> s1 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
18 | s1 -> s1 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_REJECT_IND"];
19 | s1 -> s1 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
20 | s1 -> s2 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
21 | s1 -> s1 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
22 | s1 -> s1 [label="pairing_req/BTLE|BTLE_DATA"];
23 | s2 -> s0 [label="scan_req/Adv"];
24 | s2 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
25 | s2 -> s2 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
26 | s2 -> s2 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
27 | s2 -> s2 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_REJECT_IND"];
28 | s2 -> s2 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
29 | s2 -> s2 [label="version_req/BTLE|BTLE_DATA"];
30 | s2 -> s2 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
31 | s2 -> s2 [label="pairing_req/BTLE|BTLE_DATA"];
32 | __start0 [label="", shape=none];
33 | __start0 -> s0 [label=""];
34 | }
35 |
--------------------------------------------------------------------------------
/DotModels/Bluetooth/bluetooth_model.dot:
--------------------------------------------------------------------------------
1 | digraph LearnedModel {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s0 -> s0 [label="i0/o0"];
6 | s0 -> s1 [label="i1/o1"];
7 | s0 -> s0 [label="i2/o2"];
8 | s0 -> s0 [label="i3/o2"];
9 | s0 -> s0 [label="i4/o2"];
10 | s0 -> s0 [label="i5/o2"];
11 | s0 -> s0 [label="i6/o2"];
12 | s0 -> s0 [label="i7/o2"];
13 | s0 -> s0 [label="i8/o2"];
14 | s1 -> s0 [label="i0/o0"];
15 | s1 -> s1 [label="i1/o1"];
16 | s1 -> s1 [label="i2/o3"];
17 | s1 -> s1 [label="i3/o3"];
18 | s1 -> s1 [label="i4/o4"];
19 | s1 -> s1 [label="i5/o5"];
20 | s1 -> s2 [label="i6/o6"];
21 | s1 -> s1 [label="i7/o7"];
22 | s1 -> s1 [label="i8/o8"];
23 | s2 -> s0 [label="i0/o0"];
24 | s2 -> s1 [label="i1/o1"];
25 | s2 -> s2 [label="i2/o3"];
26 | s2 -> s2 [label="i3/o3"];
27 | s2 -> s2 [label="i4/o4"];
28 | s2 -> s2 [label="i5/o5"];
29 | s2 -> s2 [label="i6/o1"];
30 | s2 -> s2 [label="i7/o7"];
31 | s2 -> s2 [label="i8/o8"];
32 | __start0 [label="", shape=none];
33 | __start0 -> s0 [label=""];
34 | }
--------------------------------------------------------------------------------
/DotModels/Bluetooth/bluetooth_reduced.dot:
--------------------------------------------------------------------------------
1 | digraph LearnedModel {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s0 -> s0 [label="scan_req/Adv"];
6 | s0 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
7 | s0 -> s0 [label="length_req/Empty"];
8 | s0 -> s0 [label="length_rsp/Empty"];
9 | s0 -> s0 [label="feature_rsp/Empty"];
10 | s0 -> s0 [label="feature_req/Empty"];
11 | s0 -> s0 [label="version_req/Empty"];
12 | s0 -> s0 [label="mtu_req/Empty"];
13 | s0 -> s0 [label="pairing_req/Empty"];
14 | s1 -> s0 [label="scan_req/Adv"];
15 | s1 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
16 | s1 -> s1 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
17 | s1 -> s1 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
18 | s1 -> s1 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_REJECT_IND"];
19 | s1 -> s1 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
20 | s1 -> s2 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
21 | s1 -> s1 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
22 | s1 -> s1 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Failed|SM_Hdr"];
23 | s2 -> s0 [label="scan_req/Adv"];
24 | s2 -> s1 [label="connection_req/BTLE|BTLE_DATA"];
25 | s2 -> s2 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
26 | s2 -> s2 [label="length_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
27 | s2 -> s2 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_REJECT_IND"];
28 | s2 -> s2 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
29 | s2 -> s2 [label="version_req/BTLE|BTLE_DATA"];
30 | s2 -> s2 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
31 | s2 -> s2 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Failed|SM_Hdr"];
32 | __start0 [label="", shape=none];
33 | __start0 -> s0 [label=""];
34 | }
--------------------------------------------------------------------------------
/DotModels/Bluetooth/cc2652r1.dot:
--------------------------------------------------------------------------------
1 | digraph "CC2652R1" {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s3 [label=s3];
6 | s0 -> s0 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
7 | s0 -> s0 [label="length_rsp/BTLE|BTLE_DATA"];
8 | s0 -> s2 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_REQ"];
9 | s0 -> s0 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
10 | s0 -> s0 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
11 | s0 -> s0 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
12 | s0 -> s1 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Hdr|SM_Pairing_Response"];
13 | s1 -> s1 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
14 | s1 -> s1 [label="length_rsp/BTLE|BTLE_DATA"];
15 | s1 -> s3 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_REQ"];
16 | s1 -> s1 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
17 | s1 -> s1 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
18 | s1 -> s1 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
19 | s1 -> s0 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Failed|SM_Hdr"];
20 | s2 -> s2 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
21 | s2 -> s0 [label="length_rsp/BTLE|BTLE_DATA"];
22 | s2 -> s2 [label="feature_rsp/BTLE|BTLE_DATA"];
23 | s2 -> s2 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
24 | s2 -> s2 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
25 | s2 -> s2 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
26 | s2 -> s3 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Hdr|SM_Pairing_Response"];
27 | s3 -> s3 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
28 | s3 -> s1 [label="length_rsp/BTLE|BTLE_DATA"];
29 | s3 -> s3 [label="feature_rsp/BTLE|BTLE_DATA"];
30 | s3 -> s3 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
31 | s3 -> s3 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
32 | s3 -> s3 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
33 | s3 -> s2 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Failed|SM_Hdr"];
34 | __start0 [label="", shape=none];
35 | __start0 -> s0 [label=""];
36 | }
37 |
--------------------------------------------------------------------------------
/DotModels/Bluetooth/nRF52832.dot:
--------------------------------------------------------------------------------
1 | digraph "nRF52832" {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s3 [label=s3];
6 | s4 [label=s4];
7 | s0 -> s0 [label="scan_req/Adv"];
8 | s0 -> s1 [label="connection_req/BTLE|BTLE_DATA|L2CAP_Hdr|Raw|SM_Hdr"];
9 | s0 -> s0 [label="length_req/Empty"];
10 | s0 -> s0 [label="length_rsp/Empty"];
11 | s0 -> s0 [label="feature_rsp/Empty"];
12 | s0 -> s0 [label="feature_req/Empty"];
13 | s0 -> s0 [label="version_req/Empty"];
14 | s0 -> s0 [label="mtu_req/Empty"];
15 | s0 -> s0 [label="pairing_req/Empty"];
16 | s1 -> s0 [label="scan_req/Adv"];
17 | s1 -> s1 [label="connection_req/BTLE|BTLE_DATA|L2CAP_Hdr|Raw|SM_Hdr"];
18 | s1 -> s1 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
19 | s1 -> s0 [label="length_rsp/BTLE|BTLE_DATA"];
20 | s1 -> s1 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
21 | s1 -> s1 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
22 | s1 -> s3 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
23 | s1 -> s2 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
24 | s1 -> s1 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Hdr|SM_Pairing_Response"];
25 | s2 -> s0 [label="scan_req/Adv"];
26 | s2 -> s1 [label="connection_req/BTLE|BTLE_DATA|L2CAP_Hdr|Raw|SM_Hdr"];
27 | s2 -> s2 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
28 | s2 -> s0 [label="length_rsp/BTLE|BTLE_DATA"];
29 | s2 -> s2 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
30 | s2 -> s2 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
31 | s2 -> s4 [label="version_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_VERSION_IND"];
32 | s2 -> s2 [label="mtu_req/ATT_Error_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
33 | s2 -> s2 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Hdr|SM_Pairing_Response"];
34 | s3 -> s0 [label="scan_req/Adv"];
35 | s3 -> s1 [label="connection_req/BTLE|BTLE_DATA|L2CAP_Hdr|Raw|SM_Hdr"];
36 | s3 -> s3 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
37 | s3 -> s0 [label="length_rsp/BTLE|BTLE_DATA"];
38 | s3 -> s3 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
39 | s3 -> s3 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
40 | s3 -> s3 [label="version_req/BTLE|BTLE_DATA"];
41 | s3 -> s4 [label="mtu_req/ATT_Exchange_MTU_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
42 | s3 -> s3 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Hdr|SM_Pairing_Response"];
43 | s4 -> s0 [label="scan_req/Adv"];
44 | s4 -> s1 [label="connection_req/BTLE|BTLE_DATA|L2CAP_Hdr|Raw|SM_Hdr"];
45 | s4 -> s4 [label="length_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_LENGTH_RSP"];
46 | s4 -> s0 [label="length_rsp/BTLE|BTLE_DATA"];
47 | s4 -> s4 [label="feature_rsp/BTLE|BTLE_CTRL|BTLE_DATA|LL_UNKNOWN_RSP"];
48 | s4 -> s4 [label="feature_req/BTLE|BTLE_CTRL|BTLE_DATA|LL_FEATURE_RSP"];
49 | s4 -> s4 [label="version_req/BTLE|BTLE_DATA"];
50 | s4 -> s4 [label="mtu_req/ATT_Error_Response|ATT_Hdr|BTLE|BTLE_DATA|L2CAP_Hdr"];
51 | s4 -> s4 [label="pairing_req/BTLE|BTLE_DATA|L2CAP_Hdr|SM_Hdr|SM_Pairing_Response"];
52 | __start0 [label="", shape=none];
53 | __start0 -> s0 [label=""];
54 | }
55 |
--------------------------------------------------------------------------------
/DotModels/MDPs/faulty_car_alarm.dot:
--------------------------------------------------------------------------------
1 | digraph faulty_car_alarm {
2 | q1_locked_closed [label="N"];
3 | q2_locked_open [label="A"];
4 | q3_locked_closed [label="A"];
5 | q5_unlocked_closed [label="N"];
6 | q6_unlocked_open [label="N"];
7 | q7_locked_open [label="N"];
8 | q4_faulty [label="N"];
9 | q1_locked_closed -> q2_locked_open [label="d:1"];
10 | q1_locked_closed -> q5_unlocked_closed [label="l:1"];
11 | q2_locked_open -> q3_locked_closed [label="d:1"];
12 | q2_locked_open -> q6_unlocked_open [label="l:1"];
13 | q3_locked_closed -> q2_locked_open [label="d:1"];
14 | q3_locked_closed -> q5_unlocked_closed [label="l:1"];
15 | q5_unlocked_closed -> q6_unlocked_open [label="d:1"];
16 | q5_unlocked_closed -> q1_locked_closed [label="l:1"];
17 | q6_unlocked_open -> q5_unlocked_closed [label="d:1"];
18 | q6_unlocked_open -> q7_locked_open [label="l:1"];
19 | q7_locked_open -> q4_faulty [label="d:1"];
20 | q7_locked_open -> q6_unlocked_open [label="l:1"];
21 | q4_faulty -> q2_locked_open [label="d:0.9"];
22 | q4_faulty -> q7_locked_open [label="d:0.1"];
23 | q4_faulty -> q5_unlocked_closed [label="l:1"];
24 | __start0 [label="", shape=none];
25 | __start0 -> q1_locked_closed [label=""];
26 | }
27 |
--------------------------------------------------------------------------------
/DotModels/TLS/JSSE_1.8.0_25_server_regular.dot:
--------------------------------------------------------------------------------
1 | digraph g {
2 | __start0 [shape="none", label=""];
3 | s0 [shape="circle", label="0"];
4 | s1 [shape="circle", label="1"];
5 | s2 [shape="circle", label="2"];
6 | s3 [shape="circle", label="3"];
7 | s4 [shape="circle", label="4"];
8 | s5 [shape="circle", label="5"];
9 | s6 [shape="circle", label="6"];
10 | s7 [shape="circle", label="7"];
11 | s8 [shape="circle", label="8"];
12 | s8 -> s3 [label=Empty>];
13 | s8 -> s2 [label=Alert Fatal (Unexpected message) / ConnectionClosed>];
14 | s8 -> s2 [label=Alert Fatal (Handshake failure) / ConnectionClosed>];
15 | s8 -> s8 [label=ServerHello / Certificate / ServerHelloDone>];
16 | s8 -> s8 [label=Empty>];
17 | s3 -> s3 [label=Empty>];
18 | s3 -> s2 [label=Alert Fatal (Internal error) / ConnectionClosed>];
19 | s3 -> s2 [label=Alert Fatal (Unexpected message) / ConnectionClosed>];
20 | s3 -> s6 [label=ChangeCipherSpec / Finished>];
21 | s3 -> s5 [label=Empty>];
22 | s3 -> s4 [label=ServerHello / Certificate / ServerHelloDone>];
23 | s2 -> s2 [label=ConnectionClosed>];
24 | s1 -> s3 [label=Empty>];
25 | s1 -> s2 [label=ChangeCipherSpecDecryption failed>];
26 | s1 -> s2 [label=Alert Fatal (Unexpected message) / ConnectionClosed>];
27 | s1 -> s1 [label=Empty>];
28 | s0 -> s2 [label=Alert Fatal (Internal error) / ConnectionClosed>];
29 | s0 -> s2 [label=Alert Fatal (Unexpected message) / ConnectionClosed>];
30 | s0 -> s1 [label=ServerHello / Certificate / ServerHelloDone>];
31 | s7 -> s2 [label=Alert Fatal (Bad record MAC) / ConnectionClosed>];
32 | s7 -> s2 [label=Alert Fatal (Handshake failure) / ConnectionClosed>];
33 | s6 -> s2 [label=Alert Fatal (Internal error) / ConnectionClosed>];
34 | s6 -> s2 [label=Alert Fatal (Handshake failure) / ConnectionClosed>];
35 | s6 -> s2 [label=Alert Fatal (Unexpected message) / ConnectionClosed>];
36 | s6 -> s6 [label=ApplicationData>];
37 | s6 -> s6 [label=Empty>];
38 | s5 -> s2 [label=Alert Fatal (Internal error) / ConnectionClosed>];
39 | s5 -> s2 [label=Alert Fatal (Unexpected message) / ConnectionClosed>];
40 | s5 -> s8 [label=ServerHello / Certificate / ServerHelloDone>];
41 | s5 -> s6 [label=ChangeCipherSpec / Finished>];
42 | s5 -> s5 [label=Empty>];
43 | s4 -> s3 [label=Empty>];
44 | s4 -> s2 [label=Alert Fatal (Unexpected message) / ConnectionClosed>];
45 | s4 -> s2 [label=Alert Fatal (Handshake failure) / ConnectionClosed>];
46 | s4 -> s7 [label=Empty>];
47 | s4 -> s4 [label=ServerHello / Certificate / ServerHelloDone>];
48 | s4 -> s4 [label=Empty>];
49 | __start0 -> s0 [label=Empty>];
50 | }
51 |
--------------------------------------------------------------------------------
/DotModels/TLS/OpenSSL_1.0.2_server_regular.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | 6 [label="s6"]
3 | 0 [label="s0"]
4 | 1 [label="s1"]
5 | 2 [label="s2"]
6 | 3 [label="s3"]
7 | 4 [label="s4"]
8 | 5 [label="s5"]
9 | 6 -> 4 [label="ApplicationData/ConnectionClosed"]
10 | 6 -> 5 [label="ApplicationDataEmpty/Empty"]
11 | 6 -> 4 [label="ChangeCipherSpec/Empty"]
12 | 6 -> 1 [label="ClientHelloRSA/ServerHello & Certificate & ServerHelloDone"]
13 | 6 -> 4 [label="ClientKeyExchange/ConnectionClosed"]
14 | 6 -> 4 [label="EmptyCertificate/ConnectionClosed"]
15 | 6 -> 4 [label="Finished/ConnectionClosed"]
16 | 0 -> 4 [label="ApplicationData/Alert Fatal (Unexpected message) & ConnectionClosed"]
17 | 0 -> 0 [label="ApplicationDataEmpty/Empty"]
18 | 0 -> 4 [label="ChangeCipherSpec/Alert Fatal (Unexpected message) & ConnectionClosed"]
19 | 0 -> 4 [label="ClientHelloRSA/Alert Fatal (Unexpected message) & ConnectionClosed"]
20 | 0 -> 4 [label="ClientKeyExchange/Alert Fatal (Unexpected message) & ConnectionClosed"]
21 | 0 -> 4 [label="EmptyCertificate/Alert Fatal (Unexpected message) & ConnectionClosed"]
22 | 0 -> 3 [label="Finished/ChangeCipherSpec & Finished"]
23 | 1 -> 4 [label="ApplicationData/Alert Fatal (Unexpected message) & ConnectionClosed"]
24 | 1 -> 1 [label="ApplicationDataEmpty/Empty"]
25 | 1 -> 4 [label="ChangeCipherSpec/Alert Fatal (Unexpected message) & ConnectionClosed"]
26 | 1 -> 4 [label="ClientHelloRSA/Alert Fatal (Unexpected message) & ConnectionClosed"]
27 | 1 -> 2 [label="ClientKeyExchange/Empty"]
28 | 1 -> 4 [label="EmptyCertificate/Alert Fatal (Unexpected message) & ConnectionClosed"]
29 | 1 -> 4 [label="Finished/Alert Fatal (Unexpected message) & ConnectionClosed"]
30 | 2 -> 4 [label="ApplicationData/Alert Fatal (Unexpected message) & ConnectionClosed"]
31 | 2 -> 2 [label="ApplicationDataEmpty/Empty"]
32 | 2 -> 0 [label="ChangeCipherSpec/Empty"]
33 | 2 -> 4 [label="ClientHelloRSA/Alert Fatal (Unexpected message) & ConnectionClosed"]
34 | 2 -> 4 [label="ClientKeyExchange/Alert Fatal (Unexpected message) & ConnectionClosed"]
35 | 2 -> 4 [label="EmptyCertificate/Alert Fatal (Unexpected message) & ConnectionClosed"]
36 | 2 -> 4 [label="Finished/Alert Fatal (Unexpected message) & ConnectionClosed"]
37 | 3 -> 4 [label="ApplicationData/ApplicationData & ConnectionClosed"]
38 | 3 -> 3 [label="ApplicationDataEmpty/Empty"]
39 | 3 -> 4 [label="ChangeCipherSpec/Alert Fatal (Unexpected message) & ConnectionClosed"]
40 | 3 -> 4 [label="ClientHelloRSA/Alert Fatal (Handshake failure) & ConnectionClosed"]
41 | 3 -> 4 [label="ClientKeyExchange/Alert Fatal (Unexpected message) & ConnectionClosed"]
42 | 3 -> 4 [label="EmptyCertificate/Alert Fatal (Unexpected message) & ConnectionClosed"]
43 | 3 -> 4 [label="Finished/Alert Fatal (Unexpected message) & ConnectionClosed"]
44 | 4 -> 4 [label="ApplicationData/ConnectionClosed"]
45 | 4 -> 4 [label="ApplicationDataEmpty/ConnectionClosed"]
46 | 4 -> 4 [label="ChangeCipherSpec/ConnectionClosed"]
47 | 4 -> 4 [label="ClientHelloRSA/ConnectionClosed"]
48 | 4 -> 4 [label="ClientKeyExchange/ConnectionClosed"]
49 | 4 -> 4 [label="EmptyCertificate/ConnectionClosed"]
50 | 4 -> 4 [label="Finished/ConnectionClosed"]
51 | 5 -> 4 [label="ApplicationData/ConnectionClosed"]
52 | 5 -> 4 [label="ApplicationDataEmpty/Empty"]
53 | 5 -> 4 [label="ChangeCipherSpec/ConnectionClosed"]
54 | 5 -> 4 [label="ClientHelloRSA/ConnectionClosed"]
55 | 5 -> 4 [label="ClientKeyExchange/ConnectionClosed"]
56 | 5 -> 4 [label="EmptyCertificate/ConnectionClosed"]
57 | 5 -> 4 [label="Finished/ConnectionClosed"]
58 | __start0 [label="", shape=none];
59 | __start0 -> 6 [label=""];
60 | }
61 |
--------------------------------------------------------------------------------
/DotModels/TLS/miTLS_0.1.3_server_regular.dot:
--------------------------------------------------------------------------------
1 | digraph {
2 | 2 [label="s2"]
3 | 0 [label="s0"]
4 | 1 [label="s1"]
5 | 3 [label="s3"]
6 | 4 [label="s4"]
7 | 5 [label="s5"]
8 | 2 -> 5 [label="ApplicationData/ConnectionClosed"]
9 | 2 -> 5 [label="ApplicationDataEmpty/Alert Fatal (Illegal parameter) & ConnectionClosed"]
10 | 2 -> 5 [label="ChangeCipherSpec/ConnectionClosed"]
11 | 2 -> 1 [label="ClientHelloRSA/ServerHello & Certificate & ServerHelloDone"]
12 | 2 -> 5 [label="ClientKeyExchange/Alert Fatal (Unexpected message) & ConnectionClosed"]
13 | 2 -> 5 [label="EmptyCertificate/Alert Fatal (Unexpected message) & ConnectionClosed"]
14 | 2 -> 5 [label="Finished/Alert Fatal (Unexpected message) & ConnectionClosed"]
15 | 2 -> 5 [label="HeartbeatRequest/ConnectionClosed"]
16 | 0 -> 5 [label="ApplicationData/ApplicationDataApplicationDataApplicationDataApplicationDataApplicationDataApplicationData & ConnectionClosed"]
17 | 0 -> 0 [label="ApplicationDataEmpty/Empty"]
18 | 0 -> 5 [label="ChangeCipherSpec/Alert Fatal (Unexpected message) & ConnectionClosed"]
19 | 0 -> 5 [label="ClientHelloRSA/Alert Fatal (Handshake failure) & ConnectionClosed"]
20 | 0 -> 5 [label="ClientKeyExchange/Alert Fatal (Unexpected message) & ConnectionClosed"]
21 | 0 -> 5 [label="EmptyCertificate/Alert Fatal (Unexpected message) & ConnectionClosed"]
22 | 0 -> 5 [label="Finished/Alert Fatal (Unexpected message) & ConnectionClosed"]
23 | 0 -> 5 [label="HeartbeatRequest/ConnectionClosed"]
24 | 1 -> 5 [label="ApplicationData/ConnectionClosed"]
25 | 1 -> 5 [label="ApplicationDataEmpty/Alert Fatal (Illegal parameter) & ConnectionClosed"]
26 | 1 -> 5 [label="ChangeCipherSpec/Alert Fatal (Unexpected message) & ConnectionClosed"]
27 | 1 -> 5 [label="ClientHelloRSA/Alert Fatal (Unexpected message) & ConnectionClosed"]
28 | 1 -> 3 [label="ClientKeyExchange/Empty"]
29 | 1 -> 5 [label="EmptyCertificate/Alert Fatal (Unexpected message) & ConnectionClosed"]
30 | 1 -> 5 [label="Finished/Alert Fatal (Unexpected message) & ConnectionClosed"]
31 | 1 -> 5 [label="HeartbeatRequest/ConnectionClosed"]
32 | 3 -> 5 [label="ApplicationData/ConnectionClosed"]
33 | 3 -> 5 [label="ApplicationDataEmpty/Alert Fatal (Illegal parameter) & ConnectionClosed"]
34 | 3 -> 4 [label="ChangeCipherSpec/Empty"]
35 | 3 -> 5 [label="ClientHelloRSA/Alert Fatal (Unexpected message) & ConnectionClosed"]
36 | 3 -> 5 [label="ClientKeyExchange/Alert Fatal (Unexpected message) & ConnectionClosed"]
37 | 3 -> 5 [label="EmptyCertificate/Alert Fatal (Unexpected message) & ConnectionClosed"]
38 | 3 -> 5 [label="Finished/Alert Fatal (Unexpected message) & ConnectionClosed"]
39 | 3 -> 5 [label="HeartbeatRequest/ConnectionClosed"]
40 | 4 -> 5 [label="ApplicationData/ConnectionClosed"]
41 | 4 -> 5 [label="ApplicationDataEmpty/ConnectionClosed"]
42 | 4 -> 5 [label="ChangeCipherSpec/ConnectionClosed"]
43 | 4 -> 5 [label="ClientHelloRSA/Alert Fatal (Unexpected message) & ConnectionClosed"]
44 | 4 -> 5 [label="ClientKeyExchange/Alert Fatal (Unexpected message) & ConnectionClosed"]
45 | 4 -> 5 [label="EmptyCertificate/Alert Fatal (Unexpected message) & ConnectionClosed"]
46 | 4 -> 0 [label="Finished/ChangeCipherSpec & Finished"]
47 | 4 -> 5 [label="HeartbeatRequest/ConnectionClosed"]
48 | 5 -> 5 [label="ApplicationData/ConnectionClosed"]
49 | 5 -> 5 [label="ApplicationDataEmpty/ConnectionClosed"]
50 | 5 -> 5 [label="ChangeCipherSpec/ConnectionClosed"]
51 | 5 -> 5 [label="ClientHelloRSA/ConnectionClosed"]
52 | 5 -> 5 [label="ClientKeyExchange/ConnectionClosed"]
53 | 5 -> 5 [label="EmptyCertificate/ConnectionClosed"]
54 | 5 -> 5 [label="Finished/ConnectionClosed"]
55 | 5 -> 5 [label="HeartbeatRequest/ConnectionClosed"]
56 | __start0 [label="", shape=none];
57 | __start0 -> 2 [label=""];
58 | }
59 |
--------------------------------------------------------------------------------
/DotModels/arithmetics.dot:
--------------------------------------------------------------------------------
1 | digraph learnedModel {
2 | s0 [label="s0", shape=circle];
3 | s1 [label="s1", shape=doublecircle];
4 | s0 -> s1 [label="1"];
5 | s0 -> s0 [label="( / push(()"];
6 | s1 -> s0 [label="+"];
7 | s1 -> s1 [label=") / pop(()"];
8 | __start0 [label="", shape=none];
9 | __start0 -> s0 [label=""];
10 | }
--------------------------------------------------------------------------------
/DotModels/car_alarm.dot:
--------------------------------------------------------------------------------
1 | digraph car_alarm {
2 | q1_locked_closed [label="N"];
3 | q2_locked_open [label="A"];
4 | q3_locked_closed [label="A"];
5 | q5_unlocked_closed [label="N"];
6 | q6_unlocked_open [label="N"];
7 | q7_locked_open [label="N"];
8 | q1_locked_closed -> q2_locked_open [label="d"];
9 | q1_locked_closed -> q5_unlocked_closed [label="l"];
10 | q2_locked_open -> q3_locked_closed [label="d"];
11 | q2_locked_open -> q6_unlocked_open [label="l"];
12 | q3_locked_closed -> q2_locked_open [label="d"];
13 | q3_locked_closed -> q5_unlocked_closed [label="l"];
14 | q5_unlocked_closed -> q6_unlocked_open [label="d"];
15 | q5_unlocked_closed -> q1_locked_closed [label="l"];
16 | q6_unlocked_open -> q5_unlocked_closed [label="d"];
17 | q6_unlocked_open -> q7_locked_open [label="l"];
18 | q7_locked_open -> q1_locked_closed [label="d"];
19 | q7_locked_open -> q6_unlocked_open [label="l"];
20 | __start0 [label="", shape=none];
21 | __start0 -> q1_locked_closed [label=""];
22 | }
23 |
--------------------------------------------------------------------------------
/DotModels/coffee_mealy.dot:
--------------------------------------------------------------------------------
1 | digraph coffee_mealy {
2 | s0 [label="s0"];
3 | s1 [label="s1"];
4 | s0 -> s1 [label="coin/ beep"];
5 | s0 -> s0 [label="button/ init"];
6 | s1 -> s1 [label="coin/ beep"];
7 | s1 -> s0 [label="button/ coffee"];
8 | __start0 [label="", shape=none];
9 | __start0 -> s0 [label=""];
10 | }
11 |
--------------------------------------------------------------------------------
/DotModels/coffee_moore.dot:
--------------------------------------------------------------------------------
1 | digraph g {
2 | __start0 [label="" shape="none"];
3 | __start0 -> A;
4 | A [shape="record", style="rounded", label="{ A | init }"];
5 | B [shape="record", style="rounded", label="{ B | beep }"];
6 | C [shape="doublecircle", style="rounded", label="{ C | coffee }"];
7 | A -> B [label="coin"];
8 | A -> A [label="button"];
9 | B -> C [label="button"];
10 | B -> B [label="coin"];
11 | C -> B [label="coin"];
12 | C -> A [label="button"];
13 | }
14 |
--------------------------------------------------------------------------------
/DotModels/mooreModel.dot:
--------------------------------------------------------------------------------
1 | digraph g {
2 | __start0 [label="" shape="none"];
3 | __start0 -> A;
4 |
5 | A [shape="record", style="rounded", label="{ A | 0 }"];
6 | B [shape="record", style="rounded", label="{ B | 0 }"];
7 | C [shape="record", style="rounded", label="{ C | 0 }"];
8 | D [shape="record", style="rounded", label="{ D | 0 }"];
9 | E [shape="record", style="rounded", label="{ E | 0 }"];
10 | F [shape="record", style="rounded", label="{ F | 0 }"];
11 | G [shape="record", style="rounded", label="{ G | 0 }"];
12 | H [shape="record", style="rounded", label="{ H | 0 }"];
13 | I [shape="record", style="rounded", label="{ I | 1 }"];
14 |
15 |
16 | A -> D [label="0"];
17 | A -> B [label="1"];
18 | B -> E [label="0"];
19 | B -> C [label="1"];
20 | C -> F [label="0"];
21 | C -> C [label="1"];
22 | D -> G [label="0"];
23 | D -> E [label="1"];
24 | E -> H [label="0"];
25 | E -> F [label="1"];
26 | F -> I [label="0"];
27 | F -> F [label="1"];
28 | G -> G [label="0"];
29 | G -> H [label="1"];
30 | H -> H [label="0"];
31 | H -> I [label="1"];
32 | I -> I [label="0"];
33 | I -> I [label="1"];
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/DotModels/onfsm_0.dot:
--------------------------------------------------------------------------------
1 | digraph g {
2 | __start0 [label="" shape="none"];
3 | q0 [shape="circle" margin=0 label="q0"];
4 | q1 [shape="circle" margin=0 label="q1"];
5 | q0 -> q0 [label="a/1"];
6 | q0 -> q1 [label="b/0"];
7 | q1 -> q1 [label="b/O"];
8 | q1 -> q1 [label="a/1"];
9 | __start0 -> q0;
10 | }
--------------------------------------------------------------------------------
/DotModels/onfsm_1.dot:
--------------------------------------------------------------------------------
1 | digraph g {
2 | __start0 [label="" shape="none"];
3 | q0 [shape="circle" margin=0 label="q0"];
4 | q2 [shape="circle" margin=0 label="q2"];
5 | q1 [shape="circle" margin=0 label="q1"];
6 | q0 -> q2 [label="b/1"];
7 | q0 -> q0 [label="a/0"];
8 | q0 -> q0 [label="b/2"];
9 | q0 -> q2 [label="a/1"];
10 | q2 -> q1 [label="b/0"];
11 | q2 -> q0 [label="a/2"];
12 | q1 -> q1 [label="a/2"];
13 | q1 -> q2 [label="b/0"];
14 | __start0 -> q1;
15 | }
--------------------------------------------------------------------------------
/DotModels/onfsm_2.dot:
--------------------------------------------------------------------------------
1 | digraph g {
2 | __start0 [label="" shape="none"];
3 | q1 [shape="circle" margin=0 label="q1"];
4 | q0 [shape="circle" margin=0 label="q0"];
5 | q2 [shape="circle" margin=0 label="q2"];
6 | q2 -> q0 [label="b/O"];
7 | q0 -> q1 [label="a/2"];
8 | q2 -> q1 [label="b/0"];
9 | q2 -> q2 [label="a/1"];
10 | q1 -> q2 [label="b/0"];
11 | q1 -> q0 [label="a/2"];
12 | q0 -> q0 [label="b/0"];
13 | __start0 -> q0;
14 | }
--------------------------------------------------------------------------------
/DotModels/onfsm_3.dot:
--------------------------------------------------------------------------------
1 | digraph g {
2 | __start0 [label="" shape="none"];
3 | q5 [shape="circle" margin=0 label="q5"];
4 | q2 [shape="circle" margin=0 label="q2"];
5 | q7 [shape="circle" margin=0 label="q7"];
6 | q8 [shape="circle" margin=0 label="q8"];
7 | q4 [shape="circle" margin=0 label="q4"];
8 | q6 [shape="circle" margin=0 label="q6"];
9 | q0 [shape="circle" margin=0 label="q0"];
10 | q1 [shape="circle" margin=0 label="q1"];
11 | q3 [shape="circle" margin=0 label="q3"];
12 | q8 -> q6 [label="b/0"];
13 | q5 -> q1 [label="b/O"];
14 | q1 -> q3 [label="a/2"];
15 | q7 -> q2 [label="b/0"];
16 | q2 -> q8 [label="b/0"];
17 | q8 -> q8 [label="a/1"];
18 | q6 -> q5 [label="b/0"];
19 | q2 -> q4 [label="a/2"];
20 | q4 -> q4 [label="b/0"];
21 | q1 -> q1 [label="b/0"];
22 | q5 -> q5 [label="a/1"];
23 | q3 -> q7 [label="b/0"];
24 | q6 -> q0 [label="a/2"];
25 | q0 -> q6 [label="a/2"];
26 | q4 -> q2 [label="a/2"];
27 | q3 -> q1 [label="a/2"];
28 | q0 -> q0 [label="b/0"];
29 | q7 -> q7 [label="a/1"];
30 | __start0 -> q1;
31 | }
--------------------------------------------------------------------------------
/DotModels/onfsm_4.dot:
--------------------------------------------------------------------------------
1 | digraph Angluin_Mealy {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s3 [label=s3];
6 | s0 -> s1 [label="a/x"];
7 | s0 -> s2 [label="a/y"];
8 | s0 -> s3 [label="a/z"];
9 |
10 | s1 -> s1 [label="a/0"];
11 | s2 -> s2 [label="a/0"];
12 | s3 -> s3 [label="a/0"];
13 | __start0 [label="", shape=none];
14 | __start0 -> s0 [label=""];
15 | }
--------------------------------------------------------------------------------
/DotModels/onfsm_5.dot:
--------------------------------------------------------------------------------
1 | digraph Angluin_Mealy {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s3 [label=s3];
6 | s4 [label=s4];
7 | s0 -> s1 [label="a/X"];
8 | s0 -> s2 [label="a/Y"];
9 | s0 -> s0 [label="b/Z"];
10 | s1 -> s1 [label="a/X"];
11 | s1 -> s3 [label="b/Z"];
12 | s2 -> s2 [label="a/Y"];
13 | s2 -> s4 [label="b/W"];
14 | s3 -> s0 [label="a/V"];
15 | s3 -> s3 [label="b/Z"];
16 | s4 -> s0 [label="a/V"];
17 | s4 -> s4 [label="b/W"];
18 | __start0 [label="", shape=none];
19 | __start0 -> s0 [label=""];
20 | }
--------------------------------------------------------------------------------
/DotModels/tomitaGrammars/tomita_1.dot:
--------------------------------------------------------------------------------
1 | digraph "tomita_1" {
2 | s0 [label=s0, shape=doublecircle];
3 | s1 [label=s1];
4 | s0 -> s1 [label=0];
5 | s0 -> s0 [label=1];
6 | s1 -> s1 [label=0];
7 | s1 -> s1 [label=1];
8 | __start0 [label="", shape=none];
9 | __start0 -> s0 [label=""];
10 | }
11 |
--------------------------------------------------------------------------------
/DotModels/tomitaGrammars/tomita_2.dot:
--------------------------------------------------------------------------------
1 | digraph "tomita_2" {
2 | s0 [label=s0];
3 | s1 [label=s1];
4 | s2 [label=s2, shape=doublecircle];
5 | s3 [label=s3];
6 | s0 -> s3 [label=0];
7 | s0 -> s1 [label=1];
8 | s1 -> s2 [label=0];
9 | s1 -> s3 [label=1];
10 | s2 -> s3 [label=0];
11 | s2 -> s1 [label=1];
12 | s3 -> s3 [label=0];
13 | s3 -> s3 [label=1];
14 | __start0 [label="", shape=none];
15 | __start0 -> s0 [label=""];
16 | }
17 |
--------------------------------------------------------------------------------
/DotModels/tomitaGrammars/tomita_3.dot:
--------------------------------------------------------------------------------
1 | digraph "tomita_3" {
2 | s0 [label=s0, shape=doublecircle];
3 | s1 [label=s1, shape=doublecircle];
4 | s2 [label=s2];
5 | s3 [label=s3];
6 | s4 [label=s4, shape=doublecircle];
7 | s0 -> s0 [label=0];
8 | s0 -> s1 [label=1];
9 | s1 -> s2 [label=0];
10 | s1 -> s0 [label=1];
11 | s2 -> s4 [label=0];
12 | s2 -> s3 [label=1];
13 | s3 -> s3 [label=0];
14 | s3 -> s3 [label=1];
15 | s4 -> s2 [label=0];
16 | s4 -> s4 [label=1];
17 | __start0 [label="", shape=none];
18 | __start0 -> s0 [label=""];
19 | }
20 |
--------------------------------------------------------------------------------
/DotModels/tomitaGrammars/tomita_4.dot:
--------------------------------------------------------------------------------
1 | digraph "tomita_4" {
2 | s0 [label=s0, shape=doublecircle];
3 | s1 [label=s1, shape=doublecircle];
4 | s2 [label=s2, shape=doublecircle];
5 | s3 [label=s3];
6 | s0 -> s1 [label=0];
7 | s0 -> s0 [label=1];
8 | s1 -> s2 [label=0];
9 | s1 -> s0 [label=1];
10 | s2 -> s3 [label=0];
11 | s2 -> s0 [label=1];
12 | s3 -> s3 [label=0];
13 | s3 -> s3 [label=1];
14 | __start0 [label="", shape=none];
15 | __start0 -> s0 [label=""];
16 | }
17 |
--------------------------------------------------------------------------------
/DotModels/tomitaGrammars/tomita_5.dot:
--------------------------------------------------------------------------------
1 | digraph "tomita_5" {
2 | s0 [label=s0, shape=doublecircle];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s3 [label=s3];
6 | s0 -> s1 [label=0];
7 | s0 -> s2 [label=1];
8 | s1 -> s0 [label=0];
9 | s1 -> s3 [label=1];
10 | s2 -> s3 [label=0];
11 | s2 -> s0 [label=1];
12 | s3 -> s2 [label=0];
13 | s3 -> s1 [label=1];
14 | __start0 [label="", shape=none];
15 | __start0 -> s0 [label=""];
16 | }
17 |
--------------------------------------------------------------------------------
/DotModels/tomitaGrammars/tomita_6.dot:
--------------------------------------------------------------------------------
1 | digraph "tomita_6" {
2 | s0 [label=s0, shape=doublecircle];
3 | s1 [label=s1];
4 | s2 [label=s2];
5 | s0 -> s1 [label=0];
6 | s0 -> s2 [label=1];
7 | s1 -> s2 [label=0];
8 | s1 -> s0 [label=1];
9 | s2 -> s0 [label=0];
10 | s2 -> s1 [label=1];
11 | __start0 [label="", shape=none];
12 | __start0 -> s0 [label=""];
13 | }
14 |
--------------------------------------------------------------------------------
/DotModels/tomitaGrammars/tomita_7.dot:
--------------------------------------------------------------------------------
1 | digraph "tomita_7" {
2 | s0 [label=s0, shape=doublecircle];
3 | s1 [label=s1, shape=doublecircle];
4 | s2 [label=s2, shape=doublecircle];
5 | s3 [label=s3, shape=doublecircle];
6 | s4 [label=s4];
7 | s0 -> s0 [label=0];
8 | s0 -> s1 [label=1];
9 | s1 -> s2 [label=0];
10 | s1 -> s1 [label=1];
11 | s2 -> s2 [label=0];
12 | s2 -> s3 [label=1];
13 | s3 -> s4 [label=0];
14 | s3 -> s3 [label=1];
15 | s4 -> s4 [label=0];
16 | s4 -> s4 [label=1];
17 | __start0 [label="", shape=none];
18 | __start0 -> s0 [label=""];
19 | }
20 |
--------------------------------------------------------------------------------
/LICENCE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 TU Graz - SAL Dependable Embedded Systems Lab (DES Lab),
4 | Edi Muskardin
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
--------------------------------------------------------------------------------
/aalpy/SULs/AutomataSUL.py:
--------------------------------------------------------------------------------
1 | from aalpy.base import Automaton
2 | from aalpy.base import SUL
3 |
4 |
5 | class AutomatonSUL(SUL):
6 | def __init__(self, automaton: Automaton):
7 | super().__init__()
8 | self.automaton: Automaton = automaton
9 |
10 | def pre(self):
11 | self.automaton.reset_to_initial()
12 |
13 | def step(self, letter=None):
14 | return self.automaton.step(letter)
15 |
16 | def post(self):
17 | pass
18 |
19 |
20 | MealySUL = OnfsmSUL = StochasticMealySUL = DfaSUL = MooreSUL = MdpSUL = McSUL = SevpaSUL = AutomatonSUL
21 |
--------------------------------------------------------------------------------
/aalpy/SULs/PyMethodSUL.py:
--------------------------------------------------------------------------------
1 | from aalpy.base import SUL
2 |
3 |
4 | class FunctionDecorator:
5 | """
6 | Decorator of methods found in the SUL class.
7 | """
8 |
9 | def __init__(self, function, args=None):
10 | """
11 | Args:
12 |
13 | function: function of the class to be learned
14 |
15 | args: arguments to be passed to the function. Either a single argument, or a list of arguments if
16 | function has more than one parameter.
17 | """
18 |
19 | self.function = function
20 | self.args = None
21 | if args:
22 | self.args = [args] if not isinstance(args, (list, tuple)) else args
23 |
24 | def __repr__(self):
25 | if self.args:
26 | return f'{self.function.__name__}{self.args}'
27 | return self.function.__name__
28 |
29 |
30 | class PyClassSUL(SUL):
31 | """
32 | System under learning for inferring python classes.
33 | """
34 | def __init__(self, python_class):
35 | """
36 | Args:
37 |
38 | python_class: class to be learned
39 | """
40 | super().__init__()
41 | self._class = python_class
42 | self.sul: object = None
43 |
44 | def pre(self):
45 | """
46 | Do the reset by initializing the class again or call reset method of the class
47 | """
48 | self.sul = self._class()
49 |
50 | def post(self):
51 | pass
52 |
53 | def step(self, letter):
54 | """
55 | Executes the function(with arguments) found in letter against the SUL
56 |
57 | Args:
58 |
59 | letter: single input of type FunctionDecorator
60 |
61 | Returns:
62 |
63 | output of the function
64 |
65 | """
66 | if letter.args:
67 | return getattr(self.sul, letter.function.__name__, letter)(*letter.args)
68 | return getattr(self.sul, letter.function.__name__, letter)()
69 |
--------------------------------------------------------------------------------
/aalpy/SULs/RegexSUL.py:
--------------------------------------------------------------------------------
1 | from aalpy.base import SUL
2 | import re
3 |
4 |
5 | class RegexSUL(SUL):
6 | """
7 | An example implementation of a system under learning that can be used to learn any regex expression.
8 | Note that the $ is added to the expression as in this SUL only exact matches are learned.
9 | """
10 | def __init__(self, regex: str):
11 | super().__init__()
12 | self.regex = regex if regex[-1] == '$' else regex + '$'
13 | self.string = ""
14 |
15 | def pre(self):
16 | self.string = ""
17 | pass
18 |
19 | def post(self):
20 | self.string = ""
21 | pass
22 |
23 | def step(self, letter):
24 | """
25 |
26 | Args:
27 |
28 | letter: single element of the input alphabet
29 |
30 | Returns:
31 |
32 | Whether the current string (previous string + letter) is accepted
33 |
34 | """
35 | if letter is not None:
36 | self.string += str(letter)
37 | return True if re.match(self.regex, self.string) else False
38 |
--------------------------------------------------------------------------------
/aalpy/SULs/TomitaSUL.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | from aalpy.base import SUL
4 |
5 |
6 | class TomitaSUL(SUL):
7 | """
8 | Tomita grammars are often used as a benchmark for automata-related challenges. Simple SUL that implements all 7
9 | Tomita grammars and enables their learning.
10 | """
11 |
12 | def __init__(self, tomita_level_fun):
13 | super().__init__()
14 | num_fun_map = {1: tomita_1, 2: tomita_2, 3: tomita_3, 4: tomita_4, 5: tomita_5, 6: tomita_6, 7: tomita_7,
15 | -3: not_tomita_3}
16 | assert tomita_level_fun in num_fun_map.keys()
17 | self.string = ""
18 | self.tomita_level = num_fun_map[tomita_level_fun]
19 |
20 | def pre(self):
21 | self.string = ""
22 | pass
23 |
24 | def post(self):
25 | self.string = ""
26 | pass
27 |
28 | def step(self, letter):
29 | if input:
30 | self.string += str(letter)
31 | return self.tomita_level(self.string)
32 |
33 |
34 | _not_tomita_3 = re.compile("((0|1)*0)*1(11)*(0(0|1)*1)*0(00)*(1(0|1)*)*$")
35 |
36 |
37 | def tomita_1(word):
38 | return "0" not in word
39 |
40 |
41 | def tomita_2(word):
42 | return word == "10" * (int(len(word) / 2))
43 |
44 |
45 | def tomita_3(word):
46 | if not _not_tomita_3.match(word):
47 | return True
48 | return False
49 |
50 |
51 | def not_tomita_3(word):
52 | return not tomita_3(word)
53 |
54 |
55 | def tomita_4(word):
56 | return "000" not in word
57 |
58 |
59 | def tomita_5(word):
60 | return (word.count("0") % 2 == 0) and (word.count("1") % 2 == 0)
61 |
62 |
63 | def tomita_6(word):
64 | return ((word.count("0") - word.count("1")) % 3) == 0
65 |
66 |
67 | def tomita_7(word):
68 | return word.count("10") <= 1
69 |
--------------------------------------------------------------------------------
/aalpy/SULs/__init__.py:
--------------------------------------------------------------------------------
1 | from .AutomataSUL import *
2 | from .PyMethodSUL import FunctionDecorator, PyClassSUL
3 | from .RegexSUL import RegexSUL
4 | from .TomitaSUL import TomitaSUL
5 |
--------------------------------------------------------------------------------
/aalpy/__init__.py:
--------------------------------------------------------------------------------
1 | from .automata import (
2 | Dfa,
3 | DfaState,
4 | MarkovChain,
5 | McState,
6 | Mdp,
7 | MdpState,
8 | MealyMachine,
9 | MealyState,
10 | MooreMachine,
11 | MooreState,
12 | NDMooreMachine,
13 | NDMooreState,
14 | Onfsm,
15 | OnfsmState,
16 | Sevpa,
17 | SevpaAlphabet,
18 | SevpaState,
19 | SevpaTransition,
20 | StochasticMealyMachine,
21 | StochasticMealyState,
22 | )
23 | from .base import (
24 | SUL,
25 | Automaton,
26 | AutomatonState,
27 | CacheTree,
28 | DeterministicAutomaton,
29 | Oracle,
30 | )
31 | from .learning_algs import (
32 | run_abstracted_ONFSM_Lstar,
33 | run_active_Alergia,
34 | run_active_RPNI,
35 | run_Alergia,
36 | run_JAlergia,
37 | run_KV,
38 | run_Lstar,
39 | run_non_det_Lstar,
40 | run_RPNI,
41 | run_stochastic_Lstar,
42 | run_GSM,
43 | run_PAPNI
44 | )
45 | from .oracles import (
46 | BreadthFirstExplorationEqOracle,
47 | CacheBasedEqOracle,
48 | KWayStateCoverageEqOracle,
49 | KWayTransitionCoverageEqOracle,
50 | PacOracle,
51 | PerfectKnowledgeEqOracle,
52 | ProvidedSequencesOracleWrapper,
53 | RandomWalkEqOracle,
54 | RandomWMethodEqOracle,
55 | RandomWordEqOracle,
56 | StatePrefixEqOracle,
57 | TransitionFocusOracle,
58 | UserInputEqOracle,
59 | WMethodEqOracle,
60 | kWayStateCoverageEqOracle,
61 | kWayTransitionCoverageEqOracle,
62 | )
63 | from .SULs import (
64 | AutomatonSUL,
65 | FunctionDecorator,
66 | PyClassSUL,
67 | RegexSUL,
68 | TomitaSUL
69 | )
70 | from .utils import (
71 | CharacterTokenizer,
72 | DataHandler,
73 | DelimiterTokenizer,
74 | IODelimiterTokenizer,
75 | bisimilar,
76 | compare_automata,
77 | convert_i_o_traces_for_RPNI,
78 | generate_random_deterministic_automata,
79 | generate_random_dfa,
80 | generate_random_markov_chain,
81 | generate_random_mdp,
82 | generate_random_mealy_machine,
83 | generate_random_moore_machine,
84 | generate_random_ONFSM,
85 | generate_random_sevpa,
86 | generate_random_smm,
87 | generate_test_cases,
88 | get_correct_prop_values,
89 | get_properties_file,
90 | load_automaton_from_file,
91 | make_input_complete,
92 | mdp_2_prism_format,
93 | model_check_experiment,
94 | model_check_properties,
95 | save_automaton_to_file,
96 | statistical_model_checking,
97 | visualize_automaton,
98 | )
99 |
--------------------------------------------------------------------------------
/aalpy/automata/Dfa.py:
--------------------------------------------------------------------------------
1 | from typing import Generic, Dict
2 |
3 | from aalpy.base import AutomatonState, DeterministicAutomaton
4 | from aalpy.base.Automaton import InputType
5 |
6 |
7 | class DfaState(AutomatonState, Generic[InputType]):
8 | """
9 | Single state of a deterministic finite automaton.
10 | """
11 |
12 | def __init__(self, state_id, is_accepting=False):
13 | super().__init__(state_id)
14 | self.transitions : Dict[InputType, DfaState] = dict()
15 | self.is_accepting = is_accepting
16 |
17 | @property
18 | def output(self):
19 | return self.is_accepting
20 |
21 | class Dfa(DeterministicAutomaton[DfaState[InputType]]):
22 | """
23 | Deterministic finite automaton.
24 | """
25 |
26 | def __init__(self, initial_state: DfaState, states):
27 | super().__init__(initial_state, states)
28 |
29 | def step(self, letter):
30 | """
31 | Args:
32 |
33 | letter: single input that is looked up in the transition table of the DfaState
34 |
35 | Returns:
36 |
37 | True if the reached state is an accepting state, False otherwise
38 | """
39 | if letter is not None:
40 | self.current_state = self.current_state.transitions[letter]
41 | return self.current_state.is_accepting
42 |
43 | def compute_characterization_set(self, char_set_init=None, online_suffix_closure=True, split_all_blocks=True,
44 | return_same_states=False, raise_warning=True):
45 | return super(Dfa, self).compute_characterization_set(char_set_init if char_set_init else [()],
46 | online_suffix_closure, split_all_blocks,
47 | return_same_states, raise_warning)
48 |
49 | def compute_output_seq(self, state, sequence):
50 | if not sequence:
51 | return [state.is_accepting]
52 | return super(Dfa, self).compute_output_seq(state, sequence)
53 |
54 | def execute_sequence(self, origin_state, seq):
55 | if not seq:
56 | return origin_state.output
57 | return super(Dfa, self).execute_sequence(origin_state, seq)
58 |
59 |
60 | def to_state_setup(self):
61 | state_setup_dict = {}
62 |
63 | # ensure prefixes are computed
64 | self.compute_prefixes()
65 |
66 | sorted_states = sorted(self.states, key=lambda x: len(x.prefix) if x.prefix is not None else len(self.states))
67 | for s in sorted_states:
68 | state_setup_dict[s.state_id] = (s.is_accepting, {k: v.state_id for k, v in s.transitions.items()})
69 |
70 | return state_setup_dict
71 |
72 | @staticmethod
73 | def from_state_setup(state_setup : dict, **kwargs):
74 | """
75 | First state in the state setup is the initial state.
76 | Example state setup:
77 | state_setup = {
78 | "a": (True, {"x": "b1", "y": "a"}),
79 | "b1": (False, {"x": "b2", "y": "a"}),
80 | "b2": (True, {"x": "b3", "y": "a"}),
81 | "b3": (False, {"x": "b4", "y": "a"}),
82 | "b4": (False, {"x": "c", "y": "a"}),
83 | "c": (True, {"x": "a", "y": "a"}),
84 | }
85 |
86 | Args:
87 |
88 | state_setup: map from state_id to tuple(output and transitions_dict)
89 |
90 | Returns:
91 |
92 | DFA
93 | """
94 | # state_setup should map from state_id to tuple(is_accepting and transitions_dict)
95 |
96 | # build states with state_id and output
97 | states = {key: DfaState(key, val[0]) for key, val in state_setup.items()}
98 |
99 | # add transitions to states
100 | for state_id, state in states.items():
101 | for _input, target_state_id in state_setup[state_id][1].items():
102 | state.transitions[_input] = states[target_state_id]
103 |
104 | # states to list
105 | states = [state for state in states.values()]
106 |
107 | # build moore machine with first state as starting state
108 | dfa = Dfa(states[0], states)
109 |
110 | for state in states:
111 | state.prefix = dfa.get_shortest_path(dfa.initial_state, state)
112 |
113 | return dfa
--------------------------------------------------------------------------------
/aalpy/automata/MarkovChain.py:
--------------------------------------------------------------------------------
1 | import random
2 | from typing import Generic, Tuple, List
3 |
4 | from aalpy.base import Automaton, AutomatonState
5 | from aalpy.base.Automaton import OutputType
6 |
7 |
8 | class McState(AutomatonState, Generic[OutputType]):
9 | def __init__(self, state_id, output):
10 | super().__init__(state_id)
11 | self.output: OutputType = output
12 | # transitions is a list of tuples (Node(output), probability)
13 | self.transitions: List[Tuple[McState, float]] = list()
14 |
15 |
16 | class MarkovChain(Automaton[McState[OutputType]]):
17 | """Markov Decision Process."""
18 |
19 | def __init__(self, initial_state, states: list):
20 | super().__init__(initial_state, states)
21 |
22 | def reset_to_initial(self):
23 | self.current_state = self.initial_state
24 |
25 | def step(self, letter=None):
26 | """Next step is determined based on transition probabilities of the current state.
27 |
28 | Args:
29 |
30 | letter: input
31 |
32 | Returns:
33 |
34 | output of the current state
35 | """
36 |
37 | if not self.current_state.transitions:
38 | return self.current_state.output
39 |
40 | probability_distributions = [i[1] for i in self.current_state.transitions]
41 | states = [i[0] for i in self.current_state.transitions]
42 |
43 | new_state = random.choices(states, probability_distributions, k=1)[0]
44 |
45 | self.current_state = new_state
46 | return self.current_state.output
47 |
48 | def step_to(self, input):
49 | """Performs a step on the automaton based on the input `inp` and output `out`.
50 |
51 | Args:
52 |
53 | input: input
54 |
55 | Returns:
56 |
57 | output of the reached state, None otherwise
58 | """
59 | for s in self.current_state.transitions:
60 | if s[0].output == input:
61 | self.current_state = s[0]
62 | return self.current_state.output
63 | return None
64 |
65 | @staticmethod
66 | def from_state_setup(state_setup: dict, **kwargs):
67 | raise NotImplementedError() # TODO implement
68 |
69 | def to_state_setup(self):
70 | raise NotImplementedError() # TODO implement
71 |
--------------------------------------------------------------------------------
/aalpy/automata/Mdp.py:
--------------------------------------------------------------------------------
1 | import random
2 | from collections import defaultdict
3 | from typing import Dict, Generic, List, Tuple
4 |
5 | from aalpy.base import Automaton, AutomatonState
6 | from aalpy.base.Automaton import OutputType, InputType
7 |
8 |
9 | class MdpState(AutomatonState, Generic[InputType, OutputType]):
10 | """
11 | For transitions, each transition is a tuple (Node(output), probability)
12 | """
13 | def __init__(self, state_id, output=None):
14 | super().__init__(state_id)
15 | self.output: OutputType = output
16 | # each transition is a tuple (Node(output), probability)
17 | self.transitions: Dict[InputType, List[Tuple[MdpState, float]]] = defaultdict(list)
18 |
19 |
20 | class Mdp(Automaton[MdpState[InputType, OutputType]]):
21 | """Markov Decision Process."""
22 |
23 | def __init__(self, initial_state: MdpState, states: list):
24 | super().__init__(initial_state, states)
25 |
26 | def reset_to_initial(self):
27 | self.current_state = self.initial_state
28 |
29 | def step(self, letter):
30 | """Next step is determined based on transition probabilities of the current state.
31 |
32 | Args:
33 |
34 | letter: input
35 |
36 | Returns:
37 |
38 | output of the current state
39 | """
40 | if letter is None:
41 | return self.current_state.output
42 |
43 | probability_distributions = [i[1] for i in self.current_state.transitions[letter]]
44 | states = [i[0] for i in self.current_state.transitions[letter]]
45 |
46 | new_state = random.choices(states, probability_distributions, k=1)[0]
47 |
48 | self.current_state = new_state
49 | return self.current_state.output
50 |
51 | def step_to(self, inp, out):
52 | """Performs a step on the automaton based on the input `inp` and output `out`.
53 |
54 | Args:
55 |
56 | inp: input
57 | out: output
58 |
59 | Returns:
60 |
61 | output of the reached state, None otherwise
62 | """
63 | for new_state in self.current_state.transitions[inp]:
64 | if new_state[0].output == out:
65 | self.current_state = new_state[0]
66 | return out
67 | return None
68 |
69 | def to_state_setup(self):
70 | state_setup_dict = {}
71 |
72 | # ensure initial state is first in the list
73 | if self.states[0] != self.initial_state:
74 | self.states.remove(self.initial_state)
75 | self.states.insert(0, self.initial_state)
76 |
77 | for s in self.states:
78 | state_setup_dict[s.state_id] = (s.output, {k: [(node.state_id, prob) for node, prob in v]
79 | for k, v in s.transitions.items()})
80 |
81 | return state_setup_dict
82 |
83 | @staticmethod
84 | def from_state_setup(state_setup: dict, **kwargs):
85 | states_map = {key: MdpState(key, output=value[0]) for key, value in state_setup.items()}
86 |
87 | for key, values in state_setup.items():
88 | source = states_map[key]
89 | for i, transitions in values[1].items():
90 | for node, prob in transitions:
91 | source.transitions[i].append((states_map[node], prob))
92 |
93 | initial_state = states_map[list(state_setup.keys())[0]]
94 | return Mdp(initial_state, list(states_map.values()))
95 |
--------------------------------------------------------------------------------
/aalpy/automata/MealyMachine.py:
--------------------------------------------------------------------------------
1 | from typing import Generic, Dict
2 |
3 | from aalpy.base import AutomatonState, DeterministicAutomaton
4 | from aalpy.base.Automaton import OutputType, InputType
5 |
6 |
7 | class MealyState(AutomatonState, Generic[InputType, OutputType]):
8 | """
9 | Single state of a Mealy machine. Each state has an output_fun dictionary that maps inputs to outputs.
10 | """
11 |
12 | def __init__(self, state_id):
13 | super().__init__(state_id)
14 | self.transitions : Dict[InputType, MealyState] = dict()
15 | self.output_fun : Dict[InputType, OutputType] = dict()
16 |
17 |
18 | class MealyMachine(DeterministicAutomaton[MealyState[InputType, OutputType]]):
19 |
20 | def __init__(self, initial_state: MealyState, states):
21 | super().__init__(initial_state, states)
22 |
23 | def step(self, letter):
24 | """
25 | In Mealy machines, outputs depend on the input and the current state.
26 |
27 | Args:
28 |
29 | letter: single input that is looked up in the transition and output functions
30 |
31 | Returns:
32 |
33 | output corresponding to the input from the current state
34 | """
35 | output = self.current_state.output_fun[letter]
36 | self.current_state = self.current_state.transitions[letter]
37 | return output
38 |
39 | def to_state_setup(self):
40 | state_setup_dict = {}
41 |
42 | # ensure prefixes are computed
43 | self.compute_prefixes()
44 |
45 | sorted_states = sorted(self.states, key=lambda x: len(x.prefix) if x.prefix is not None else len(self.states))
46 | for s in sorted_states:
47 | state_setup_dict[s.state_id] = {k: (s.output_fun[k], v.state_id) for k, v in s.transitions.items()}
48 |
49 | return state_setup_dict
50 |
51 | @staticmethod
52 | def from_state_setup(state_setup : dict, **kwargs):
53 | """
54 | First state in the state setup is the initial state.
55 | state_setup = {
56 | "a": {"x": ("o1", "b1"), "y": ("o2", "a")},
57 | "b1": {"x": ("o3", "b2"), "y": ("o1", "a")},
58 | "b2": {"x": ("o1", "b3"), "y": ("o2", "a")},
59 | "b3": {"x": ("o3", "b4"), "y": ("o1", "a")},
60 | "b4": {"x": ("o1", "c"), "y": ("o4", "a")},
61 | "c": {"x": ("o3", "a"), "y": ("o5", "a")},
62 | }
63 |
64 |
65 | Args:
66 |
67 | state_setup:
68 | state_setup should map from state_id to tuple(transitions_dict).
69 |
70 | Returns:
71 |
72 | Mealy Machine
73 | """
74 | # state_setup should map from state_id to tuple(transitions_dict).
75 | # Each entry in transition dict is :