falafel 0.0.1.1 → 0.0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cfg.rb +3 -19
- data/lib/chomsky_nf.rb +3 -3
- data/lib/chomsky_nf_simplifier.rb +35 -30
- data/lib/cyk.rb +34 -10
- data/lib/epsilon_free.rb +1 -1
- data/lib/falafel.rb +2 -3
- data/lib/pump.rb +52 -13
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5180f16b8868a35cf65faa396c7b341166604e2aaf7db8d9f7099c819630497f
|
4
|
+
data.tar.gz: 7c773f6a53d8895333d37115cba598dcf60128bff2eaf4dc47e73f7e1ca21298
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b7470e125d1f803eacc1d207704b90782e439fef8c7fe00dcf0acdb6c27324d24ed2da0666b3c456fe7cc7b255902002f20870e8f93d589482d4d1df3370aca
|
7
|
+
data.tar.gz: c8534f9da1cfec2623caa5cf0422f3d03009579374d2183a10341398a93aad87fbf2a0e85aaba0a0a766ee1d8ae62baa02e39bd2a76c7857fa6613629ae64f5a
|
data/lib/cfg.rb
CHANGED
@@ -10,7 +10,7 @@ require_relative 'chaining_free'
|
|
10
10
|
# generates random words
|
11
11
|
class CFG
|
12
12
|
attr_accessor :start_var, :rules
|
13
|
-
attr_reader :rules_ef, :rules_cf, :rnd_words,
|
13
|
+
attr_reader :rules_ef, :rules_cf, :rnd_words,
|
14
14
|
:rules_ef_res, :rules_cf_res, :chomsky_nf_rules,
|
15
15
|
:cyk_matrix, :is_in_l
|
16
16
|
|
@@ -18,7 +18,6 @@ class CFG
|
|
18
18
|
@start_var = start_var
|
19
19
|
@rules = _rules rules
|
20
20
|
@rnd_words = []
|
21
|
-
@reachables = []
|
22
21
|
@vars = vars
|
23
22
|
@alphabet = alphabet
|
24
23
|
end
|
@@ -35,24 +34,9 @@ class CFG
|
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
|
-
def
|
39
|
-
@rules[@start_var].each do |rule|
|
40
|
-
@vars.each { |var| @reachables << var if rule.include? var }
|
41
|
-
end
|
42
|
-
@reachables.uniq!
|
43
|
-
end
|
44
|
-
|
45
|
-
def var_productive?
|
46
|
-
''
|
47
|
-
end
|
48
|
-
|
49
|
-
def var_reduced?
|
50
|
-
''
|
51
|
-
end
|
52
|
-
|
53
|
-
def epsilon_free
|
37
|
+
def epsilon_free(custom_rule)
|
54
38
|
e_free = EpsilonFree.new
|
55
|
-
@rules_ef_res = e_free.run @rules
|
39
|
+
@rules_ef_res = e_free.run custom_rule || @rules
|
56
40
|
@rules_ef = e_free.rebuild_rules @rules, @rules_ef_res
|
57
41
|
end
|
58
42
|
|
data/lib/chomsky_nf.rb
CHANGED
@@ -46,15 +46,15 @@ class ChomskyNF
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def _handle_all_rule(new_rules)
|
49
|
-
new_rules_buffer =
|
49
|
+
new_rules_buffer = []
|
50
50
|
|
51
51
|
new_rules.each do |var, rules|
|
52
52
|
next if _is_character? rules
|
53
53
|
|
54
|
-
new_rules_buffer
|
54
|
+
new_rules_buffer << _new_rules_buffer(rules, var)
|
55
55
|
end
|
56
56
|
|
57
|
-
new_rules.merge! new_rules_buffer
|
57
|
+
new_rules.merge! new_rules_buffer.reduce(&:merge)
|
58
58
|
end
|
59
59
|
|
60
60
|
def _is_character?(value)
|
@@ -3,15 +3,15 @@
|
|
3
3
|
# simplify chomsky normal form
|
4
4
|
class ChomskyNFSimplifier
|
5
5
|
def run(new_rules, alphabet)
|
6
|
-
|
6
|
+
vars_with_one_letter = _vars_with_one_letter new_rules, alphabet
|
7
7
|
|
8
|
-
return new_rules if
|
8
|
+
return new_rules if vars_with_one_letter.empty?
|
9
9
|
|
10
|
-
|
10
|
+
extendible_rules = _find_extendible_rules new_rules, vars_with_one_letter.keys
|
11
11
|
|
12
|
-
return new_rules if
|
12
|
+
return new_rules if extendible_rules.empty?
|
13
13
|
|
14
|
-
missing_rules =
|
14
|
+
missing_rules = _missing_rules extendible_rules, vars_with_one_letter
|
15
15
|
|
16
16
|
_add_missing_rules missing_rules, new_rules
|
17
17
|
|
@@ -20,56 +20,57 @@ class ChomskyNFSimplifier
|
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
|
-
def
|
23
|
+
def _vars_with_one_letter(new_rules, alphabet)
|
24
24
|
vars = {}
|
25
25
|
|
26
26
|
new_rules.each do |key, values|
|
27
|
+
# skip simple rules like (A, a), (B, b),...
|
27
28
|
next if values.size == 1
|
28
29
|
|
29
|
-
values.
|
30
|
-
|
31
|
-
|
32
|
-
vars[key] ||= []
|
33
|
-
vars[key] << val
|
34
|
-
end
|
30
|
+
letters = values.select { |val| _is_letter val, alphabet }.uniq
|
31
|
+
vars[key] = letters
|
35
32
|
end
|
36
33
|
|
37
34
|
vars
|
38
35
|
end
|
39
36
|
|
40
|
-
def
|
41
|
-
|
37
|
+
def _is_letter(val, alphabet)
|
38
|
+
val.size == 1 && alphabet.include?(val.downcase)
|
39
|
+
end
|
42
40
|
|
43
|
-
|
44
|
-
|
41
|
+
def _find_extendible_rules(new_rules, rules_keys)
|
42
|
+
extendible = {}
|
45
43
|
|
46
|
-
|
47
|
-
vars.each_key do |k|
|
48
|
-
next unless v.include?(k)
|
44
|
+
filterd_rules = new_rules.reject { |_, rules| rules.is_a?(String) }
|
49
45
|
|
50
|
-
|
46
|
+
filterd_rules.each do |letter, rules|
|
47
|
+
rules_keys.each do |rules_key|
|
48
|
+
rules.each do |rule|
|
49
|
+
next unless rule.include?(rules_key)
|
51
50
|
|
52
|
-
|
53
|
-
|
51
|
+
extendible[letter] ||= []
|
52
|
+
extendible[letter] << rule
|
54
53
|
end
|
55
54
|
end
|
56
55
|
end
|
57
56
|
|
58
|
-
|
57
|
+
extendible
|
59
58
|
end
|
60
59
|
|
61
|
-
def
|
60
|
+
def _missing_rules(extendible_rules, vars)
|
62
61
|
res = {}
|
63
62
|
|
64
|
-
|
65
|
-
nfs.
|
63
|
+
extendible_rules.each do |var_rule, nfs|
|
64
|
+
nfs.each do |nf|
|
66
65
|
vars.each do |match_char, replacement_chars|
|
67
66
|
replacement_chars.each do |rc|
|
68
|
-
new_rules = _combinations nf, rc, match_char
|
69
67
|
res[var_rule] ||= []
|
70
|
-
res[var_rule] <<
|
68
|
+
res[var_rule] << _combinations(nf, rc, match_char)
|
71
69
|
end
|
72
70
|
end
|
71
|
+
|
72
|
+
res[var_rule] = res[var_rule]&.flatten&.uniq
|
73
|
+
|
73
74
|
_check_special_case nf, res, var_rule, vars
|
74
75
|
end
|
75
76
|
end
|
@@ -93,7 +94,11 @@ class ChomskyNFSimplifier
|
|
93
94
|
end
|
94
95
|
|
95
96
|
def _add_missing_rules(missing_rules, new_rules)
|
96
|
-
missing_rules.each
|
97
|
+
missing_rules.each do |key, val|
|
98
|
+
next if val.nil?
|
99
|
+
|
100
|
+
new_rules[key].concat(val).uniq!
|
101
|
+
end
|
97
102
|
end
|
98
103
|
|
99
104
|
def _check_special_case(nf, res, var_rule, vars)
|
@@ -102,7 +107,7 @@ class ChomskyNFSimplifier
|
|
102
107
|
|
103
108
|
missing_rules = combi.map { |lft| combi.map { |rgt| "#{lft}#{rgt}" } }.flatten
|
104
109
|
|
105
|
-
res[var_rule]
|
110
|
+
res[var_rule].concat(missing_rules)
|
106
111
|
end
|
107
112
|
|
108
113
|
res
|
data/lib/cyk.rb
CHANGED
@@ -13,7 +13,7 @@ class CYK
|
|
13
13
|
def run
|
14
14
|
_cyk_fill_diagonal
|
15
15
|
_cyk_fill_matrix
|
16
|
-
_is_in_l?
|
16
|
+
@is_in_l = _is_in_l?
|
17
17
|
end
|
18
18
|
|
19
19
|
private
|
@@ -34,9 +34,9 @@ class CYK
|
|
34
34
|
|
35
35
|
next if i == j
|
36
36
|
|
37
|
-
helper_var
|
38
|
-
|
39
|
-
@matrix[i][j]
|
37
|
+
helper_var = _helper_var i, j
|
38
|
+
matrix_ele_info = _matrix_ele_info i, j
|
39
|
+
@matrix[i][j] = _add_to_matrix helper_var, matrix_ele_info
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
@@ -55,20 +55,44 @@ class CYK
|
|
55
55
|
res
|
56
56
|
end
|
57
57
|
|
58
|
-
def
|
59
|
-
res =
|
60
|
-
|
58
|
+
def _matrix_ele_info(i, j)
|
59
|
+
res = {}
|
60
|
+
|
61
|
+
res['i'] = i
|
62
|
+
res['j'] = j
|
63
|
+
res['row_c'] = @matrix.count
|
64
|
+
|
65
|
+
res
|
66
|
+
end
|
67
|
+
|
68
|
+
def _add_to_matrix(helper_var, matrix_ele_info)
|
69
|
+
matrix_ele = '0'
|
70
|
+
return if helper_var == matrix_ele
|
71
|
+
|
72
|
+
keys = []
|
61
73
|
|
62
74
|
@rules.each do |key, vals|
|
63
75
|
vals.each do |val|
|
64
|
-
|
76
|
+
keys << key if val == helper_var
|
65
77
|
end
|
66
78
|
end
|
67
79
|
|
68
|
-
|
80
|
+
_matrix_ele keys, matrix_ele_info
|
81
|
+
end
|
82
|
+
|
83
|
+
def _matrix_ele(keys, matrix_ele_info)
|
84
|
+
return 'S' if keys.include?('S') && _is_last_element?(matrix_ele_info)
|
85
|
+
|
86
|
+
return keys.last if keys.size == 1
|
87
|
+
|
88
|
+
keys.reject { |key| key == 'S' }.last || '0'
|
89
|
+
end
|
90
|
+
|
91
|
+
def _is_last_element?(matrix_ele_info)
|
92
|
+
matrix_ele_info['i'].zero? && matrix_ele_info['j'] == matrix_ele_info['row_c'] - 1
|
69
93
|
end
|
70
94
|
|
71
95
|
def _is_in_l?
|
72
|
-
@
|
96
|
+
@matrix.first.last == 'S'
|
73
97
|
end
|
74
98
|
end
|
data/lib/epsilon_free.rb
CHANGED
data/lib/falafel.rb
CHANGED
@@ -104,10 +104,10 @@ class Falafel
|
|
104
104
|
dfa.to_min
|
105
105
|
end
|
106
106
|
|
107
|
-
def pump_lemma
|
107
|
+
def pump_lemma(lang, length)
|
108
108
|
require_relative 'pump'
|
109
109
|
|
110
|
-
Pump.new lang:
|
110
|
+
Pump.new lang: lang, length: length
|
111
111
|
end
|
112
112
|
|
113
113
|
def cfg(alphabet, vars_set, start_var, rules)
|
@@ -118,7 +118,6 @@ class Falafel
|
|
118
118
|
|
119
119
|
private
|
120
120
|
|
121
|
-
# alle bilder eine menge m unter r
|
122
121
|
def _image(m, r)
|
123
122
|
m.flat_map { |x| r.map { |y, z| z if x == y }.compact }.sort.uniq
|
124
123
|
end
|
data/lib/pump.rb
CHANGED
@@ -2,29 +2,68 @@
|
|
2
2
|
|
3
3
|
# Pump Lemma
|
4
4
|
# It takes language as lambda function and a word as a string
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# lang is a regular expression like a^*b^* given as lambda function and set by user
|
6
|
+
# word is the word to check pumping
|
7
|
+
# length is the length of the string you want to pump
|
8
|
+
# return is_regular to tell if lang is regular and decomposition to show why
|
7
9
|
class Pump
|
8
10
|
attr_accessor :lang, :word
|
11
|
+
attr_reader :is_regular, :decomposition
|
9
12
|
|
10
|
-
def initialize(lang:,
|
11
|
-
@lang
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@k = k
|
13
|
+
def initialize(lang:, length:)
|
14
|
+
@lang = lang
|
15
|
+
@length = length
|
16
|
+
@word = ''
|
15
17
|
end
|
16
18
|
|
17
|
-
def run
|
19
|
+
def run(show_pros:)
|
20
|
+
_clear_old_run
|
21
|
+
|
18
22
|
r, s, t = ''
|
19
23
|
|
20
|
-
|
21
|
-
r =
|
22
|
-
|
23
|
-
|
24
|
+
@word.length.times do |leng|
|
25
|
+
r, s, t = _sigma_chars leng
|
26
|
+
|
27
|
+
pump_up_down_res = _pump_up_down_res r, s, t, show_pros
|
28
|
+
not_in_language = pump_up_down_res.include? false
|
24
29
|
|
25
|
-
|
30
|
+
@is_regular = false if not_in_language
|
31
|
+
|
32
|
+
break if not_in_language
|
26
33
|
end
|
27
34
|
|
35
|
+
@decomposition = [r, s, t]
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def _clear_old_run
|
41
|
+
@decomposition = []
|
42
|
+
@is_regular = true
|
43
|
+
end
|
44
|
+
|
45
|
+
# ∃r, s, t ∈ Σ^∗
|
46
|
+
def _sigma_chars(leng)
|
47
|
+
r = @word[0...leng] || ''
|
48
|
+
s = @word[leng...leng + @length] || ''
|
49
|
+
t = @word[leng + @length..] || ''
|
50
|
+
|
28
51
|
[r, s, t]
|
29
52
|
end
|
53
|
+
|
54
|
+
# ∀k ≥ 0 : r·s^k·t ∈ L
|
55
|
+
def _pump_up_down_res(r, s, t, show_pros)
|
56
|
+
pump_up_down_res = []
|
57
|
+
|
58
|
+
20.times do |k|
|
59
|
+
puts "r: #{r}, s: #{s}, t: #{t}, k: #{k}, r + s * k + t: #{r + s * k + t}" if show_pros
|
60
|
+
pump_up_down_res << _pump_condtion_satisfied?(r, s, t, k)
|
61
|
+
end
|
62
|
+
|
63
|
+
pump_up_down_res
|
64
|
+
end
|
65
|
+
|
66
|
+
def _pump_condtion_satisfied?(r, s, t, k)
|
67
|
+
(s.length.positive? && @lang.call(r + s * k + t))
|
68
|
+
end
|
30
69
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: falafel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abed Alkedda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-08-
|
11
|
+
date: 2023-08-12 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -28,7 +28,7 @@ files:
|
|
28
28
|
- lib/rx.rb
|
29
29
|
homepage: https://github.com/AbedAlkedda/AFS
|
30
30
|
licenses:
|
31
|
-
-
|
31
|
+
- ''
|
32
32
|
metadata: {}
|
33
33
|
post_install_message:
|
34
34
|
rdoc_options: []
|
@@ -48,5 +48,6 @@ requirements: []
|
|
48
48
|
rubygems_version: 3.3.26
|
49
49
|
signing_key:
|
50
50
|
specification_version: 4
|
51
|
-
summary: Falafel is a gem
|
51
|
+
summary: Falafel is a gem that will hopefully help you better understand automata
|
52
|
+
and formal languages
|
52
53
|
test_files: []
|