rlsm 0.2.4 → 0.4.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.
@@ -1,123 +0,0 @@
1
- #
2
- # This file is part of the RLSM gem.
3
- #
4
- #(The MIT License)
5
- #
6
- #Copyright (c) 2008 Gunther Diemant <g.diemant@gmx.net>
7
- #
8
- #Permission is hereby granted, free of charge, to any person obtaining
9
- #a copy of this software and associated documentation files (the
10
- #'Software'), to deal in the Software without restriction, including
11
- #without limitation the rights to use, copy, modify, merge, publish,
12
- #distribute, sublicense, and/or sell copies of the Software, and to
13
- #permit persons to whom the Software is furnished to do so, subject to
14
- #the following conditions:
15
- #
16
- #The above copyright notice and this permission notice shall be
17
- #included in all copies or substantial portions of the Software.
18
- #
19
- #THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
20
- #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
- #MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
- #IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
- #CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
- #TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25
- #SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
- #
27
-
28
-
29
- require "rubygems"
30
- require "sqlite3"
31
- require "singleton"
32
-
33
- module RLSM
34
- class MonoidDB
35
-
36
- Columns = [:binop, :m_order, :num_generators,
37
- :num_idempotents, :num_left_nulls, :num_right_nulls,
38
- :syntactic, :idempotent, :aperiodic,
39
- :commutative, :is_group, :has_null,
40
- :l_trivial, :r_trivial, :d_trivial]
41
-
42
- include Singleton
43
-
44
- attr_reader :db
45
-
46
- def self.query(query, &block)
47
- if block_given?
48
- instance.db.execute(query, &block)
49
- else
50
- instance.db.execute(query)
51
- end
52
- end
53
-
54
- def self.find(params = {}, &block)
55
- if block_given?
56
- query construct_query(params), &block
57
- else
58
- query construct_query(params)
59
- end
60
- end
61
-
62
- def self.count(params = {})
63
- q = construct_query(params).sub('T binop F',
64
- "T count(*), total(syntactic) F")
65
- query(q).first.map { |x| x.to_i }
66
- end
67
-
68
- def self.statistic
69
- res = instance.db.execute2 <<SQL
70
- SELECT
71
- m_order AS 'Order',
72
- count(*) AS 'Total',
73
- total(syntactic) AS 'Syntactic',
74
- total(is_group) AS 'Groups',
75
- total(commutative) AS 'Commutative',
76
- total(aperiodic) AS 'Aperiodic',
77
- total(idempotent) AS 'Idempotent'
78
- FROM monoids
79
- GROUP BY m_order
80
- ORDER BY 'Order' ASC;
81
- SQL
82
-
83
- desc = res.shift
84
- res.map! { |row| row.map { |x| x.to_i } }
85
- res.unshift desc
86
-
87
- res
88
- end
89
-
90
- private
91
- def initialize
92
- db_name = File.join(File.dirname(__FILE__), '..', 'data', 'monoids.db')
93
- @db = SQLite3::Database.open(db_name)
94
- end
95
-
96
- def self.construct_query(params)
97
- limit = ""
98
- if params[:limit]
99
- limit = "\nLIMIT #{params[:limit]}"
100
- params.delete :limit
101
- if params[:offset]
102
- limit += " OFFSET #{params[:offset]}"
103
- end
104
- end
105
-
106
- order_by = "\nORDER BY binop #{params[:ordering] || 'ASC'}"
107
-
108
- params.delete :ordering
109
-
110
- q = "SELECT binop FROM monoids"
111
-
112
- where = Columns.map do |col|
113
- params[col] ? ("#{col.to_s} = #{params[col]}") : nil
114
- end.compact.join(" AND ")
115
-
116
- if where.length > 0
117
- q += "\nWHERE " + where
118
- end
119
-
120
- q + order_by + limit + ";"
121
- end
122
- end
123
- end
@@ -1,229 +0,0 @@
1
- #
2
- # This file is part of the RLSM gem.
3
- #
4
- #(The MIT License)
5
- #
6
- #Copyright (c) 2008 Gunther Diemant <g.diemant@gmx.net>
7
- #
8
- #Permission is hereby granted, free of charge, to any person obtaining
9
- #a copy of this software and associated documentation files (the
10
- #'Software'), to deal in the Software without restriction, including
11
- #without limitation the rights to use, copy, modify, merge, publish,
12
- #distribute, sublicense, and/or sell copies of the Software, and to
13
- #permit persons to whom the Software is furnished to do so, subject to
14
- #the following conditions:
15
- #
16
- #The above copyright notice and this permission notice shall be
17
- #included in all copies or substantial portions of the Software.
18
- #
19
- #THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
20
- #EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
- #MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
- #IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
23
- #CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24
- #TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25
- #SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
- #
27
-
28
- require File.join(File.dirname(__FILE__), 'monkey_patching')
29
- require File.join(File.dirname(__FILE__), 'exceptions.rb')
30
- require File.join(File.dirname(__FILE__), 'regexp_nodes', 'renodes')
31
- require File.join(File.dirname(__FILE__), 'dfa')
32
-
33
- module RLSM
34
- class RegExp
35
- include RLSM::RENodes
36
-
37
- #Creates a new RegExp from a string description. Metacharacters are
38
- # & * | ( )
39
- #Here & is the empty word and an empty string represents the empty set.
40
- def initialize(desc = "")
41
- #Is the argument a well formed RegExp?
42
- _well_formed?(desc)
43
-
44
- @re = RLSM::RENodes.new(desc)
45
- end
46
-
47
- #--
48
- #Operations of a regexp
49
- #++
50
-
51
- #Kleene star of the regexp. Alters the regexp in place
52
- def star!
53
- #For empty set and empty word a star changes nothing.
54
- #A double star is also useless
55
- return if empty? or lambda? or (@re.class == Star)
56
- str = '(' + to_s + ')*'
57
- @re = RLSM::RENodes.new(str)
58
-
59
- #Unset the str rep
60
- @re_str = nil
61
-
62
- self
63
- end
64
-
65
- #Returns the kleene star of this regexp. Leaves the regexp untouched.
66
- def star
67
- self.deep_copy.star!
68
- end
69
-
70
- #Returns the concatenation of two regexps
71
- def *(other)
72
- return RegExp.new if empty? or other.empty?
73
- RegExp.new('(' + to_s + ')(' + other.to_s + ')')
74
- end
75
-
76
- #Returns the union of two regexps
77
- def +(other)
78
- return self.deep_copy if other.empty?
79
- return other.deep_copy if empty?
80
- RegExp.new('(' + to_s + ')|(' + other.to_s + ')')
81
- end
82
-
83
- #--
84
- #Some small flags
85
- #++
86
- #Returns true if this regexp is the empty word.
87
- def lambda?
88
- @re.lambda?
89
- end
90
-
91
- #Returns true if this regexp is the empty set.
92
- def empty?
93
- @re.empty?
94
- end
95
-
96
- #Returns true if the empty word matches this regexp
97
- def null?
98
- @re.null?
99
- end
100
-
101
- #--
102
- #Some properties of a regexp
103
- #++
104
-
105
- #Returns an array of beginning symbols of the regexp.
106
- def first
107
- @re.first
108
- end
109
-
110
- #Returns an array of end symbols of the regexp.
111
- def last
112
- @re.last
113
- end
114
-
115
- #Returns an array of all possible two letter substrings of words matched by the regexp.
116
- def follow
117
- @re.follow.uniq
118
- end
119
-
120
- #--
121
- #Conversion methods
122
- #++
123
- #Returns a string representation of the regexp
124
- def to_s
125
- @re_str ||= @re.to_s
126
- end
127
-
128
- #Returns a minimal DFA which accepts the same language as the regexp.
129
- def to_dfa
130
- #Step 1: Substitute every char such that every character is unique
131
- #Add also a beginning marker
132
-
133
- orig = []
134
- rre = [0]
135
- to_s.each_char do |c|
136
- if ['(', ')', '|', '*', '&'].include? c
137
- rre << c
138
- else
139
- orig << c
140
- rre << (orig.size)
141
- end
142
- end
143
-
144
- tmp_re = RLSM::RENodes.new(rre)
145
-
146
- #Step 2a: Construct a DFA representation of this new regexp
147
- #Step 2b: reverse the substitution (yields (maybe) a NFA)
148
-
149
- alph = orig.uniq
150
- initial = 0
151
-
152
- tmp_finals = tmp_re.last
153
-
154
- tmp_trans = tmp_re.follow.map do |s1,s2|
155
- [orig[s2-1], s1, s2]
156
- end
157
-
158
- #Step 4: Transform the NFA to a DFA
159
- states = [[0]]
160
- new_states = [[0]]
161
- trans = []
162
- while new_states.size > 0
163
- tmp = new_states.deep_copy
164
- new_states = []
165
-
166
- tmp.each do |new_state|
167
- alph.each do |char|
168
- tr_set = tmp_trans.find_all do |c,s1,s2|
169
- c == char and new_state.include? s1
170
- end
171
-
172
- unless tr_set.empty?
173
- state = tr_set.map { |c,s1,s2| s2 }.sort
174
-
175
- #Found a new state?
176
- unless states.include? state
177
- new_states << state
178
- states << state
179
- end
180
-
181
- tr = [char, states.index(new_state), states.index(state)]
182
-
183
- #Found new trans?
184
- trans << tr unless trans.include? tr
185
- end
186
- end
187
- end
188
- end
189
-
190
- finals = states.find_all do |state|
191
- tmp_finals.any? { |tf| state.include? tf }
192
- end.map { |fi| states.index(fi) }
193
-
194
- states = (0...states.size).to_a
195
-
196
- #Step 5: Return the result
197
- RLSM::DFA.new(alph,states,initial,finals,trans).minimize(:rename_states => true)
198
- end
199
-
200
- def inspect # :nodoc:
201
- "<#{self.class} : '#{to_s}' >"
202
- end
203
-
204
- #Returns true if the two regexps are the same, i.e. the dfas are isomorphic.
205
- def ==(other)
206
- to_dfa == other.to_dfa
207
- end
208
-
209
-
210
- private
211
- def _well_formed?(str)
212
- #parantheses must be balanced, somthing like |) or *a or (| isn't allowed
213
- #1 balanced parenthesis
214
- state = 0
215
- str.each_char do |c|
216
- state += RLSM::RENodes::PCount[c]
217
- end
218
-
219
- if state != 0
220
- raise RegExpException, "Unbalanced parenthesis in #{str}"
221
- end
222
-
223
- #2 bad sequenzes
224
- if str =~ /\(\)|\|\)|\(\||\|\*|^\*|\(\*/
225
- raise RegExpException, "Bad character sequence #{$&} found in #{str}"
226
- end
227
- end
228
- end
229
- end
@@ -1,112 +0,0 @@
1
- module RLSM::RENodes
2
- private
3
- class Concat
4
- def initialize(parent, str)
5
- @parent = parent
6
- @childs = _split(str).map do |substr|
7
- RLSM::RENodes.new(substr, self)
8
- end.reject { |child| child.lambda? }
9
- end
10
-
11
- def null?
12
- @childs.all? { |child| child.null? }
13
- end
14
-
15
- def first
16
- res = []
17
- @childs.each do |child|
18
- child.first.each do |f|
19
- res << f
20
- end
21
-
22
- break unless child.null?
23
- end
24
-
25
- res
26
- end
27
-
28
- def last
29
- res = []
30
- @childs.reverse.each do |child|
31
- child.last.each do |f|
32
- res << f
33
- end
34
-
35
- break unless child.null?
36
- end
37
-
38
- res
39
- end
40
-
41
- def follow
42
- res = []
43
-
44
- @childs.each do |child|
45
- child.follow.each do |f|
46
- res << f
47
- end
48
- end
49
-
50
- (1...@childs.size).each do |i|
51
- @childs[i-1].last.each do |l|
52
- @childs[(i..-1)].each do |ch|
53
- ch.first.each do |f|
54
- res << [l,f]
55
- end
56
-
57
- break unless ch.null?
58
- end
59
- end
60
- end
61
-
62
- res
63
- end
64
-
65
- def to_s
66
- @childs.map { |child| child.to_s }.join
67
- end
68
-
69
- def lambda?
70
- false
71
- end
72
-
73
- def empty?
74
- false
75
- end
76
-
77
- private
78
- def _split(str)
79
- state = 0
80
- count = Hash.new(0)
81
- count['('] = 1
82
- count[')'] = -1
83
-
84
- res = [[]]
85
- previous = nil
86
- str.each_char do |c|
87
- state += count[c]
88
-
89
- if state == 1 and c == '('
90
- res << []
91
- res.last << c
92
- elsif state == 0 and c == '*'
93
- if previous == ')'
94
- res[-2] << c
95
- else
96
- res << [res.last.pop, c]
97
- res << []
98
- end
99
- elsif state == 0 and c == ')'
100
- res.last << c
101
- res << []
102
- else
103
- res.last << c
104
- end
105
-
106
- previous = c
107
- end
108
-
109
- res.select { |subarr| subarr.size > 0 }#.map { |substr| substr.join }
110
- end
111
- end
112
- end