lernen 0.2.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 +15 -0
- data/README.md +534 -48
- data/Rakefile +26 -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 -493
- 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 +284 -34
- 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 -92
- data/lib/lernen/kearns_vazirani.rb +0 -310
- data/lib/lernen/lsharp.rb +0 -344
- data/lib/lernen/lstar.rb +0 -170
- data/lib/lernen/oracle.rb +0 -119
- data/lib/lernen/sul.rb +0 -210
@@ -0,0 +1,300 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# rbs_inline: enabled
|
3
|
+
|
4
|
+
module Lernen
|
5
|
+
module Automaton
|
6
|
+
# VPA represents a [visily pushdown automaton](https://en.wikipedia.org/wiki/Nested_word#Visibly_pushdown_automaton).
|
7
|
+
#
|
8
|
+
# Especially, this definition represents 1-SEVPA (1-module single-entry visibly pushdown automaton).
|
9
|
+
#
|
10
|
+
# @rbs generic In -- Type for input alphabet
|
11
|
+
# @rbs generic Call -- Type for call alphabet
|
12
|
+
# @rbs generic Return -- Type for return alphabet
|
13
|
+
class VPA < MooreLike #[VPA::Conf[Call] | nil, In | Call | Return, bool]
|
14
|
+
# Conf is a configuration of VPA run.
|
15
|
+
#
|
16
|
+
# @rbs skip
|
17
|
+
Conf = Data.define(:state, :stack)
|
18
|
+
|
19
|
+
# @rbs!
|
20
|
+
# class Conf[Call] < Data
|
21
|
+
# attr_reader state: Integer
|
22
|
+
# attr_reader stack: Array[[Integer, Call]]
|
23
|
+
# def self.[]: [Call] (Integer state, Array[[Integer, Call]] stack) -> Conf[Call]
|
24
|
+
# end
|
25
|
+
|
26
|
+
# @rbs @initial_state: Integer
|
27
|
+
# @rbs @accept_state_set: Set[Integer]
|
28
|
+
# @rbs @transition_function: Hash[[Integer, In], Integer]
|
29
|
+
# @rbs @return_transition_function: Hash[[Integer, Return], Hash[[Integer, Call], Integer]]
|
30
|
+
|
31
|
+
#: (
|
32
|
+
# Integer initial_state,
|
33
|
+
# Set[Integer] accept_state_set,
|
34
|
+
# Hash[[Integer, In], Integer] transition_function.
|
35
|
+
# Hash[[Integer, Return], Hash[[Integer, Call], Integer]] return_transition_function
|
36
|
+
# ) -> void
|
37
|
+
def initialize(initial_state, accept_state_set, transition_function, return_transition_function)
|
38
|
+
super()
|
39
|
+
|
40
|
+
@initial_state = initial_state
|
41
|
+
@accept_state_set = accept_state_set
|
42
|
+
@transition_function = transition_function
|
43
|
+
@return_transition_function = return_transition_function
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :initial_state #: Integer
|
47
|
+
attr_reader :accept_state_set #: Set[Integer]
|
48
|
+
attr_reader :transition_function #: Hash[[Integer, In], Integer]
|
49
|
+
attr_reader :return_transition_function #: Hash[[Integer, Return], Hash[[Integer, Call], Integer]]
|
50
|
+
|
51
|
+
# @rbs return: :vpa
|
52
|
+
def type = :vpa
|
53
|
+
|
54
|
+
# @rbs override
|
55
|
+
def initial_conf = Conf[initial_state, []]
|
56
|
+
|
57
|
+
# @rbs override
|
58
|
+
def step_conf(conf, input)
|
59
|
+
return nil if conf.nil?
|
60
|
+
|
61
|
+
next_state = transition_function[[conf.state, input]] # steep:ignore
|
62
|
+
return Conf[next_state, conf.stack] if next_state
|
63
|
+
|
64
|
+
return_transition_guard = return_transition_function[[conf.state, input]] # steep:ignore
|
65
|
+
if return_transition_guard
|
66
|
+
*next_stack, last_call = conf.stack
|
67
|
+
return nil unless last_call
|
68
|
+
next_state = return_transition_guard[last_call]
|
69
|
+
return Conf[next_state, next_stack]
|
70
|
+
end
|
71
|
+
|
72
|
+
# When there is no usual transition and no return tansition for `input`,
|
73
|
+
# then we assume that `input` is a call alphabet.
|
74
|
+
Conf[initial_state, conf.stack + [[conf.state, input]]] # steep:ignore
|
75
|
+
end
|
76
|
+
|
77
|
+
# @rbs override
|
78
|
+
def output(conf)
|
79
|
+
!conf.nil? && accept_state_set.include?(conf.state) && conf.stack.empty?
|
80
|
+
end
|
81
|
+
|
82
|
+
# Checks the structural equality between `self` and `other`.
|
83
|
+
#
|
84
|
+
#: (untyped other) -> bool
|
85
|
+
def ==(other)
|
86
|
+
other.is_a?(VPA) && initial_state == other.initial_state && accept_state_set == other.accept_state_set &&
|
87
|
+
transition_function == other.transition_function &&
|
88
|
+
return_transition_function == other.return_transition_function
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the array of states of this VPA.
|
92
|
+
#
|
93
|
+
# The result array is sorted.
|
94
|
+
#
|
95
|
+
#: () -> Array[Integer]
|
96
|
+
def states
|
97
|
+
state_set = Set.new
|
98
|
+
state_set << initial_state
|
99
|
+
accept_state_set.each { |state| state_set << state }
|
100
|
+
transition_function.each do |(state, _), next_state|
|
101
|
+
state_set << state
|
102
|
+
state_set << next_state
|
103
|
+
end
|
104
|
+
return_transition_function.each do |(state, _), return_transition_guard|
|
105
|
+
state_set << state
|
106
|
+
return_transition_guard.each do |(call_state, _), next_state|
|
107
|
+
state_set << call_state
|
108
|
+
state_set << next_state
|
109
|
+
end
|
110
|
+
end
|
111
|
+
state_set.to_a.sort!
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns the error state of this VPA.
|
115
|
+
#
|
116
|
+
# An error state is:
|
117
|
+
#
|
118
|
+
# - neither a initial state nor accepting states, and
|
119
|
+
# - only having self-loops for all `input`.
|
120
|
+
#
|
121
|
+
# If an error state is not found, it returns `nil`.
|
122
|
+
#
|
123
|
+
#: () -> (Integer | nil)
|
124
|
+
def error_state
|
125
|
+
transition_function
|
126
|
+
.group_by { |(state, _), _| state }
|
127
|
+
.transform_values { _1.to_h { |(_, input), next_state| [input, next_state] } }
|
128
|
+
.each do |state, transition_hash|
|
129
|
+
# The initial state and accepting states are not an error state.
|
130
|
+
next if state == initial_state || accept_state_set.include?(state)
|
131
|
+
|
132
|
+
# An error state should only have self-loops.
|
133
|
+
next unless transition_hash.all? { |_, next_state| state == next_state }
|
134
|
+
all_returns_are_self_loops =
|
135
|
+
return_transition_function.all? do |_, return_transition_guard|
|
136
|
+
return_transition_guard
|
137
|
+
.filter { |(call_state, _), _| call_state == state }
|
138
|
+
.all? { |_, next_state| state == next_state }
|
139
|
+
end
|
140
|
+
next unless all_returns_are_self_loops
|
141
|
+
|
142
|
+
return state
|
143
|
+
end
|
144
|
+
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns a graph of this VPA.
|
149
|
+
#
|
150
|
+
# (?shows_error_state: bool) -> Graph
|
151
|
+
def to_graph(shows_error_state: false)
|
152
|
+
error_state = error_state() unless shows_error_state
|
153
|
+
|
154
|
+
nodes =
|
155
|
+
states
|
156
|
+
.filter_map do |state|
|
157
|
+
next if state == error_state
|
158
|
+
shape = accept_state_set.include?(state) ? :doublecircle : :circle #: Graph::node_shape
|
159
|
+
[state, Graph::Node[state.to_s, shape]]
|
160
|
+
end
|
161
|
+
.to_h
|
162
|
+
|
163
|
+
edges =
|
164
|
+
transition_function.filter_map do |(state, input), next_state|
|
165
|
+
next if state == error_state || next_state == error_state
|
166
|
+
Graph::Edge[state, input.inspect, next_state] # steep:ignore
|
167
|
+
end
|
168
|
+
|
169
|
+
edges +=
|
170
|
+
return_transition_function.flat_map do |(state, return_input), return_transition_guard|
|
171
|
+
next [] if state == error_state
|
172
|
+
return_transition_guard.filter_map do |(call_state, call_input), next_state|
|
173
|
+
next if call_state == error_state || next_state == error_state
|
174
|
+
label = "#{return_input.inspect} / (#{call_state}, #{call_input.inspect})" # steep:ignore
|
175
|
+
Graph::Edge[state, label, next_state]
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
Graph.new(nodes, edges)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Finds a separating word between `vpa1` and `vpa2`.
|
183
|
+
#
|
184
|
+
#: [In, Call, Return] (
|
185
|
+
# Array[In] alphabet,
|
186
|
+
# Array[Call] call_alphabet,
|
187
|
+
# Array[Return] return_alphabet,
|
188
|
+
# VPA[In, Call, Return] vpa1,
|
189
|
+
# VPA[In, Call, Return] vpa2
|
190
|
+
# ) -> (Array[In | Call | Return] | nil)
|
191
|
+
def self.find_separating_word(alphabet, call_alphabet, return_alphabet, vpa1, vpa2)
|
192
|
+
raise ArgumentError, "Cannot find a separating word for different type automata" unless vpa2.is_a?(vpa1.class)
|
193
|
+
|
194
|
+
queue = []
|
195
|
+
prefix_hash = {}
|
196
|
+
|
197
|
+
initial_pair = [vpa1.initial_conf&.state, vpa2.initial_conf&.state]
|
198
|
+
queue << initial_pair
|
199
|
+
prefix_hash[initial_pair] = []
|
200
|
+
|
201
|
+
until queue.empty?
|
202
|
+
state1, state2 = queue.shift
|
203
|
+
prefix = prefix_hash[[state1, state2]]
|
204
|
+
|
205
|
+
alphabet.each do |input|
|
206
|
+
output1, next_conf1 = vpa1.step(state1 && Conf[state1, []], input)
|
207
|
+
output2, next_conf2 = vpa2.step(state2 && Conf[state2, []], input)
|
208
|
+
|
209
|
+
word = prefix + [input]
|
210
|
+
return word if output1 != output2
|
211
|
+
|
212
|
+
next_pair = [next_conf1&.state, next_conf2&.state]
|
213
|
+
unless prefix_hash.include?(next_pair)
|
214
|
+
queue << next_pair
|
215
|
+
prefix_hash[next_pair] = word
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
found_state_pairs = prefix_hash.keys
|
220
|
+
call_alphabet.each do |call_input|
|
221
|
+
return_alphabet.each do |return_input|
|
222
|
+
found_state_pairs.each do |(call_state1, call_state2)|
|
223
|
+
return_conf1 = state1 && Conf[state1, [[call_state1, call_input]]] # steep:ignore
|
224
|
+
return_conf2 = state2 && Conf[state2, [[call_state2, call_input]]] # steep:ignore
|
225
|
+
|
226
|
+
output1, next_conf1 = vpa1.step(return_conf1, return_input)
|
227
|
+
output2, next_conf2 = vpa2.step(return_conf2, return_input)
|
228
|
+
|
229
|
+
word = prefix_hash[[call_state1, call_state2]] + [call_input] + prefix + [return_input]
|
230
|
+
return word if output1 != output2
|
231
|
+
|
232
|
+
next_pair = [next_conf1&.state, next_conf2&.state]
|
233
|
+
unless prefix_hash.include?(next_pair)
|
234
|
+
queue << next_pair
|
235
|
+
prefix_hash[next_pair] = word
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
nil
|
243
|
+
end
|
244
|
+
|
245
|
+
# Generates a VPA randomly.
|
246
|
+
#
|
247
|
+
#: [In, Call, Return] (
|
248
|
+
# alphabet: Array[In],
|
249
|
+
# call_alphabet: Array[Call],
|
250
|
+
# return_alphabet: Array[Return],
|
251
|
+
# ?min_state_size: Integer,
|
252
|
+
# ?max_state_size: Integer,
|
253
|
+
# ?accept_state_size: Integer,
|
254
|
+
# ?random: Random,
|
255
|
+
# ) -> VPA[In, Call, Return]
|
256
|
+
def self.random(
|
257
|
+
alphabet:,
|
258
|
+
call_alphabet:,
|
259
|
+
return_alphabet:,
|
260
|
+
min_state_size: 5,
|
261
|
+
max_state_size: 10,
|
262
|
+
accept_state_size: 2,
|
263
|
+
random: Random
|
264
|
+
)
|
265
|
+
transition_function, reachable_paths =
|
266
|
+
TransitionSystem.random_transition_function(
|
267
|
+
alphabet:,
|
268
|
+
min_state_size:,
|
269
|
+
max_state_size:,
|
270
|
+
num_reachable_paths: accept_state_size,
|
271
|
+
random:
|
272
|
+
)
|
273
|
+
accept_state_set = reachable_paths.to_set(&:last) #: Set[Integer]
|
274
|
+
|
275
|
+
state_set = Set.new
|
276
|
+
transition_function.each do |(state, _), next_state|
|
277
|
+
state_set << state
|
278
|
+
state_set << next_state
|
279
|
+
end
|
280
|
+
states = state_set.to_a
|
281
|
+
states.sort!
|
282
|
+
|
283
|
+
return_transition_function = {}
|
284
|
+
states.each do |return_state|
|
285
|
+
return_alphabet.each do |return_input|
|
286
|
+
return_transition_guard = return_transition_function[[return_state, return_input]] = {}
|
287
|
+
states.each do |call_state|
|
288
|
+
call_alphabet.each do |call_input|
|
289
|
+
next_state = states.sample(random:)
|
290
|
+
return_transition_guard[[call_state, call_input]] = next_state
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
new(0, accept_state_set, transition_function, return_transition_function)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|