rlsm 0.4.0 → 1.0.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.
@@ -3,8 +3,16 @@ Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
5
  bin/smon
6
- lib/data/monoids.db
7
- lib/dfa.rb
8
- lib/monoid.rb
9
- lib/re.rb
6
+ data/monoids.db
7
+ lib/database.rb
8
+ lib/monkey_patching/array_ext.rb
10
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 CHANGED
@@ -1,2 +1,39 @@
1
- #! /usr/bin/env ruby
2
- puts "Comming soon"
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
File without changes
@@ -0,0 +1,95 @@
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
@@ -0,0 +1,50 @@
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,7 +1,9 @@
1
1
  $:.unshift File.expand_path(File.dirname(__FILE__))
2
2
 
3
+ require 'monkey_patching/array_ext'
4
+
3
5
  module RLSM
4
- VERSION = '0.4.0'
6
+ VERSION = '1.0.0'
5
7
  end
6
8
 
7
9
  #Setting up the exception classes.
@@ -10,51 +12,6 @@ class MonoidException < RLSMException; end
10
12
  class DFAException < RLSMException; end
11
13
  class REException < RLSMException; end
12
14
 
13
- #--
14
- #Monkey patching the Array class
15
- class Array # :nodoc:
16
- #Returns all permutations of the array.
17
- def permutations
18
- return [self] if size < 2
19
- perm = []
20
- each { |e| (self - [e]).permutations.each { |p| perm << ([e] + p) } }
21
- perm
22
- end
23
-
24
- #Returns the powerset of the array (interpreted as set).
25
- def powerset
26
- ret = self.inject([[]]) do |acc, x|
27
- res = []
28
- acc.each { |s| res << s; res << ([x]+s).sort }
29
- res
30
- end
31
-
32
- ret.sort_lex
33
- end
34
-
35
- #Sorts an array of arrays more or less lexicographical.
36
- def sort_lex
37
- sort { |s1, s2| s1.size == s2.size ? s1 <=> s2 : s1.size <=> s2.size }
38
- end
39
-
40
- #Returns the cartesian product of self and the given arrays
41
- def product(*args)
42
- args.inject(self.map { |x| [x] }) do |res,arr|
43
- new = []
44
- arr.each do |x|
45
- new += res.map { |tup| tup += [x] }
46
- end
47
- new
48
- end
49
- end
50
-
51
- #Returns all unordered pairs.
52
- def unordered_pairs
53
- pairs = []
54
- (0...size-1).each do |i|
55
- pairs |= self[i+1..-1].map { |x| [self[i],x] }
56
- end
57
-
58
- pairs
59
- end
60
- end
15
+ require 'rlsm/monoid'
16
+ require 'rlsm/dfa'
17
+ require 'rlsm/re'
@@ -1,6 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'rlsm'))
2
- require 'monoid'
3
- require "re"
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rlsm'))
4
2
 
5
3
  =begin rdoc
6
4
  ==Basic theory of deterministic finite automaton (short DFA)
@@ -160,6 +158,16 @@ It is required that all occuring states are in the states array and all transiti
160
158
 
161
159
  attr_reader :alphabet, :states, :initial_state, :finals
162
160
 
161
+ #Returns an Array with 3-tuples as transitions.
162
+ def transitions
163
+ res = []
164
+ @alphabet.each do |letter|
165
+ res |= @transitions[letter].to_a.map { |x| [letter] + x }
166
+ end
167
+
168
+ res
169
+ end
170
+
163
171
  #Returns the number of states.
164
172
  def num_states
165
173
  @states.size
@@ -338,7 +346,7 @@ Minimizes the DFA. Takes as optional parameter a hash with only processed key :+
338
346
 
339
347
  #Returns the transition monoid of the DFA.
340
348
  def transition_monoid
341
- RLSM::Monoid.new get_binary_operation, :rename_elements => true
349
+ RLSM::Monoid.new get_binary_operation, :rename => true
342
350
  end
343
351
 
344
352
  #Returns the transition monoid of the equivalent minimal DFA.
@@ -346,6 +354,16 @@ Minimizes the DFA. Takes as optional parameter a hash with only processed key :+
346
354
  minimize.transition_monoid
347
355
  end
348
356
 
357
+ #Synonym for syntactic_monoid
358
+ def to_monoid
359
+ syntactic_monoid
360
+ end
361
+
362
+ #Returns self.
363
+ def to_dfa
364
+ self
365
+ end
366
+
349
367
  #Returns a RE which represents the same language.
350
368
  def to_re
351
369
  les = []
@@ -360,6 +378,49 @@ Minimizes the DFA. Takes as optional parameter a hash with only processed key :+
360
378
  simplify_les_row(les.pop)[:final]
361
379
  end
362
380
 
381
+ def inspect
382
+ "<#{self.class}: #{@states.join(',')}>"
383
+ end
384
+
385
+ def to_s
386
+ output = []
387
+ output << @states.inject(['']) do |res, state|
388
+ prefix = ''
389
+ prefix += '*' if @finals.include? state
390
+ prefix += '->' if initial_state == state
391
+
392
+ res + [prefix + ' ' + state + ' ']
393
+ end
394
+
395
+ @alphabet.each do |letter|
396
+ column = [' ' + letter + ' ']
397
+ @states.each do |state|
398
+ tmp = self[letter,state]
399
+ if tmp.nil?
400
+ column << ' nil '
401
+ else
402
+ column << ' ' + tmp + ' '
403
+ end
404
+ end
405
+
406
+ output << column.clone
407
+ end
408
+
409
+ #Align output
410
+ output.map! do |col|
411
+ max_length = col.map { |x| x.length }.max
412
+ col.map { |x| ' '*(max_length - x.length) + x }
413
+ end
414
+
415
+ rows = (0..@states.size).map { |i| output.map { |col| col[i] } }
416
+ rows.map! { |row| row.join('|') }
417
+ head = rows.shift
418
+ rows.unshift head.scan(/./).map { |c| c == '|' ? '+' : '-' }.join
419
+ rows.unshift head
420
+
421
+ rows.join("\n")
422
+ end
423
+
363
424
  private
364
425
  def initialize_row_for(state)
365
426
  row = { :state => state.clone }
@@ -1,5 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'rlsm'))
2
- require 'dfa'
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rlsm'))
3
2
 
4
3
  =begin rdoc
5
4
  =The RLSM::Monoid class
@@ -548,7 +547,7 @@ Returns true if the monoid is aperiodic. (A synonym for h_trivial?)
548
547
  end
549
548
 
550
549
  def inspect # :nodoc:
551
- "<#{self.class} : {#{@elements.join(',')}}; #{to_s}>"
550
+ "<#{self.class}: #{to_s}>"
552
551
  end
553
552
 
554
553
  =begin rdoc
@@ -638,9 +637,22 @@ Also if the monoid is syntactic the set returned by disjunctive subset will be u
638
637
  end
639
638
  end
640
639
 
641
- RLSM::DFA.create(:initial => neutral_element,
642
- :finals => finals,
643
- :transitions => get_transitions)
640
+ dfa = RLSM::DFA.create(:initial => neutral_element,
641
+ :finals => finals,
642
+ :transitions => get_transitions)
643
+ dfa.rename_states
644
+
645
+ dfa
646
+ end
647
+
648
+ #Returns itself.
649
+ def to_monoid
650
+ self
651
+ end
652
+
653
+ #Returns the regexp for the language.
654
+ def to_re
655
+ to_dfa.to_re
644
656
  end
645
657
 
646
658
  private
@@ -1,6 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'rlsm'))
2
- require 'dfa'
3
-
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'rlsm'))
4
2
  require 'enumerator'
5
3
 
6
4
  class RLSM::RE
@@ -11,6 +9,10 @@ class RLSM::RE
11
9
  Lambda = '&'
12
10
  Specials = [LeftBracket, RightBracket, Star, Union, Lambda]
13
11
 
12
+ def to_s
13
+ @pattern
14
+ end
15
+
14
16
  def inspect
15
17
  "<#{self.class}: #@pattern>"
16
18
  end
@@ -86,6 +88,16 @@ class RLSM::RE
86
88
  end
87
89
  end
88
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
+
89
101
  #Returns true if the res are equal
90
102
  def ==(other)
91
103
  return true if @pattern == other.pattern
@@ -158,7 +170,7 @@ class RLSM::RE
158
170
 
159
171
  def recursive_split(child, type)
160
172
  if type_of(child) == type
161
- return self.send "split_#{type}".to_sym, child
173
+ return self.send("split_#{type}".to_sym, child)
162
174
  else
163
175
  return [child]
164
176
  end