rlsm 1.0.0 → 1.1.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,6 +0,0 @@
1
- === 1.0.0 / 2008-11-09
2
-
3
- * 1 major enhancement
4
-
5
- * Birthday!
6
-
@@ -1,18 +0,0 @@
1
- History.txt
2
- Manifest.txt
3
- README.txt
4
- Rakefile
5
- bin/smon
6
- data/monoids.db
7
- lib/database.rb
8
- lib/monkey_patching/array_ext.rb
9
- lib/rlsm.rb
10
- lib/rlsm/dfa.rb
11
- lib/rlsm/monoid.rb
12
- lib/rlsm/re.rb
13
- lib/smon/base.rb
14
- lib/smon/db.rb
15
- lib/smon/dot.rb
16
- lib/smon/latex.rb
17
- lib/smon/smon.rb
18
- stdarb.tex
data/bin/smon DELETED
@@ -1,39 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require File.join(File.dirname(__FILE__), '..', 'lib', 'smon', 'smon')
3
- require 'optparse'
4
-
5
- Version = RLSM::VERSION
6
- out = STDOUT
7
- path = ""
8
-
9
- opts = OptionParser.new do |op|
10
- op.banner = <<USEAGE
11
- Usage: smon [-oh] [FILE1 FILE2 ...]
12
- Executes each FILE as smon script or if no file is given
13
- starts in interactive mode.
14
-
15
- USEAGE
16
- op.separator("Options:")
17
-
18
- op.on('-p','--path PATH', "Adds PATH to the loadpath for librarys.") do |p|
19
- path = p
20
- end
21
-
22
- op.on('-o', '--out FILE', "Output is redirected to FILE.") do |f|
23
- out = File.open(f, 'w')
24
- end
25
-
26
- op.on_tail('-h', '--help', "This help.") { puts op; exit }
27
- op.on_tail('--version', "Shows version.") { puts op.ver }
28
- end
29
-
30
- begin
31
- opts.parse! ARGV
32
-
33
- SMON.new :files =>ARGV, :messenger => out, :path => path
34
- rescue => e
35
- STDERR.puts "Error: #{e.message}"
36
- STDERR.puts
37
- STDERR.puts opts
38
- exit 1
39
- end
Binary file
@@ -1,95 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'rlsm'))
2
-
3
- require "rubygems"
4
- require "sqlite3"
5
-
6
- class RLSM::MonoidDB
7
- @@db = SQLite3::Database.open(File.join(File.dirname(__FILE__), '..',
8
- 'data', 'monoids.db'))
9
-
10
- Columns = [:binop, :m_order, :num_generators,
11
- :num_idempotents, :num_left_nulls, :num_right_nulls,
12
- :syntactic, :idempotent, :aperiodic,
13
- :commutative, :is_group, :has_null,
14
- :l_trivial, :r_trivial, :d_trivial]
15
-
16
- def self.query(query, &block)
17
- if block_given?
18
- @@db.execute(query, &block)
19
- else
20
- @@db.execute(query)
21
- end
22
- end
23
-
24
- def self.find(params = {}, &block)
25
- if block_given?
26
- query construct_query(params), &block
27
- else
28
- query construct_query(params)
29
- end
30
- end
31
-
32
- def self.count(params = {})
33
- q = construct_query(params).sub('T binop F',
34
- "T count(*), total(syntactic) F")
35
- query(q).first.map { |x| x.to_i }
36
- end
37
-
38
- def self.statistic
39
- res = @@db.execute2 <<SQL
40
- SELECT
41
- m_order AS 'Order',
42
- count(*) AS 'Total',
43
- total(syntactic) AS 'Syntactic',
44
- total(is_group) AS 'Groups',
45
- total(commutative) AS 'Commutative',
46
- total(aperiodic) AS 'Aperiodic',
47
- total(idempotent) AS 'Idempotent'
48
- FROM monoids
49
- GROUP BY m_order
50
- ORDER BY 'Order' ASC;
51
- SQL
52
-
53
- desc = res.shift
54
- res.map! { |row| row.map { |x| x.to_i } }
55
- res.unshift desc
56
-
57
- res
58
- end
59
-
60
- private
61
- def self.construct_query(params)
62
- limit = ""
63
- if params[:limit]
64
- limit = "\nLIMIT #{params[:limit]}"
65
- params.delete :limit
66
- if params[:offset]
67
- limit += " OFFSET #{params[:offset]}"
68
- end
69
- end
70
-
71
- order_by = "\nORDER BY binop #{params[:ordering] || 'ASC'}"
72
-
73
- params.delete :ordering
74
-
75
- q = "SELECT binop FROM monoids"
76
-
77
- where = Columns.inject([]) do |res,col|
78
- if params[col]
79
- if [:binop, :m_order].include?(col) or col.to_s =~ /^num_/
80
- res << "#{col.to_s} = #{params[col]}"
81
- else
82
- res << "#{col.to_s} = 1"
83
- end
84
- end
85
-
86
- res
87
- end.join(" AND ")
88
-
89
- if where.length > 0
90
- q += "\nWHERE " + where
91
- end
92
-
93
- q + order_by + limit + ";"
94
- end
95
- end
@@ -1,50 +0,0 @@
1
- module RLSMArrayExt # :nodoc:
2
- #Returns all permutations of the array.
3
- def permutations
4
- return [self] if size < 2
5
- perm = []
6
- each { |e| (self - [e]).permutations.each { |p| perm << ([e] + p) } }
7
- perm
8
- end
9
-
10
- #Returns the powerset of the array (interpreted as set).
11
- def powerset
12
- ret = self.inject([[]]) do |acc, x|
13
- res = []
14
- acc.each { |s| res << s; res << ([x]+s).sort }
15
- res
16
- end
17
-
18
- ret.sort_lex
19
- end
20
-
21
- #Sorts an array of arrays more or less lexicographical.
22
- def sort_lex
23
- sort { |s1, s2| s1.size == s2.size ? s1 <=> s2 : s1.size <=> s2.size }
24
- end
25
-
26
- #Returns the cartesian product of self and the given arrays
27
- def product(*args)
28
- args.inject(self.map { |x| [x] }) do |res,arr|
29
- new = []
30
- arr.each do |x|
31
- new += res.map { |tup| tup += [x] }
32
- end
33
- new
34
- end
35
- end
36
-
37
- #Returns all unordered pairs.
38
- def unordered_pairs
39
- pairs = []
40
- (0...size-1).each do |i|
41
- pairs |= self[i+1..-1].map { |x| [self[i],x] }
42
- end
43
-
44
- pairs
45
- end
46
- end
47
-
48
- class Array # :nodoc:
49
- include RLSMArrayExt
50
- end
@@ -1,504 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rlsm'))
2
- require 'enumerator'
3
-
4
- class RLSM::RE
5
- LeftBracket = '('
6
- RightBracket = ')'
7
- Star = '*'
8
- Union = '|'
9
- Lambda = '&'
10
- Specials = [LeftBracket, RightBracket, Star, Union, Lambda]
11
-
12
- def to_s
13
- @pattern
14
- end
15
-
16
- def inspect
17
- "<#{self.class}: #@pattern>"
18
- end
19
-
20
- def initialize(pattern = '')
21
- if pattern == ''
22
- @empty_set = true
23
- elsif pattern.scan(/./).all? { |x| Specials.include? x }
24
- @pattern = Lambda
25
- else
26
- @pattern = pattern
27
- end
28
-
29
- unless @empty_set
30
- validate_brackets_balanced
31
- validate_form
32
- preparse
33
- parse
34
- else
35
- @pattern = ''
36
- @parsed = { :first => [], :last => [], :follow => [], :null => false }
37
- end
38
- end
39
-
40
- #Returns the patttern of the regexp
41
- attr_reader :pattern
42
-
43
- #Returns the union of this and the other re as new re.
44
- def +(other)
45
- #One is the empty set?
46
- return RLSM::RE.new(@pattern) if other.pattern == ''
47
- return RLSM::RE.new(other.pattern) if @pattern == ''
48
-
49
- RLSM::RE.new(LeftBracket + @pattern + RightBracket +
50
- Union +
51
- LeftBracket + other.pattern + RightBracket)
52
- end
53
-
54
- #Returns the catenation of this and other re.
55
- def *(other)
56
- #One is the empty set?
57
- return RLSM::RE.new if other.pattern == '' or @pattern == ''
58
-
59
- RLSM::RE.new(LeftBracket + @pattern + RightBracket +
60
- LeftBracket + other.pattern + RightBracket)
61
- end
62
-
63
- #Returns the stared re.
64
- def star
65
- return RLSM::RE.new if @pattern == ''
66
- RLSM::RE.new(LeftBracket + @pattern + RightBracket + Star)
67
- end
68
-
69
- #Alters the re in place to the star form. Returns the altered re.
70
- def star!
71
- unless @pattern == ''
72
- @pattern = LeftBracket + @pattern + RightBracket + Star
73
- parse
74
- end
75
-
76
- self
77
- end
78
-
79
- #Returns a minimal DFA which accepts the same language.
80
- def to_dfa
81
- if @empty_set
82
- RLSM::DFA.new(:alphabet => [],:states => ['0'],:initial => '0',
83
- :finals => [], :transitions => [])
84
- else
85
- add_initial_state
86
- perform_subset_construction
87
- RLSM::DFA.create(@dfa_hash).minimize!(:rename => :new)
88
- end
89
- end
90
-
91
- #Returns the syntactic monoid to this language.
92
- def to_monoid
93
- to_dfa.to_monoid
94
- end
95
-
96
- #Returns self.
97
- def to_re
98
- self
99
- end
100
-
101
- #Returns true if the res are equal
102
- def ==(other)
103
- return true if @pattern == other.pattern
104
-
105
- to_dfa.isomorph_to?(other.to_dfa)
106
- end
107
-
108
- private
109
- def add_initial_state
110
- @parsed[:initial] = [-1]
111
- @parsed[:follow] |= @parsed[:initial].product(@parsed[:first])
112
- end
113
-
114
- def perform_subset_construction
115
- @dfa_hash = {:transitions => [], :finals => [], :initial => '0'}
116
- @dfa_hash[:finals] << @parsed[:initial] if @parsed[:null]
117
- alphabet = @iso.uniq
118
- unmarked = [@parsed[:initial]]
119
- marked = []
120
- until unmarked.empty?
121
- state = unmarked.shift
122
- marked << state
123
- alphabet.each do |char|
124
- nstate = move(state, char)
125
- unmarked << nstate unless (unmarked | marked).include? nstate
126
- if @parsed[:last].any? { |x| nstate.include? x }
127
- @dfa_hash[:finals] << nstate unless @dfa_hash[:finals].include? nstate
128
- end
129
- @dfa_hash[:transitions] << [char, state, nstate]
130
- end
131
- end
132
-
133
- @dfa_hash[:finals].map! { |x| marked.index(x).to_s }
134
- @dfa_hash[:transitions].map! { |c,x,y| [c,marked.index(x).to_s,
135
- marked.index(y).to_s] }
136
- end
137
-
138
- def move(state,c)
139
- state.map do |x|
140
- @parsed[:follow].find_all { |y,z| y == x and @iso[z] == c }.map do |a|
141
- a.last
142
- end
143
- end.flatten.uniq.sort
144
- end
145
-
146
- def parse
147
- pat, @iso = transform_pattern_to_unique_identifiers
148
-
149
- @parsed = parse_pattern(pat)
150
- @pattern = @parsed[:pattern]
151
- end
152
-
153
- def parse_pattern(pat, parent = nil)
154
- pat = remove_surrounding_brackets pat
155
- pat = [Lambda] if pat.all? { |x| Specials.include? x }
156
-
157
- case type_of pat
158
- when :term : return parse_term(pat, parent)
159
- when :star : return parse_star(pat, parent)
160
- when :union : return parse_union(pat, parent)
161
- when :cat : return parse_cat(pat, parent)
162
- else
163
- raise REException, "Unable to parse pattern: #{pat.join}"
164
- end
165
- end
166
-
167
- def parse_children(childs, parent)
168
- childs.map { |child| parse_pattern(child, parent) }
169
- end
170
-
171
- def recursive_split(child, type)
172
- if type_of(child) == type
173
- return self.send("split_#{type}".to_sym, child)
174
- else
175
- return [child]
176
- end
177
- end
178
-
179
- def parse_union(p, parent)
180
- childs = parse_children(split_union(p), parent)
181
- childs = simplify_union(childs, parent)
182
-
183
- #If after simplification there is only one child left, the union isn't
184
- #needed anymore.
185
- return childs.first if childs.size == 1
186
-
187
- childs = sort_union(childs)
188
-
189
- construct_union_result_from childs
190
- end
191
-
192
- def split_union(p)
193
- depth = 0
194
- splitted = [[]]
195
- p.each do |x|
196
- depth += count(x)
197
- if depth == 0 and x == Union
198
- splitted << remove_surrounding_brackets(splitted.pop)
199
- splitted << []
200
- else
201
- splitted.last << x
202
- end
203
- end
204
-
205
- splitted.inject([]) { |res,x| res | recursive_split(x, :union) }
206
- end
207
-
208
- def simplify_union(childs, parent)
209
- #Check if we need an empty word, not the case if
210
- # - parent is a star
211
- # - some nullable choices exists
212
- if childs.any? { |x| x[:null] and x[:pattern] != Lambda } or parent == :star
213
- childs = childs.reject { |x| x[:pattern] == Lambda }
214
- end
215
-
216
- #Simplify somthing like 'a|a' to 'a'
217
- childs.inject([]) do |res,child|
218
- res << child unless res.any? { |x| x[:pattern] == child[:pattern] }
219
- res
220
- end
221
- end
222
-
223
- def sort_union(childs)
224
- childs.sort do |x1,x2|
225
- if x1[:pattern] == Lambda
226
- -1
227
- elsif x2[:pattern] == Lambda
228
- 1
229
- else
230
- x1[:pattern] <=> x2[:pattern]
231
- end
232
- end
233
- end
234
-
235
- def construct_union_result_from(childs)
236
- res = {}
237
- res[:type] = :union
238
-
239
- res[:null] = childs.any? { |x| x[:null] }
240
- res[:first] = childs.map { |x| x[:first] }.flatten
241
- res[:last] = childs.map { |x| x[:last] }.flatten
242
- res[:follow] = childs.inject([]) { |r,x| r | x[:follow] }
243
- res[:pattern] = childs.map { |x| x[:pattern] }.join(Union)
244
-
245
- res
246
- end
247
-
248
- def parse_cat(p, parent)
249
- childs = parse_children(split_cat(p), parent)
250
-
251
- childs = simplify_cat(childs, parent)
252
-
253
- #If after simplification there is only one child left, the cat isn't
254
- #needed anymore.
255
- return childs.first if childs.size == 1
256
-
257
- construct_cat_result_from childs
258
- end
259
-
260
- def split_cat(p)
261
- splitted = [[]]
262
- depth = 0
263
- p.each_with_index do |x,i|
264
- depth += count(x)
265
- if depth == 1 and x == LeftBracket
266
- splitted << [LeftBracket]
267
- elsif depth == 0
268
- if p[i+1] == Star
269
- if x == RightBracket
270
- splitted.last << RightBracket
271
- splitted.last << Star
272
- splitted << []
273
- else
274
- splitted << [x,Star]
275
- splitted << []
276
- end
277
- else
278
- splitted.last << x unless x == Star
279
- if x == RightBracket
280
- last = splitted.pop
281
- splitted << remove_surrounding_brackets(last) unless last.empty?
282
- splitted << []
283
- end
284
- end
285
- else
286
- splitted.last << x
287
- end
288
- end
289
-
290
- splitted.inject([]) do |res,x|
291
- unless x.empty? or x == [Lambda]
292
- res | recursive_split(x, :cat)
293
- else
294
- res
295
- end
296
- end
297
- end
298
-
299
- def simplify_cat(childs, parent)
300
- #Simplify a*a* to a*
301
- childs = childs.inject([]) do |res, child|
302
- unless child[:type] == :star and
303
- res.last and res.last[:type] == :star and
304
- child[:pattern] == res.last[:pattern]
305
- res << child
306
- end
307
-
308
- res
309
- end
310
-
311
- #Simplify (aa*)* to a*
312
- if parent == :star and childs.size == 2
313
- star_exp, other = childs.partition { |x| x[:type] == :star }
314
- unless star_exp.empty? or other.empty?
315
- p1 = remove_surrounding_brackets(star_exp.first[:pattern].
316
- scan(/./)[0..-2])
317
- p2 = remove_surrounding_brackets(other.first[:pattern].
318
- scan(/./))
319
-
320
- if p1 == p2
321
- return other
322
- end
323
- end
324
- end
325
-
326
- childs
327
- end
328
-
329
- def construct_cat_result_from(childs)
330
- childs.map! do |x|
331
- if x[:type] == :union
332
- x[:pattern] = LeftBracket + x[:pattern] + RightBracket
333
- x
334
- else
335
- x
336
- end
337
- end
338
-
339
- res = {}
340
- res[:null] = childs.all? { |x| x[:null] }
341
-
342
- childs.each do |x|
343
- res[:first] = (res[:first] ||= []) | x[:first]
344
- break unless x[:null]
345
- end
346
-
347
- childs.reverse.each do |x|
348
- res[:last] = (res[:last] ||= []) | x[:last]
349
- break unless x[:null]
350
- end
351
-
352
- res[:follow] = childs.inject([]) { |r,x| r | x[:follow] }
353
-
354
- (1...childs.size).each do |i|
355
- res[:follow] |= childs[i-1][:last].product(childs[i][:first])
356
- j = i
357
- while childs[j][:null] and (j < childs.size - 1)
358
- res[:follow] |= childs[i-1][:last].product(childs[j+1][:first])
359
- j += 1
360
- end
361
- end
362
-
363
- res[:pattern] = childs.map { |x| x[:pattern] }.join
364
-
365
- res
366
- end
367
-
368
- def parse_term(pat, parent)
369
- pat = pat.reject { |x| x == Lambda }
370
-
371
- res = {}
372
-
373
- res[:first] = [pat.first].compact
374
- res[:last] = [pat.last].compact
375
- res[:follow] = pat.enum_cons(2).to_a
376
- res[:null] = pat.empty?
377
- res[:pattern] = if res[:null]
378
- Lambda
379
- else
380
- pat.map { |i| @iso[i] }.join
381
- end
382
- res
383
- end
384
-
385
- def parse_star(pat, parent)
386
- pat = remove_surrounding_brackets(pat[0..-2])
387
- child = parse_pattern(pat, :star)
388
-
389
- if child[:pattern] == Lambda or child[:type] == :star
390
- return child
391
- else
392
- res = {}
393
- res[:type] = :star
394
- res[:null] = true
395
- res[:first] = child[:first]
396
- res[:last] = child[:last]
397
- res[:follow] = (child[:follow] | child[:last].product(child[:first]))
398
- res[:pattern] = if child[:pattern].size > 1
399
- LeftBracket + child[:pattern] + RightBracket + Star
400
- else
401
- child[:pattern] + Star
402
- end
403
-
404
- return res
405
- end
406
- end
407
-
408
- def remove_surrounding_brackets(pat)
409
- pat = pat[1..-2] while type_of(pat) == :surr_brackets
410
- pat
411
- end
412
-
413
- def type_of(p)
414
- return :term unless p.any? { |x| (Specials - [Lambda]).include? x }
415
-
416
- unnested_characters = []
417
- depth = 0
418
- p.each do |x|
419
- if x == LeftBracket
420
- unnested_characters << x if depth == 0
421
- depth += 1
422
- elsif x == RightBracket
423
- depth -= 1
424
- unnested_characters << x if depth == 0
425
- else
426
- unnested_characters << x if depth == 0
427
- end
428
- end
429
-
430
- return :union if unnested_characters.include? Union
431
- return :star if p.size == 2 and p.last == Star and !Specials.include? p[0]
432
- return :star if unnested_characters == [LeftBracket, RightBracket, Star]
433
- return :surr_brackets if unnested_characters == [LeftBracket, RightBracket]
434
- :cat
435
- end
436
-
437
- def transform_pattern_to_unique_identifiers
438
- pat = @pattern.scan(/./)
439
- iso = []
440
- for i in (0...pat.size)
441
- next if Specials.include? pat[i]
442
- iso << pat[i]
443
- pat[i] = iso.size - 1
444
- end
445
-
446
- [pat, iso]
447
- end
448
-
449
- def preparse
450
- substitute_empty_brackets
451
- simplify_brackets_around_singeltons
452
- simplify_lambdastar_to_lambda
453
- simplify_implicit_empty_set_unions
454
- squeeze_repeated_specials
455
- end
456
-
457
- def squeeze_repeated_specials
458
- @pattern.squeeze! Star
459
- @pattern.squeeze! Union
460
- @pattern.squeeze! Lambda
461
- end
462
-
463
- def simplify_implicit_empty_set_unions
464
- @pattern.gsub!(LeftBracket + Union, LeftBracket)
465
- @pattern.gsub!(LeftBracket + Star + Union, LeftBracket)
466
- @pattern.gsub!(Union + Star + Union, Union)
467
- end
468
-
469
- def simplify_lambdastar_to_lambda
470
- str = Lambda + Star
471
- @pattern.gsub!(str, Lambda) while @pattern.include? str
472
- end
473
-
474
- def substitute_empty_brackets
475
- @pattern.gsub! LeftBracket + RightBracket, Lambda
476
- end
477
-
478
- def simplify_brackets_around_singeltons
479
- re = Regexp.new("\\#{LeftBracket}(.)\\#{RightBracket}")
480
- @pattern.gsub!(re, '\1') while @pattern =~ re
481
- end
482
-
483
- def validate_form
484
- if @pattern =~ Regexp.new("\\#{LeftBracket}\\#{Star}[^#{Specials.join}]")
485
- raise REException, "Not wellformed. Detected '#{Regexp.last_match(0)}'"
486
- end
487
- end
488
-
489
- def validate_brackets_balanced
490
- unless 0 == @pattern.scan(/./).inject(0) do |res,x|
491
- res += count(x)
492
- break if res < 0
493
- res
494
- end
495
- raise REException, "Unbalanced parentheses in pattern!"
496
- end
497
- end
498
-
499
- def count(x)
500
- return 1 if x == LeftBracket
501
- return -1 if x == RightBracket
502
- 0
503
- end
504
- end