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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +18 -0
  3. data/README.md +531 -28
  4. data/Rakefile +29 -7
  5. data/Steepfile +14 -0
  6. data/examples/ripper_prism.rb +63 -0
  7. data/examples/uri_parse_regexp.rb +73 -0
  8. data/lib/lernen/algorithm/cex_processor/acex.rb +43 -0
  9. data/lib/lernen/algorithm/cex_processor/prefix_transformer_acex.rb +43 -0
  10. data/lib/lernen/algorithm/cex_processor.rb +115 -0
  11. data/lib/lernen/algorithm/kearns_vazirani/discrimination_tree.rb +207 -0
  12. data/lib/lernen/algorithm/kearns_vazirani/kearns_vazirani_learner.rb +100 -0
  13. data/lib/lernen/algorithm/kearns_vazirani.rb +44 -0
  14. data/lib/lernen/algorithm/kearns_vazirani_vpa/discrimination_tree_vpa.rb +246 -0
  15. data/lib/lernen/algorithm/kearns_vazirani_vpa/kearns_vazirani_vpa_learner.rb +89 -0
  16. data/lib/lernen/algorithm/kearns_vazirani_vpa.rb +35 -0
  17. data/lib/lernen/algorithm/learner.rb +82 -0
  18. data/lib/lernen/algorithm/lsharp/lsharp_learner.rb +367 -0
  19. data/lib/lernen/algorithm/lsharp/observation_tree.rb +115 -0
  20. data/lib/lernen/algorithm/lsharp.rb +43 -0
  21. data/lib/lernen/algorithm/lstar/lstar_learner.rb +49 -0
  22. data/lib/lernen/algorithm/lstar/observation_table.rb +214 -0
  23. data/lib/lernen/algorithm/lstar.rb +49 -0
  24. data/lib/lernen/algorithm/procedural/atr_manager.rb +200 -0
  25. data/lib/lernen/algorithm/procedural/procedural_learner.rb +223 -0
  26. data/lib/lernen/algorithm/procedural/procedural_sul.rb +47 -0
  27. data/lib/lernen/algorithm/procedural/return_indices_acex.rb +58 -0
  28. data/lib/lernen/algorithm/procedural.rb +57 -0
  29. data/lib/lernen/algorithm.rb +19 -0
  30. data/lib/lernen/automaton/dfa.rb +204 -0
  31. data/lib/lernen/automaton/mealy.rb +108 -0
  32. data/lib/lernen/automaton/moore.rb +122 -0
  33. data/lib/lernen/automaton/moore_like.rb +83 -0
  34. data/lib/lernen/automaton/proc_util.rb +93 -0
  35. data/lib/lernen/automaton/spa.rb +368 -0
  36. data/lib/lernen/automaton/transition_system.rb +209 -0
  37. data/lib/lernen/automaton/vpa.rb +300 -0
  38. data/lib/lernen/automaton.rb +19 -92
  39. data/lib/lernen/equiv/combined_oracle.rb +57 -0
  40. data/lib/lernen/equiv/exhaustive_search_oracle.rb +60 -0
  41. data/lib/lernen/equiv/moore_like_simulator_oracle.rb +36 -0
  42. data/lib/lernen/equiv/oracle.rb +109 -0
  43. data/lib/lernen/equiv/random_walk_oracle.rb +69 -0
  44. data/lib/lernen/equiv/random_well_matched_word_oracle.rb +139 -0
  45. data/lib/lernen/equiv/random_word_oracle.rb +71 -0
  46. data/lib/lernen/equiv/spa_simulator_oracle.rb +39 -0
  47. data/lib/lernen/equiv/test_words_oracle.rb +42 -0
  48. data/lib/lernen/equiv/transition_system_simulator_oracle.rb +36 -0
  49. data/lib/lernen/equiv/vpa_simulator_oracle.rb +48 -0
  50. data/lib/lernen/equiv.rb +25 -0
  51. data/lib/lernen/graph.rb +215 -0
  52. data/lib/lernen/system/block_sul.rb +41 -0
  53. data/lib/lernen/system/moore_like_simulator.rb +45 -0
  54. data/lib/lernen/system/moore_like_sul.rb +33 -0
  55. data/lib/lernen/system/sul.rb +126 -0
  56. data/lib/lernen/system/transition_system_simulator.rb +40 -0
  57. data/lib/lernen/system.rb +72 -0
  58. data/lib/lernen/version.rb +2 -1
  59. data/lib/lernen.rb +322 -13
  60. data/rbs_collection.lock.yaml +16 -0
  61. data/rbs_collection.yaml +14 -0
  62. data/renovate.json +6 -0
  63. data/sig/generated/lernen/algorithm/cex_processor/acex.rbs +30 -0
  64. data/sig/generated/lernen/algorithm/cex_processor/prefix_transformer_acex.rbs +27 -0
  65. data/sig/generated/lernen/algorithm/cex_processor.rbs +59 -0
  66. data/sig/generated/lernen/algorithm/kearns_vazirani/discrimination_tree.rbs +68 -0
  67. data/sig/generated/lernen/algorithm/kearns_vazirani/kearns_vazirani_learner.rbs +51 -0
  68. data/sig/generated/lernen/algorithm/kearns_vazirani.rbs +32 -0
  69. data/sig/generated/lernen/algorithm/kearns_vazirani_vpa/discrimination_tree_vpa.rbs +73 -0
  70. data/sig/generated/lernen/algorithm/kearns_vazirani_vpa/kearns_vazirani_vpa_learner.rbs +51 -0
  71. data/sig/generated/lernen/algorithm/kearns_vazirani_vpa.rbs +20 -0
  72. data/sig/generated/lernen/algorithm/learner.rbs +53 -0
  73. data/sig/generated/lernen/algorithm/lsharp/lsharp_learner.rbs +103 -0
  74. data/sig/generated/lernen/algorithm/lsharp/observation_tree.rbs +53 -0
  75. data/sig/generated/lernen/algorithm/lsharp.rbs +38 -0
  76. data/sig/generated/lernen/algorithm/lstar/lstar_learner.rbs +38 -0
  77. data/sig/generated/lernen/algorithm/lstar/observation_table.rbs +79 -0
  78. data/sig/generated/lernen/algorithm/lstar.rbs +37 -0
  79. data/sig/generated/lernen/algorithm/procedural/atr_manager.rbs +80 -0
  80. data/sig/generated/lernen/algorithm/procedural/procedural_learner.rbs +79 -0
  81. data/sig/generated/lernen/algorithm/procedural/procedural_sul.rbs +36 -0
  82. data/sig/generated/lernen/algorithm/procedural/return_indices_acex.rbs +33 -0
  83. data/sig/generated/lernen/algorithm/procedural.rbs +27 -0
  84. data/sig/generated/lernen/algorithm.rbs +10 -0
  85. data/sig/generated/lernen/automaton/dfa.rbs +93 -0
  86. data/sig/generated/lernen/automaton/mealy.rbs +61 -0
  87. data/sig/generated/lernen/automaton/moore.rbs +69 -0
  88. data/sig/generated/lernen/automaton/moore_like.rbs +63 -0
  89. data/sig/generated/lernen/automaton/proc_util.rbs +38 -0
  90. data/sig/generated/lernen/automaton/spa.rbs +125 -0
  91. data/sig/generated/lernen/automaton/transition_system.rbs +108 -0
  92. data/sig/generated/lernen/automaton/vpa.rbs +109 -0
  93. data/sig/generated/lernen/automaton.rbs +15 -0
  94. data/sig/generated/lernen/equiv/combined_oracle.rbs +27 -0
  95. data/sig/generated/lernen/equiv/exhaustive_search_oracle.rbs +38 -0
  96. data/sig/generated/lernen/equiv/moore_like_simulator_oracle.rbs +27 -0
  97. data/sig/generated/lernen/equiv/oracle.rbs +75 -0
  98. data/sig/generated/lernen/equiv/random_walk_oracle.rbs +41 -0
  99. data/sig/generated/lernen/equiv/random_well_matched_word_oracle.rbs +70 -0
  100. data/sig/generated/lernen/equiv/random_word_oracle.rbs +45 -0
  101. data/sig/generated/lernen/equiv/spa_simulator_oracle.rbs +30 -0
  102. data/sig/generated/lernen/equiv/test_words_oracle.rbs +20 -0
  103. data/sig/generated/lernen/equiv/transition_system_simulator_oracle.rbs +27 -0
  104. data/sig/generated/lernen/equiv/vpa_simulator_oracle.rbs +33 -0
  105. data/sig/generated/lernen/equiv.rbs +11 -0
  106. data/sig/generated/lernen/graph.rbs +80 -0
  107. data/sig/generated/lernen/system/block_sul.rbs +29 -0
  108. data/sig/generated/lernen/system/moore_like_simulator.rbs +31 -0
  109. data/sig/generated/lernen/system/moore_like_sul.rbs +28 -0
  110. data/sig/generated/lernen/system/sul.rbs +87 -0
  111. data/sig/generated/lernen/system/transition_system_simulator.rbs +28 -0
  112. data/sig/generated/lernen/system.rbs +62 -0
  113. data/sig/generated/lernen/version.rbs +6 -0
  114. data/sig/generated/lernen.rbs +214 -0
  115. data/sig-test/generated/test/example_test.rbs +14 -0
  116. data/sig-test/generated/test/lernen/algorithm/kearns_vazirani_test.rbs +16 -0
  117. data/sig-test/generated/test/lernen/algorithm/kearns_vazirani_vpa_test.rbs +10 -0
  118. data/sig-test/generated/test/lernen/algorithm/lsharp_test.rbs +16 -0
  119. data/sig-test/generated/test/lernen/algorithm/lstar_test.rbs +16 -0
  120. data/sig-test/generated/test/lernen/algorithm/procedural_test.rbs +10 -0
  121. data/sig-test/generated/test/lernen/automaton/dfa_test.rbs +19 -0
  122. data/sig-test/generated/test/lernen/automaton/mealy_test.rbs +19 -0
  123. data/sig-test/generated/test/lernen/automaton/moore_test.rbs +19 -0
  124. data/sig-test/generated/test/lernen/automaton/proc_util_test.rbs +19 -0
  125. data/sig-test/generated/test/lernen/automaton/spa_test.rbs +19 -0
  126. data/sig-test/generated/test/lernen/automaton/vpa_test.rbs +19 -0
  127. data/sig-test/generated/test/lernen/equiv/exhaustive_search_oracle_test.rbs +10 -0
  128. data/sig-test/generated/test/lernen/equiv/random_walk_oracle_test.rbs +10 -0
  129. data/sig-test/generated/test/lernen/equiv/random_word_oracle_test.rbs +10 -0
  130. data/sig-test/generated/test/lernen/system/block_sul_test.rbs +16 -0
  131. data/sig-test/generated/test/lernen/system/moore_like_simulator_test.rbs +16 -0
  132. data/sig-test/generated/test/lernen/system/transition_system_simulator_test.rbs +13 -0
  133. data/sig-test/generated/test/lernen/system_test.rbs +11 -0
  134. data/sig-test/generated/test/lernen_test.rbs +13 -0
  135. metadata +131 -11
  136. data/.yardopts +0 -3
  137. data/lib/lernen/cex_processor.rb +0 -61
  138. data/lib/lernen/kearns_vazirani.rb +0 -199
  139. data/lib/lernen/lsharp.rb +0 -335
  140. data/lib/lernen/lstar.rb +0 -169
  141. data/lib/lernen/oracle.rb +0 -116
  142. 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
@@ -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"
@@ -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