lernen 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +18 -0
- data/README.md +531 -28
- data/Rakefile +29 -7
- data/Steepfile +14 -0
- data/examples/ripper_prism.rb +63 -0
- data/examples/uri_parse_regexp.rb +73 -0
- data/lib/lernen/algorithm/cex_processor/acex.rb +43 -0
- data/lib/lernen/algorithm/cex_processor/prefix_transformer_acex.rb +43 -0
- data/lib/lernen/algorithm/cex_processor.rb +115 -0
- data/lib/lernen/algorithm/kearns_vazirani/discrimination_tree.rb +207 -0
- data/lib/lernen/algorithm/kearns_vazirani/kearns_vazirani_learner.rb +100 -0
- data/lib/lernen/algorithm/kearns_vazirani.rb +44 -0
- data/lib/lernen/algorithm/kearns_vazirani_vpa/discrimination_tree_vpa.rb +246 -0
- data/lib/lernen/algorithm/kearns_vazirani_vpa/kearns_vazirani_vpa_learner.rb +89 -0
- data/lib/lernen/algorithm/kearns_vazirani_vpa.rb +35 -0
- data/lib/lernen/algorithm/learner.rb +82 -0
- data/lib/lernen/algorithm/lsharp/lsharp_learner.rb +367 -0
- data/lib/lernen/algorithm/lsharp/observation_tree.rb +115 -0
- data/lib/lernen/algorithm/lsharp.rb +43 -0
- data/lib/lernen/algorithm/lstar/lstar_learner.rb +49 -0
- data/lib/lernen/algorithm/lstar/observation_table.rb +214 -0
- data/lib/lernen/algorithm/lstar.rb +49 -0
- data/lib/lernen/algorithm/procedural/atr_manager.rb +200 -0
- data/lib/lernen/algorithm/procedural/procedural_learner.rb +223 -0
- data/lib/lernen/algorithm/procedural/procedural_sul.rb +47 -0
- data/lib/lernen/algorithm/procedural/return_indices_acex.rb +58 -0
- data/lib/lernen/algorithm/procedural.rb +57 -0
- data/lib/lernen/algorithm.rb +19 -0
- data/lib/lernen/automaton/dfa.rb +204 -0
- data/lib/lernen/automaton/mealy.rb +108 -0
- data/lib/lernen/automaton/moore.rb +122 -0
- data/lib/lernen/automaton/moore_like.rb +83 -0
- data/lib/lernen/automaton/proc_util.rb +93 -0
- data/lib/lernen/automaton/spa.rb +368 -0
- data/lib/lernen/automaton/transition_system.rb +209 -0
- data/lib/lernen/automaton/vpa.rb +300 -0
- data/lib/lernen/automaton.rb +19 -92
- data/lib/lernen/equiv/combined_oracle.rb +57 -0
- data/lib/lernen/equiv/exhaustive_search_oracle.rb +60 -0
- data/lib/lernen/equiv/moore_like_simulator_oracle.rb +36 -0
- data/lib/lernen/equiv/oracle.rb +109 -0
- data/lib/lernen/equiv/random_walk_oracle.rb +69 -0
- data/lib/lernen/equiv/random_well_matched_word_oracle.rb +139 -0
- data/lib/lernen/equiv/random_word_oracle.rb +71 -0
- data/lib/lernen/equiv/spa_simulator_oracle.rb +39 -0
- data/lib/lernen/equiv/test_words_oracle.rb +42 -0
- data/lib/lernen/equiv/transition_system_simulator_oracle.rb +36 -0
- data/lib/lernen/equiv/vpa_simulator_oracle.rb +48 -0
- data/lib/lernen/equiv.rb +25 -0
- data/lib/lernen/graph.rb +215 -0
- data/lib/lernen/system/block_sul.rb +41 -0
- data/lib/lernen/system/moore_like_simulator.rb +45 -0
- data/lib/lernen/system/moore_like_sul.rb +33 -0
- data/lib/lernen/system/sul.rb +126 -0
- data/lib/lernen/system/transition_system_simulator.rb +40 -0
- data/lib/lernen/system.rb +72 -0
- data/lib/lernen/version.rb +2 -1
- data/lib/lernen.rb +322 -13
- data/rbs_collection.lock.yaml +16 -0
- data/rbs_collection.yaml +14 -0
- data/renovate.json +6 -0
- data/sig/generated/lernen/algorithm/cex_processor/acex.rbs +30 -0
- data/sig/generated/lernen/algorithm/cex_processor/prefix_transformer_acex.rbs +27 -0
- data/sig/generated/lernen/algorithm/cex_processor.rbs +59 -0
- data/sig/generated/lernen/algorithm/kearns_vazirani/discrimination_tree.rbs +68 -0
- data/sig/generated/lernen/algorithm/kearns_vazirani/kearns_vazirani_learner.rbs +51 -0
- data/sig/generated/lernen/algorithm/kearns_vazirani.rbs +32 -0
- data/sig/generated/lernen/algorithm/kearns_vazirani_vpa/discrimination_tree_vpa.rbs +73 -0
- data/sig/generated/lernen/algorithm/kearns_vazirani_vpa/kearns_vazirani_vpa_learner.rbs +51 -0
- data/sig/generated/lernen/algorithm/kearns_vazirani_vpa.rbs +20 -0
- data/sig/generated/lernen/algorithm/learner.rbs +53 -0
- data/sig/generated/lernen/algorithm/lsharp/lsharp_learner.rbs +103 -0
- data/sig/generated/lernen/algorithm/lsharp/observation_tree.rbs +53 -0
- data/sig/generated/lernen/algorithm/lsharp.rbs +38 -0
- data/sig/generated/lernen/algorithm/lstar/lstar_learner.rbs +38 -0
- data/sig/generated/lernen/algorithm/lstar/observation_table.rbs +79 -0
- data/sig/generated/lernen/algorithm/lstar.rbs +37 -0
- data/sig/generated/lernen/algorithm/procedural/atr_manager.rbs +80 -0
- data/sig/generated/lernen/algorithm/procedural/procedural_learner.rbs +79 -0
- data/sig/generated/lernen/algorithm/procedural/procedural_sul.rbs +36 -0
- data/sig/generated/lernen/algorithm/procedural/return_indices_acex.rbs +33 -0
- data/sig/generated/lernen/algorithm/procedural.rbs +27 -0
- data/sig/generated/lernen/algorithm.rbs +10 -0
- data/sig/generated/lernen/automaton/dfa.rbs +93 -0
- data/sig/generated/lernen/automaton/mealy.rbs +61 -0
- data/sig/generated/lernen/automaton/moore.rbs +69 -0
- data/sig/generated/lernen/automaton/moore_like.rbs +63 -0
- data/sig/generated/lernen/automaton/proc_util.rbs +38 -0
- data/sig/generated/lernen/automaton/spa.rbs +125 -0
- data/sig/generated/lernen/automaton/transition_system.rbs +108 -0
- data/sig/generated/lernen/automaton/vpa.rbs +109 -0
- data/sig/generated/lernen/automaton.rbs +15 -0
- data/sig/generated/lernen/equiv/combined_oracle.rbs +27 -0
- data/sig/generated/lernen/equiv/exhaustive_search_oracle.rbs +38 -0
- data/sig/generated/lernen/equiv/moore_like_simulator_oracle.rbs +27 -0
- data/sig/generated/lernen/equiv/oracle.rbs +75 -0
- data/sig/generated/lernen/equiv/random_walk_oracle.rbs +41 -0
- data/sig/generated/lernen/equiv/random_well_matched_word_oracle.rbs +70 -0
- data/sig/generated/lernen/equiv/random_word_oracle.rbs +45 -0
- data/sig/generated/lernen/equiv/spa_simulator_oracle.rbs +30 -0
- data/sig/generated/lernen/equiv/test_words_oracle.rbs +20 -0
- data/sig/generated/lernen/equiv/transition_system_simulator_oracle.rbs +27 -0
- data/sig/generated/lernen/equiv/vpa_simulator_oracle.rbs +33 -0
- data/sig/generated/lernen/equiv.rbs +11 -0
- data/sig/generated/lernen/graph.rbs +80 -0
- data/sig/generated/lernen/system/block_sul.rbs +29 -0
- data/sig/generated/lernen/system/moore_like_simulator.rbs +31 -0
- data/sig/generated/lernen/system/moore_like_sul.rbs +28 -0
- data/sig/generated/lernen/system/sul.rbs +87 -0
- data/sig/generated/lernen/system/transition_system_simulator.rbs +28 -0
- data/sig/generated/lernen/system.rbs +62 -0
- data/sig/generated/lernen/version.rbs +6 -0
- data/sig/generated/lernen.rbs +214 -0
- data/sig-test/generated/test/example_test.rbs +14 -0
- data/sig-test/generated/test/lernen/algorithm/kearns_vazirani_test.rbs +16 -0
- data/sig-test/generated/test/lernen/algorithm/kearns_vazirani_vpa_test.rbs +10 -0
- data/sig-test/generated/test/lernen/algorithm/lsharp_test.rbs +16 -0
- data/sig-test/generated/test/lernen/algorithm/lstar_test.rbs +16 -0
- data/sig-test/generated/test/lernen/algorithm/procedural_test.rbs +10 -0
- data/sig-test/generated/test/lernen/automaton/dfa_test.rbs +19 -0
- data/sig-test/generated/test/lernen/automaton/mealy_test.rbs +19 -0
- data/sig-test/generated/test/lernen/automaton/moore_test.rbs +19 -0
- data/sig-test/generated/test/lernen/automaton/proc_util_test.rbs +19 -0
- data/sig-test/generated/test/lernen/automaton/spa_test.rbs +19 -0
- data/sig-test/generated/test/lernen/automaton/vpa_test.rbs +19 -0
- data/sig-test/generated/test/lernen/equiv/exhaustive_search_oracle_test.rbs +10 -0
- data/sig-test/generated/test/lernen/equiv/random_walk_oracle_test.rbs +10 -0
- data/sig-test/generated/test/lernen/equiv/random_word_oracle_test.rbs +10 -0
- data/sig-test/generated/test/lernen/system/block_sul_test.rbs +16 -0
- data/sig-test/generated/test/lernen/system/moore_like_simulator_test.rbs +16 -0
- data/sig-test/generated/test/lernen/system/transition_system_simulator_test.rbs +13 -0
- data/sig-test/generated/test/lernen/system_test.rbs +11 -0
- data/sig-test/generated/test/lernen_test.rbs +13 -0
- metadata +131 -11
- data/.yardopts +0 -3
- data/lib/lernen/cex_processor.rb +0 -61
- data/lib/lernen/kearns_vazirani.rb +0 -199
- data/lib/lernen/lsharp.rb +0 -335
- data/lib/lernen/lstar.rb +0 -169
- data/lib/lernen/oracle.rb +0 -116
- data/lib/lernen/sul.rb +0 -134
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
module Equiv
|
6
|
+
# RandomWalkOracle provides an implementation of equivalence query
|
7
|
+
# that finds a counterexample by using random walk.
|
8
|
+
#
|
9
|
+
# This takes two important parameters:
|
10
|
+
#
|
11
|
+
# - `max_steps` (default: `1500`): It is a limit of steps of a random walk.
|
12
|
+
# If a random walk is tried up to this value and no counterexample is found,
|
13
|
+
# it returns `nil` finally.
|
14
|
+
# - `reset_prob` (default: `0.09`): It is a probability to reset a random walk.
|
15
|
+
# On resetting a random walk, it resets a word, but it does not reset
|
16
|
+
# a step counter.
|
17
|
+
#
|
18
|
+
# @rbs generic In -- Type for input alphabet
|
19
|
+
# @rbs generic Out -- Type for output values
|
20
|
+
class RandomWalkOracle < Oracle #[In, Out]
|
21
|
+
# @rbs @alphabet: Array[In]
|
22
|
+
# @rbs @max_steps: Integer
|
23
|
+
# @rbs @reset_prob: Float
|
24
|
+
# @rbs @random: Random
|
25
|
+
|
26
|
+
#: (
|
27
|
+
# Array[In] alphabet,
|
28
|
+
# System::SUL[In, Out] sul,
|
29
|
+
# ?max_steps: Integer,
|
30
|
+
# ?reset_prob: Float,
|
31
|
+
# ?random: Random
|
32
|
+
# ) -> void
|
33
|
+
def initialize(alphabet, sul, max_steps: 3000, reset_prob: 0.09, random: Random)
|
34
|
+
super(sul)
|
35
|
+
|
36
|
+
@alphabet = alphabet
|
37
|
+
@max_steps = max_steps
|
38
|
+
@reset_prob = reset_prob
|
39
|
+
@random = random
|
40
|
+
end
|
41
|
+
|
42
|
+
# @rbs override
|
43
|
+
def find_cex(hypothesis)
|
44
|
+
super
|
45
|
+
|
46
|
+
reset_internal(hypothesis)
|
47
|
+
word = []
|
48
|
+
|
49
|
+
@max_steps.times do
|
50
|
+
if @random.rand < @reset_prob
|
51
|
+
reset_internal(hypothesis)
|
52
|
+
word = []
|
53
|
+
end
|
54
|
+
|
55
|
+
word << @alphabet.sample(random: @random)
|
56
|
+
|
57
|
+
hypothesis_output, sul_output = step_internal(hypothesis, word.last)
|
58
|
+
|
59
|
+
if hypothesis_output != sul_output # steep:ignore
|
60
|
+
@sul.shutdown
|
61
|
+
return word
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
module Equiv
|
6
|
+
# RandomWellMatchedWordOracle provides an implementation of equivalence query
|
7
|
+
# that finds a counterexample by using random well-matched word generation.
|
8
|
+
#
|
9
|
+
# This takes three important parameters:
|
10
|
+
#
|
11
|
+
# - `max_words` (default: `100`): It is a limit of number of random words.
|
12
|
+
# If random words is generated and tried up to this value and no counterexample
|
13
|
+
# is found, it returns `nil` finally.
|
14
|
+
# - `min_word_size` (default: `2`): It is the minimal size of randomly generated word.
|
15
|
+
# It should be greater than `0`.
|
16
|
+
# - `max_word_size` (default: `30`): It is the maximal size of randomly generated word.
|
17
|
+
# It should be greater than or equal to `min_word_size`.
|
18
|
+
# - `call_prob` (default: `0.1`): It is a probability to generate call and return subwords.
|
19
|
+
# - `initial_proc` (default `nil`): It is the initial proc character.
|
20
|
+
# If it is specified, the generated words must be started with it.
|
21
|
+
#
|
22
|
+
# @rbs generic In -- Type for input alphabet
|
23
|
+
# @rbs generic Call -- Type for call alphabet
|
24
|
+
# @rbs generic Return -- Type for return alphabet
|
25
|
+
# @rbs generic Out -- Type for output values
|
26
|
+
class RandomWellMatchedWordOracle < Oracle #[In | Call | Return, Out]
|
27
|
+
# @rbs @alphabet: Array[In]
|
28
|
+
# @rbs @call_alphabet: Array[Call]
|
29
|
+
# @rbs @return_alphabet: Array[Return]
|
30
|
+
# @rbs @max_words: Integer
|
31
|
+
# @rbs @min_word_size: Integer
|
32
|
+
# @rbs @max_word_size: Integer
|
33
|
+
# @rbs @call_prob: Float
|
34
|
+
# @rbs @initial_proc: Call | nil
|
35
|
+
# @rbs @random: Random
|
36
|
+
|
37
|
+
#: (
|
38
|
+
# Array[In] alphabet,
|
39
|
+
# Array[Call] call_alphabet,
|
40
|
+
# Array[Return] return_alphabet,
|
41
|
+
# System::SUL[In | Call | Return, Out] sul,
|
42
|
+
# ?max_words: Integer,
|
43
|
+
# ?min_word_size: Integer,
|
44
|
+
# ?max_word_size: Integer,
|
45
|
+
# ?call_prob: Float,
|
46
|
+
# ?initial_proc: Call | nil,
|
47
|
+
# ?random: Random
|
48
|
+
# ) -> void
|
49
|
+
def initialize(
|
50
|
+
alphabet,
|
51
|
+
call_alphabet,
|
52
|
+
return_alphabet,
|
53
|
+
sul,
|
54
|
+
max_words: 100,
|
55
|
+
min_word_size: 2,
|
56
|
+
max_word_size: 30,
|
57
|
+
call_prob: 0.5,
|
58
|
+
initial_proc: nil,
|
59
|
+
random: Random
|
60
|
+
)
|
61
|
+
super(sul)
|
62
|
+
|
63
|
+
@alphabet = alphabet
|
64
|
+
@call_alphabet = call_alphabet
|
65
|
+
@return_alphabet = return_alphabet
|
66
|
+
@max_words = max_words
|
67
|
+
@min_word_size = min_word_size
|
68
|
+
@max_word_size = max_word_size
|
69
|
+
@call_prob = call_prob
|
70
|
+
@initial_proc = initial_proc
|
71
|
+
@random = random
|
72
|
+
end
|
73
|
+
|
74
|
+
# @rbs override
|
75
|
+
def find_cex(hypothesis)
|
76
|
+
super
|
77
|
+
|
78
|
+
@max_words.times do
|
79
|
+
reset_internal(hypothesis)
|
80
|
+
|
81
|
+
word = generate_word
|
82
|
+
word.each_with_index do |input, index|
|
83
|
+
hypothesis_output, sul_output = step_internal(hypothesis, input)
|
84
|
+
|
85
|
+
if hypothesis_output != sul_output # steep:ignore
|
86
|
+
@sul.shutdown
|
87
|
+
return word[0..index]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
#: () -> Array[In | Call | Return]
|
98
|
+
def generate_word
|
99
|
+
word_size = @random.rand(@min_word_size..@max_word_size)
|
100
|
+
|
101
|
+
word = []
|
102
|
+
initial_proc = @initial_proc
|
103
|
+
if initial_proc
|
104
|
+
word << initial_proc
|
105
|
+
generate_word_internal(word, word_size - 2)
|
106
|
+
word << @return_alphabet.sample(random: @random)
|
107
|
+
return word
|
108
|
+
end
|
109
|
+
|
110
|
+
generate_word_internal(word, word_size)
|
111
|
+
word
|
112
|
+
end
|
113
|
+
|
114
|
+
#: (Array[In | Call | Return] word, Integer word_size) -> void
|
115
|
+
def generate_word_internal(word, word_size)
|
116
|
+
return if word_size <= 0
|
117
|
+
|
118
|
+
if word_size == 1
|
119
|
+
word << @alphabet.sample(random: @random) # steep:ignore
|
120
|
+
return
|
121
|
+
end
|
122
|
+
|
123
|
+
if @random.rand < @call_prob
|
124
|
+
call_index = @random.rand(0...word_size - 1)
|
125
|
+
generate_word_internal(word, call_index)
|
126
|
+
word << @call_alphabet.sample(random: @random) # steep:ignore
|
127
|
+
return_index = call_index + 1 + @random.rand(0...word_size - call_index - 1)
|
128
|
+
generate_word_internal(word, return_index - call_index - 1)
|
129
|
+
word << @return_alphabet.sample(random: @random) # steep:ignore
|
130
|
+
generate_word_internal(word, word_size - return_index - 1)
|
131
|
+
else
|
132
|
+
split_size = @random.rand(1...word_size)
|
133
|
+
generate_word_internal(word, split_size)
|
134
|
+
generate_word_internal(word, word_size - split_size)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
module Equiv
|
6
|
+
# RandomWordOracle provides an implementation of equivalence query
|
7
|
+
# that finds a counterexample by using random word generation.
|
8
|
+
#
|
9
|
+
# This takes three important parameters:
|
10
|
+
#
|
11
|
+
# - `max_words` (default: `100`): It is a limit of number of random words.
|
12
|
+
# If random words is generated and tried up to this value and no counterexample
|
13
|
+
# is found, it returns `nil` finally.
|
14
|
+
# - `min_word_size` (default: `1`): It is the minimal size of randomly generated word.
|
15
|
+
# It should be greater than `0`.
|
16
|
+
# - `max_word_size` (default: `30`): It is the maximal size of randomly generated word.
|
17
|
+
# It should be greater than or equal to `min_word_size`.
|
18
|
+
#
|
19
|
+
# @rbs generic In -- Type for input alphabet
|
20
|
+
# @rbs generic Out -- Type for output values
|
21
|
+
class RandomWordOracle < Oracle #[In, Out]
|
22
|
+
# @rbs @alphabet: Array[In]
|
23
|
+
# @rbs @max_word: Integer
|
24
|
+
# @rbs @min_word_size: Integer
|
25
|
+
# @rbs @max_word_size: Integer
|
26
|
+
# @rbs @random: Random
|
27
|
+
|
28
|
+
#: (
|
29
|
+
# Array[In] alphabet,
|
30
|
+
# System::SUL[In, Out] sul,
|
31
|
+
# ?max_words: Integer,
|
32
|
+
# ?min_word_size: Integer,
|
33
|
+
# ?max_word_size: Integer,
|
34
|
+
# ?random: Random,
|
35
|
+
# ) -> void
|
36
|
+
def initialize(alphabet, sul, max_words: 100, min_word_size: 1, max_word_size: 30, random: Random)
|
37
|
+
super(sul)
|
38
|
+
|
39
|
+
@alphabet = alphabet
|
40
|
+
@max_words = max_words
|
41
|
+
@min_word_size = min_word_size
|
42
|
+
@max_word_size = max_word_size
|
43
|
+
@random = random
|
44
|
+
end
|
45
|
+
|
46
|
+
# @rbs override
|
47
|
+
def find_cex(hypothesis)
|
48
|
+
super
|
49
|
+
|
50
|
+
@max_words.times do
|
51
|
+
reset_internal(hypothesis)
|
52
|
+
word = []
|
53
|
+
|
54
|
+
word_size = @random.rand(@min_word_size..@max_word_size)
|
55
|
+
word_size.times do
|
56
|
+
word << @alphabet.sample(random: @random)
|
57
|
+
|
58
|
+
hypothesis_output, sul_output = step_internal(hypothesis, word.last)
|
59
|
+
|
60
|
+
if hypothesis_output != sul_output # steep:ignore
|
61
|
+
@sul.shutdown
|
62
|
+
return word
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
module Equiv
|
6
|
+
# SPASimulatorOracle provides an implementation of equivalence query
|
7
|
+
# that finds a counterexample by simulating the SPA.
|
8
|
+
#
|
9
|
+
# @rbs generic In -- Type for input alphabet
|
10
|
+
# @rbs generic Call -- Type for call alphabet
|
11
|
+
# @rbs generic Return -- Type for return alphabet
|
12
|
+
class SPASimulatorOracle < Oracle #[In | Call | Return, bool]
|
13
|
+
# @rbs @alphabet: Array[In]
|
14
|
+
# @rbs @call_alphabet: Array[Call]
|
15
|
+
# @rbs @spa: Automaton::SPA[In, Call, Return]
|
16
|
+
|
17
|
+
#: (
|
18
|
+
# Array[In] alphabet,
|
19
|
+
# Array[Call] call_alphabet,
|
20
|
+
# Automaton::SPA[In, Call, Return] spa,
|
21
|
+
# System::SUL[In | Call | Return, bool] sul
|
22
|
+
# ) -> void
|
23
|
+
def initialize(alphabet, call_alphabet, spa, sul)
|
24
|
+
super(sul)
|
25
|
+
|
26
|
+
@alphabet = alphabet
|
27
|
+
@call_alphabet = call_alphabet
|
28
|
+
@spa = spa
|
29
|
+
end
|
30
|
+
|
31
|
+
# @rbs override
|
32
|
+
def find_cex(hypothesis)
|
33
|
+
super
|
34
|
+
|
35
|
+
Automaton::SPA.find_separating_word(@alphabet, @call_alphabet, @spa, hypothesis) # steep:ignore
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
module Equiv
|
6
|
+
# TestWordsOracle provides an implementation of equivalence query
|
7
|
+
# that find a counterexample from the given words.
|
8
|
+
#
|
9
|
+
# @rbs generic In -- Type for input alphabet
|
10
|
+
# @rbs generic Out -- Type for output values
|
11
|
+
class TestWordsOracle < Oracle #[In, Out]
|
12
|
+
# @rbs @words: Array[Array[In]]
|
13
|
+
|
14
|
+
#: (Array[Array[In]] words, System::SUL[In, Out] sul) -> void
|
15
|
+
def initialize(words, sul)
|
16
|
+
super(sul)
|
17
|
+
|
18
|
+
@words = words
|
19
|
+
end
|
20
|
+
|
21
|
+
# @rbs override
|
22
|
+
def find_cex(hypothesis)
|
23
|
+
super
|
24
|
+
|
25
|
+
@words.each do |word|
|
26
|
+
reset_internal(hypothesis)
|
27
|
+
|
28
|
+
word.each_with_index do |input, index|
|
29
|
+
hypothesis_output, sul_output = step_internal(hypothesis, input)
|
30
|
+
|
31
|
+
if hypothesis_output != sul_output # steep:ignore
|
32
|
+
@sul.shutdown
|
33
|
+
return word[0..index]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
module Equiv
|
6
|
+
# TransitionSystemSimulatorOracle provides an implementation of equivalence query
|
7
|
+
# that finds a counterexample by simulating the transition system.
|
8
|
+
#
|
9
|
+
# @rbs generic Conf -- Type for a configuration of this automaton
|
10
|
+
# @rbs generic In -- Type for input alphabet
|
11
|
+
# @rbs generic Out -- Type for output values
|
12
|
+
class TransitionSystemSimulatorOracle < Oracle #[In, Out]
|
13
|
+
# @rbs @alphabet: Array[In]
|
14
|
+
# @rbs @automaton: Automaton::TransitionSystem[Conf, In, Out]
|
15
|
+
|
16
|
+
#: (
|
17
|
+
# Array[In] alphabet,
|
18
|
+
# Automaton::TransitionSystem[Conf, In, Out] spa,
|
19
|
+
# System::SUL[In, Out] sul
|
20
|
+
# ) -> void
|
21
|
+
def initialize(alphabet, automaton, sul)
|
22
|
+
super(sul)
|
23
|
+
|
24
|
+
@alphabet = alphabet
|
25
|
+
@automaton = automaton
|
26
|
+
end
|
27
|
+
|
28
|
+
# @rbs override
|
29
|
+
def find_cex(hypothesis)
|
30
|
+
super
|
31
|
+
|
32
|
+
Automaton::TransitionSystem.find_separating_word(@alphabet, @automaton, hypothesis)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
module Equiv
|
6
|
+
# VPASimulatorOracle provides an implementation of equivalence query
|
7
|
+
# that finds a counterexample by simulating the VPA.
|
8
|
+
#
|
9
|
+
# @rbs generic In -- Type for input alphabet
|
10
|
+
# @rbs generic Call -- Type for call alphabet
|
11
|
+
# @rbs generic Return -- Type for return alphabet
|
12
|
+
class VPASimulatorOracle < Oracle #[In | Call | Return, bool]
|
13
|
+
# @rbs @alphabet: Array[In]
|
14
|
+
# @rbs @call_alphabet: Array[Call]
|
15
|
+
# @rbs @return_alphabet: Array[Return]
|
16
|
+
# @rbs @spa: Automaton::VPA[In, Call, Return]
|
17
|
+
|
18
|
+
#: (
|
19
|
+
# Array[In] alphabet,
|
20
|
+
# Array[Call] call_alphabet,
|
21
|
+
# Array[Return] return_alphabet,
|
22
|
+
# Automaton::VPA[In, Call, Return] vpa,
|
23
|
+
# System::SUL[In | Call | Return, bool] sul
|
24
|
+
# ) -> void
|
25
|
+
def initialize(alphabet, call_alphabet, return_alphabet, vpa, sul)
|
26
|
+
super(sul)
|
27
|
+
|
28
|
+
@alphabet = alphabet
|
29
|
+
@call_alphabet = call_alphabet
|
30
|
+
@return_alphabet = return_alphabet
|
31
|
+
@vpa = vpa
|
32
|
+
end
|
33
|
+
|
34
|
+
# @rbs override
|
35
|
+
def find_cex(hypothesis)
|
36
|
+
super
|
37
|
+
|
38
|
+
Automaton::VPA.find_separating_word(
|
39
|
+
@alphabet,
|
40
|
+
@call_alphabet,
|
41
|
+
@return_alphabet,
|
42
|
+
@vpa,
|
43
|
+
hypothesis # steep:ignore
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/lernen/equiv.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
# This is a namespace for equivalence query oracles.
|
6
|
+
#
|
7
|
+
# A equivalence query check the given hypothesis automaton is equivalence
|
8
|
+
# to a SUL. If that is not, it returns a counterexample, which leads
|
9
|
+
# different output values between the hypothesis and the SUL.
|
10
|
+
module Equiv
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
require "lernen/equiv/oracle"
|
15
|
+
|
16
|
+
require "lernen/equiv/combined_oracle"
|
17
|
+
require "lernen/equiv/exhaustive_search_oracle"
|
18
|
+
require "lernen/equiv/test_words_oracle"
|
19
|
+
require "lernen/equiv/random_walk_oracle"
|
20
|
+
require "lernen/equiv/random_word_oracle"
|
21
|
+
require "lernen/equiv/random_well_matched_word_oracle"
|
22
|
+
require "lernen/equiv/transition_system_simulator_oracle"
|
23
|
+
require "lernen/equiv/moore_like_simulator_oracle"
|
24
|
+
require "lernen/equiv/vpa_simulator_oracle"
|
25
|
+
require "lernen/equiv/spa_simulator_oracle"
|
data/lib/lernen/graph.rb
ADDED
@@ -0,0 +1,215 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
# Graph represents a labelled directed graph.
|
6
|
+
#
|
7
|
+
# This is an intermediate data structure for rendering Mermaid and Graphviz diagrams.
|
8
|
+
class Graph
|
9
|
+
# @rbs!
|
10
|
+
# type node_shape = :circle | :doublecircle
|
11
|
+
#
|
12
|
+
# type mermaid_direction = "TD" | "DT" | "LR" | "RL"
|
13
|
+
|
14
|
+
# Node represents a node of graphs.
|
15
|
+
#
|
16
|
+
# @rbs skip
|
17
|
+
Node = Data.define(:label, :shape)
|
18
|
+
|
19
|
+
# @rbs!
|
20
|
+
# class Node < Data
|
21
|
+
# attr_reader label: String
|
22
|
+
# attr_reader shape: node_shape
|
23
|
+
# def self.[]: (String label, node_shape shape) -> Node
|
24
|
+
# end
|
25
|
+
|
26
|
+
# Edge represents an edge of graphs.
|
27
|
+
#
|
28
|
+
# @rbs skip
|
29
|
+
Edge = Data.define(:from, :label, :to)
|
30
|
+
|
31
|
+
# @rbs!
|
32
|
+
# class Edge < Data
|
33
|
+
# attr_reader from: Integer
|
34
|
+
# attr_reader label: String
|
35
|
+
# attr_reader to: Integer
|
36
|
+
# def self.[]: (Integer from, String label, Integer to) -> Edge
|
37
|
+
# end
|
38
|
+
|
39
|
+
# SubGraph represents a sub-graph of graphs.
|
40
|
+
#
|
41
|
+
# @rbs skip
|
42
|
+
SubGraph = Data.define(:label, :graph)
|
43
|
+
|
44
|
+
# @rbs!
|
45
|
+
# class SubGraph < Data
|
46
|
+
# attr_reader label: String
|
47
|
+
# attr_reader graph: Graph
|
48
|
+
# def self.[]: (String label, Graph graph) -> SubGraph
|
49
|
+
# end
|
50
|
+
|
51
|
+
# Returns the escaped string for Mermaid diagrams.
|
52
|
+
#
|
53
|
+
# See https://mermaid.js.org/syntax/flowchart.html#entity-codes-to-escape-characters.
|
54
|
+
#
|
55
|
+
#: (String label) -> String
|
56
|
+
def self.mermaid_escape(label)
|
57
|
+
label =
|
58
|
+
label.gsub(/[#"]/) do |c|
|
59
|
+
case c
|
60
|
+
in "#"
|
61
|
+
"#35;"
|
62
|
+
in "\""
|
63
|
+
"#quot;"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
"\"#{label}\""
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the escaped string for GraphViz DOTs.
|
70
|
+
#
|
71
|
+
# See https://graphviz.org/docs/attr-types/escString/.
|
72
|
+
#
|
73
|
+
#: (String label) -> String
|
74
|
+
def self.dot_escape(label)
|
75
|
+
label =
|
76
|
+
label.gsub(/[\\"]/) do |c|
|
77
|
+
case c
|
78
|
+
in "\\"
|
79
|
+
"\\\\"
|
80
|
+
in "\""
|
81
|
+
"\\\""
|
82
|
+
end
|
83
|
+
end
|
84
|
+
"\"#{label}\""
|
85
|
+
end
|
86
|
+
|
87
|
+
# @rbs @nodes: Hash[Integer, Node]
|
88
|
+
# @rbs @edges: Array[Edge]
|
89
|
+
# @rbs @subgraphs: Array[SubGraph]
|
90
|
+
|
91
|
+
#: (
|
92
|
+
# Hash[Integer, Node] nodes,
|
93
|
+
# Array[Edge] edges,
|
94
|
+
# ?Array[SubGraph] subgraphs
|
95
|
+
# ) -> void
|
96
|
+
def initialize(nodes, edges, subgraphs = [])
|
97
|
+
@nodes = nodes
|
98
|
+
@edges = edges
|
99
|
+
@subgraphs = subgraphs
|
100
|
+
end
|
101
|
+
|
102
|
+
attr_reader :nodes #: Hash[Integer, Node]
|
103
|
+
attr_reader :edges #: Array[Edge]
|
104
|
+
attr_reader :subgraphs #: Array[SubGraph]
|
105
|
+
|
106
|
+
# Returns a [Mermaid](https://mermaid.js.org) diagram of this graph.
|
107
|
+
#
|
108
|
+
#: (?direction: mermaid_direction) -> String
|
109
|
+
def to_mermaid(direction: "TD")
|
110
|
+
mmd = +""
|
111
|
+
|
112
|
+
mmd << "flowchart #{direction}\n"
|
113
|
+
mmd << to_mermaid_internal
|
114
|
+
|
115
|
+
mmd.freeze
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns a [GraphViz](https://graphviz.org) DOT diagram of this graph.
|
119
|
+
#
|
120
|
+
#: () -> String
|
121
|
+
def to_dot
|
122
|
+
dot = +""
|
123
|
+
|
124
|
+
dot << "digraph {\n"
|
125
|
+
dot << to_dot_internal
|
126
|
+
dot << "}\n"
|
127
|
+
|
128
|
+
dot.freeze
|
129
|
+
end
|
130
|
+
|
131
|
+
protected
|
132
|
+
|
133
|
+
#: (?String id_prefix) -> String
|
134
|
+
def to_mermaid_internal(id_prefix = "")
|
135
|
+
mmd = +""
|
136
|
+
needs_sep = false
|
137
|
+
|
138
|
+
nodes.each do |id, node|
|
139
|
+
needs_sep = true
|
140
|
+
|
141
|
+
node_def =
|
142
|
+
case node.shape
|
143
|
+
in :circle
|
144
|
+
"((#{Graph.mermaid_escape(node.label)}))"
|
145
|
+
in :doublecircle
|
146
|
+
"(((#{Graph.mermaid_escape(node.label)})))"
|
147
|
+
end
|
148
|
+
mmd << " #{id_prefix}#{id}#{node_def}\n"
|
149
|
+
end
|
150
|
+
mmd << "\n" if needs_sep
|
151
|
+
|
152
|
+
edges.each do |edge|
|
153
|
+
needs_sep = true
|
154
|
+
|
155
|
+
from = "#{id_prefix}#{edge.from}"
|
156
|
+
to = "#{id_prefix}#{edge.to}"
|
157
|
+
mmd << " #{from} -- #{Graph.mermaid_escape(edge.label)} --> #{to}\n"
|
158
|
+
end
|
159
|
+
|
160
|
+
subgraphs.each_with_index do |subgraph, index|
|
161
|
+
mmd << "\n" if needs_sep
|
162
|
+
needs_sep = true
|
163
|
+
|
164
|
+
subgraph_id = "#{id_prefix}g#{index}"
|
165
|
+
mmd << " subgraph #{subgraph_id}[#{Graph.mermaid_escape(subgraph.label)}]\n"
|
166
|
+
subgraph
|
167
|
+
.graph
|
168
|
+
.to_mermaid_internal("#{subgraph_id}_")
|
169
|
+
.lines
|
170
|
+
.each { |line| mmd << (line == "\n" ? line : " #{line}") }
|
171
|
+
mmd << " end\n"
|
172
|
+
end
|
173
|
+
|
174
|
+
mmd.freeze
|
175
|
+
end
|
176
|
+
|
177
|
+
#: (?String id_prefix) -> String
|
178
|
+
def to_dot_internal(id_prefix = "")
|
179
|
+
dot = +""
|
180
|
+
needs_sep = false
|
181
|
+
|
182
|
+
nodes.each do |index, node|
|
183
|
+
needs_sep = true
|
184
|
+
|
185
|
+
dot << " #{id_prefix}#{index} [label=#{Graph.dot_escape(node.label)}, shape=#{node.shape}];\n"
|
186
|
+
end
|
187
|
+
dot << "\n" if needs_sep
|
188
|
+
|
189
|
+
edges.each do |edge|
|
190
|
+
needs_sep = true
|
191
|
+
|
192
|
+
from = "#{id_prefix}#{edge.from}"
|
193
|
+
to = "#{id_prefix}#{edge.to}"
|
194
|
+
dot << " #{from} -> #{to} [label=#{Graph.dot_escape(edge.label)}];\n"
|
195
|
+
end
|
196
|
+
|
197
|
+
subgraphs.each_with_index do |subgraph, index|
|
198
|
+
dot << "\n" if needs_sep
|
199
|
+
needs_sep = true
|
200
|
+
|
201
|
+
subgraph_id = "#{id_prefix}g#{index}"
|
202
|
+
dot << " subgraph cluster_#{subgraph_id} {\n"
|
203
|
+
dot << " label=#{Graph.dot_escape(subgraph.label)};\n"
|
204
|
+
subgraph
|
205
|
+
.graph
|
206
|
+
.to_dot_internal("#{subgraph_id}_")
|
207
|
+
.lines
|
208
|
+
.each { |line| dot << (line == "\n" ? line : " #{line}") }
|
209
|
+
dot << " }\n"
|
210
|
+
end
|
211
|
+
|
212
|
+
dot.freeze
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|