rlsm 1.1.0 → 1.8.1

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.
@@ -0,0 +1,373 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'rlsm')
2
+ require 'enumerator'
3
+ require 'tempfile'
4
+
5
+ class Presenter
6
+ @@template = <<TEMPLATE
7
+ \\begin{minipage}{\\linewidth}
8
+ %%heading%%
9
+
10
+ \\begin{tabular}[t]{l}
11
+ %%table2tex%%
12
+ \\end{tabular}\\\\[2ex]
13
+
14
+ \\begin{tabular}{llcll}
15
+ \\multicolumn{2}{l}{\\textbf{%l%props%%:}} & & \\multicolumn{2}{l}{\\textbf{%l%special%%:}} \\\\
16
+ %l%generator%%: & %%generating_subset%% & & %l%idem_els%%: & %%idempotents%% \\\\
17
+ %l%group%%: & %%group?%% & & %%zero1%% \\\\
18
+ %l%comm%%: & %%commutative?%% & & %%zero2%% \\\\
19
+ %l%idem%%: & %%idempotent?%% & & & \\\\
20
+ %l%syn%%: & %%syntactic?%% & & \\multicolumn{2}{l}{\\textbf{%l%green%%:}} \\\\
21
+ %l%aper%%: & %%aperiodic?%% & & %l%lclasses%%: & %%l_classes%% \\\\
22
+ %l%ltriv%%: & %%l_trivial?%% & & %l%rclasses%%: & %%r_classes%% \\\\
23
+ %l%rtriv%%: & %%r_trivial?%% & & %l%hclasses%%: & %%h_classes%% \\\\
24
+ %l%jtriv%%: & %%j_trivial?%% & & %l%dclasses%%: & %%d_classes%% \\\\
25
+ %l%has_zero%%: & %%zero?%% & & & \\\\
26
+ \\end{tabular}\\\\[1ex]
27
+
28
+ \\textbf{%l%submons%%:} %%submonoids%%
29
+
30
+ %%syntactic_properties%%
31
+ \\end{minipage}
32
+ TEMPLATE
33
+
34
+ @@lang = {
35
+ :en => Hash['table', 'Binary Operation',
36
+ 'dfa', 'DFA',
37
+ 'props', 'Properties of the monoid',
38
+ 'special','Special elements',
39
+ 'generator', 'Generator',
40
+ 'group', 'Group',
41
+ 'comm', 'Commutative',
42
+ 'idem', 'Idempotent',
43
+ 'syn', 'Syntactic',
44
+ 'aper', 'Aperiodic',
45
+ 'ltriv', 'L-trivial',
46
+ 'rtriv', 'R-trivial',
47
+ 'jtriv', 'J-trivial',
48
+ 'has_zero', 'Has zero element',
49
+ 'idem_els', 'Idempotents',
50
+ 'zero', 'Zero element',
51
+ 'lzero', 'Left zeros',
52
+ 'rzero', 'Right zeros',
53
+ 'green', 'Green Relations',
54
+ 'lclasses', 'L-classes',
55
+ 'rclasses', 'R-classes',
56
+ 'hclasses', 'H-classes',
57
+ 'dclasses', 'D-classes',
58
+ 'submons', 'Proper submonoids',
59
+ 'none', 'none',
60
+ 'synprop','Syntactic Properties',
61
+ 'disj', 'Disjunctive Subset',
62
+ 'reg', 'Regular Expression',
63
+ true, 'yes',
64
+ false, 'no'],
65
+ :de => Hash['table', 'Binaere Operation',
66
+ 'dfa', 'DFA',
67
+ 'props', 'Eigenschaften des Monoids',
68
+ 'special','Spezielle Elemente',
69
+ 'generator', 'Erzeuger',
70
+ 'group', 'Gruppe',
71
+ 'comm', 'Kommutativ',
72
+ 'idem', 'Idempotent',
73
+ 'syn', 'Syntaktisch',
74
+ 'aper', 'Aperiodisch',
75
+ 'ltriv', 'L-trivial',
76
+ 'rtriv', 'R-trivial',
77
+ 'jtriv', 'J-trivial',
78
+ 'has_zero', 'mit Nullelement',
79
+ 'idem_els', 'Idempotente Elemente',
80
+ 'zero', 'Nullelement',
81
+ 'lzero', 'Linksnullelemente',
82
+ 'rzero', 'Rechtsnullelemente',
83
+ 'green', 'Greensche Relationen',
84
+ 'lclasses', 'L-Klassen',
85
+ 'rclasses', 'R-Klassen',
86
+ 'hclasses', 'H-Klassen',
87
+ 'dclasses', 'D-Klassen',
88
+ 'submons', 'Echte Untermonoide',
89
+ 'none', 'keine',
90
+ 'synprop','Syntaktische Eigenschaften',
91
+ 'disj', 'Disjunktive Teilmenge',
92
+ 'reg', 'Regulaerer Ausdruck',
93
+ true, 'ja',
94
+ false, 'nein']
95
+ }
96
+
97
+
98
+
99
+ def self.to_latex(monoid, options = {})
100
+ options[:lang] ||= :en
101
+ presenter = Presenter.new(options[:monoid], options[:lang])
102
+ output = @@template.dup
103
+ @@lang[options[:lang]].each_pair do |key, text|
104
+ output.sub!("%l%#{key}%%", text)
105
+ end
106
+
107
+ while output =~ /%%(\w+\??)%%/
108
+ output.sub!($~[0], presenter.send($~[1].to_sym))
109
+ end
110
+
111
+ output
112
+ end
113
+
114
+ #Use with caution, many assumptions about the row parameter...
115
+ def self.db_row_to_latex(row, options = {})
116
+ options[:lang] ||= :en
117
+
118
+ monoid = RLSM::Monoid[row.first]
119
+
120
+ presenter = Presenter.new(monoid, options[:lang])
121
+ output = @@template.dup
122
+ @@lang[options[:lang]].each_pair do |key, text|
123
+ output.sub!("%l%#{key}%%", text)
124
+ end
125
+
126
+ #Use precalculated values
127
+ ['zero?', 'syntactic?', 'commutative?', 'idempotent?','aperiodic?', 'l_trivial?',
128
+ 'r_trivial?', 'j_trivial?', 'group?'].each_with_index do |entry,i|
129
+ output.sub!("%%#{entry}%%", @@lang[options[:lang]][row[i+6] == '1'])
130
+ end
131
+
132
+ while output =~ /%%(\w+\??)%%/
133
+ output.sub!($~[0], presenter.send($~[1].to_sym))
134
+ end
135
+
136
+ output
137
+ end
138
+
139
+ def initialize(monoid,lang)
140
+ @monoid = monoid
141
+ @lang = @@lang[lang]
142
+ end
143
+
144
+ def table2tex
145
+ helper_table2tex(@monoid)
146
+ end
147
+
148
+ def heading
149
+ "\\paragraph{Monoid #{@monoid.to_s}:}\\mbox{ }\\\\"
150
+ end
151
+
152
+ def dfa2tex(opts = { :dot => true })
153
+ dfa = @monoid.to_dfa
154
+ if opts[:dot] and not %x(which dot).empty?
155
+ filename = tmp_filename
156
+ dfa2pic dfa, :filename => filename, :format => 'plain'
157
+
158
+ str = "\\begin{xy}\n0;<1.27cm,0cm>:\n"
159
+
160
+ edges = []
161
+ File.open(filename + ".plain", 'r').each_line do |line|
162
+ values = line.split
163
+ if ['edge','node'].include? values.first
164
+ str += tex_xy_node(values)
165
+ end
166
+ edges << tex_xy_edge(values) if values.first == 'edge'
167
+ end
168
+
169
+ str += edges.join("\n")
170
+
171
+ File.delete(filename + ".plain")
172
+
173
+ return str + "\n\\end{xy}\n"
174
+ else
175
+ str = "\\begin{tabular}{r|" +
176
+ (['c']*dfa.alphabet.size).join('|') + "}\n"
177
+ str += " & " + dfa.alphabet.map do |l|
178
+ "\\textbf{#{l}}"
179
+ end.join(' & ') + " \\\\ \\hline\n"
180
+ dfa.states.each do |state|
181
+ tmp_str = ''
182
+ tmp_str += "\\ensuremath{*}" if dfa.final_states.include? state
183
+ tmp_str += "\\ensuremath{\\rightarrow}" if dfa.initial_state == state
184
+ tmp_str += state + " & "
185
+ tmp_str += dfa.alphabet.map do |letter|
186
+ tmp = dfa[state,letter]
187
+ tmp ? tmp : 'nil'
188
+ end.join(' & ')
189
+ str+= tmp_str + " \\\\\n"
190
+ end
191
+
192
+ return str + "\\end{tabular}\n"
193
+ end
194
+ end
195
+
196
+ def submonoids
197
+ submons = @monoid.proper_submonoids.map { |sm| helper_table2tex(sm) }
198
+
199
+ if submons.empty?
200
+ @lang['none'] + "\\\\\\\\[2ex]"
201
+ else
202
+ submons.join("\\quad") + "\\\\\\\\[2ex]"
203
+ end
204
+ end
205
+
206
+ def zero1
207
+ if @monoid.zero?
208
+ "#{@lang['zero']}: & #{@monoid.zero} \\\\"
209
+ else
210
+ unless @monoid.left_zeros.empty?
211
+ "#{@lang['lzero']}: & #{@monoid.left_zeros.join(', ')} \\\\"
212
+ else
213
+ " & \\\\"
214
+ end
215
+ end
216
+ end
217
+
218
+ def zero2
219
+ if @monoid.zero?
220
+ " & \\\\"
221
+ else
222
+ unless @monoid.right_zeros.empty?
223
+ "#{@lang['rzero']}: & #{@monoid.right_zeros.join(', ')} \\\\"
224
+ else
225
+ " & \\\\"
226
+ end
227
+ end
228
+ end
229
+
230
+ def syntactic_properties
231
+ if @monoid.syntactic?
232
+ table_text = ""
233
+ @monoid.all_disjunctive_subsets.each do |set|
234
+ table_text += set2tex(set) + "& " + reg2tex(@monoid.to_dfa(set).to_regexp) + "\\\\\\\\"
235
+ end
236
+
237
+ output = <<TEXT
238
+ \\textbf{#{@lang['synprop']}:}
239
+ \\begin{center}
240
+ \\begin{tabular}{cl}
241
+ \\textbf{#{@lang['disj']}} & \\textbf{#{@lang['reg']}} \\\\\\\\ \\hline
242
+ #{table_text}
243
+ \\end{tabular}
244
+ \\end{center}
245
+ TEXT
246
+ else
247
+ ""
248
+ end
249
+ end
250
+
251
+ def method_missing(name, *args)
252
+ if name.to_s =~ /\?/
253
+ @lang[@monoid.send(name)]
254
+ else
255
+ set2tex @monoid.send(name)
256
+ end
257
+ end
258
+
259
+ private
260
+ def set2tex(set)
261
+ if Array === set.first
262
+ set.map! { |s| set2tex(s) }.join(', ')
263
+ else
264
+ "\\{" + set.join(', ') + "\\}"
265
+ end
266
+ end
267
+
268
+ def helper_table2tex(monoid)
269
+ table = []
270
+ monoid.table.each_with_index do |x, i|
271
+ table << [] if i % monoid.order == 0
272
+ table.last << monoid.elements[x]
273
+ end
274
+
275
+ buffer = ['\begin{tabular}[t]{' +
276
+ (['c']*(monoid.order+1)).join('|') + '|}']
277
+
278
+ buffer << ' & ' + table[0].map do |el|
279
+ "\\textbf{#{el}}"
280
+ end.join(' & ') + "\\\\\\\\ \\hline"
281
+
282
+ table.each do |row|
283
+ buffer << "\\textbf{#{row[0]}} & " + row.join(' & ') + "\\\\\\\\ \\hline"
284
+ end
285
+
286
+ buffer << ['\end{tabular}']
287
+ buffer.join("\n")
288
+ end
289
+
290
+ def reg2tex(re)
291
+ if re.string.empty?
292
+ "\\ensuremath{\\emptyset}"
293
+ else
294
+ re_str = re.string.
295
+ gsub(RLSM::RE::ParserHelpers::EmptyWordSymbol, "\\lambda ").
296
+ gsub(RLSM::RE::ParserHelpers::UnionSymbol, "\\mid ").
297
+ gsub(RLSM::RE::ParserHelpers::StarSymbol, "^{*}")
298
+
299
+ "\\ensuremath{#{re_str}}"
300
+ end
301
+ end
302
+
303
+ def tex_xy_node(n)
304
+ if n.first == 'edge'
305
+ return "" if n[1] == 'preinit'
306
+
307
+ num_points = n[3].to_i
308
+ lable_pos = n[2*num_points + 5,2].join(',')
309
+ label = n[2*num_points + 4].gsub("\"",'')
310
+
311
+ return ";(#{lable_pos})*[r]\\txt{#{label}}\n"
312
+ else
313
+ id = n[1]
314
+ xypos = n[2,2].join(',')
315
+ return "(#{xypos})*{}=\"#{id}\"\n" if n[1] == 'preinit'
316
+
317
+ label = n[6]
318
+ type = n[8] == 'circle' ? '' : '='
319
+
320
+ return ";(#{xypos})*+=[o]++[F#{type}]{#{label}}=\"#{id}\"\n"
321
+ end
322
+ end
323
+
324
+ def tex_xy_edge(e)
325
+ from, to = e[1,2]
326
+ num_points = e[3].to_i
327
+ points = points_to_str(e[4,2*num_points])
328
+
329
+ "\\ar @`{#{points}} \"#{from}\";\"#{to}\""
330
+ end
331
+
332
+ def points_to_str(a)
333
+ "(" + a.enum_slice(2).to_a.map { |x| x.join(',') }.join('),(') + ")"
334
+ end
335
+
336
+ def tmp_filename
337
+ File.join(Dir.tmpdir, "m#{@monoid.to_s.gsub(/\s*,?/, '_')}")
338
+ end
339
+
340
+ def dfa2pic(dfa, options = {:format => 'png'})
341
+ filename = options[:filename] || tmp_filename
342
+ File.open(filename + ".dot", "w") { |f| f.puts dfa2dot(dfa) }
343
+ system "dot -T#{options[:format]} -o #{filename}.#{options[:format]} #{filename}.dot"
344
+ File.delete(filename + ".dot")
345
+ end
346
+
347
+ #Creates string which is a dot representation of a DFA.
348
+ def dfa2dot(dfa)
349
+ str = "digraph {\n"
350
+ str += "size=\"2,2\"\nratio=1.0\n"
351
+ str += "node [shape=circle]\n"
352
+ str += "preinit [shape=plaintext, label=\"\"]\n"
353
+ (dfa.states - dfa.final_states).each do |state|
354
+ str += state + "\n"
355
+ end
356
+ str += "node [shape=doublecircle]\n"
357
+ dfa.final_states.each do |state|
358
+ str += state + "\n"
359
+ end
360
+ str += "preinit -> #{dfa.initial_state}\n"
361
+ dfa.states.each do |s1|
362
+ dfa.states.each do |s2|
363
+ res = dfa.transitions.find_all { |tr| tr[0] == s1 and tr[1] == s2 }
364
+ unless res.empty?
365
+ label = res.map { |tr| tr[2] }.join(',')
366
+ str += s1 + "->" + s2 + "[label=\"#{label}\"]\n"
367
+ end
368
+ end
369
+ end
370
+
371
+ str + "}"
372
+ end
373
+ end
@@ -0,0 +1,144 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'rlsm')
3
+ require File.join(File.dirname(__FILE__), 'presenting_monoids_in_tex')
4
+
5
+ require "rubygems"
6
+ require "sqlite3"
7
+
8
+ db = SQLite3::Database.new(File.join(File.dirname(__FILE__), '..',
9
+ 'data', 'monoids.db'))
10
+
11
+ query = <<QUERY
12
+ SELECT
13
+ ord AS ' Order',
14
+ count(*) AS ' Total',
15
+ total(is_inverse) AS ' Inverse',
16
+ total(is_syntactic) AS ' Syntactic',
17
+ total(is_group) AS ' Groups',
18
+ total(is_commutative) AS 'Commutative',
19
+ total(is_aperiodic) AS ' Aperiodic',
20
+ total(is_idempotent) AS ' Idempotent',
21
+ total(is_j_trivial) AS ' J-trivial',
22
+ total(is_r_trivial) AS ' R-trivial',
23
+ total(is_l_trivial) AS ' L-trivial',
24
+ total(has_zero) AS ' With zero'
25
+ FROM monoids
26
+ WHERE ord>=4 AND is_regular=1
27
+ GROUP BY ord
28
+ ORDER BY 'Order' ASC;
29
+ QUERY
30
+
31
+ result = db.execute2(query)
32
+
33
+ output = result.shift.map { |x| [x] }
34
+
35
+ result.each do |col|
36
+ col.each_with_index do |row,i|
37
+ (output[i] ||= []) << row.to_i
38
+ end
39
+ end
40
+
41
+ puts "Ubersicht regulaere Monoide:"
42
+ puts output.map { |row| row.join("\t") }.join("\n")
43
+ puts
44
+ puts
45
+
46
+
47
+ query = <<QUERY
48
+ SELECT
49
+ ord AS ' Order',
50
+ count(*) AS ' Total',
51
+ total(is_inverse) AS ' Inverse',
52
+ total(is_syntactic) AS ' Syntactic',
53
+ total(is_group) AS ' Groups',
54
+ total(is_commutative) AS 'Commutative',
55
+ total(is_aperiodic) AS ' Aperiodic',
56
+ total(is_idempotent) AS ' Idempotent',
57
+ total(is_j_trivial) AS ' J-trivial',
58
+ total(is_r_trivial) AS ' R-trivial',
59
+ total(is_l_trivial) AS ' L-trivial',
60
+ total(has_zero) AS ' With zero'
61
+ FROM monoids
62
+ WHERE ord>=4 AND is_regular=1 AND is_syntactic=1
63
+ GROUP BY ord
64
+ ORDER BY 'Order' ASC;
65
+ QUERY
66
+
67
+ result = db.execute2(query)
68
+
69
+ output = result.shift.map { |x| [x] }
70
+
71
+ result.each do |col|
72
+ col.each_with_index do |row,i|
73
+ (output[i] ||= []) << row.to_i
74
+ end
75
+ end
76
+
77
+ puts "Regulaere syntaktische Monoide:"
78
+ puts output.map { |row| row.join("\t") }.join("\n")
79
+ puts
80
+ puts
81
+
82
+ query = <<QUERY
83
+ SELECT
84
+ ord AS ' Order',
85
+ count(*) AS ' Total',
86
+ total(is_aperiodic) AS ' Aperiodic',
87
+ total(is_idempotent) AS ' Idempotent',
88
+ total(is_j_trivial) AS ' J-trivial',
89
+ total(is_r_trivial) AS ' R-trivial',
90
+ total(is_l_trivial) AS ' L-trivial',
91
+ total(has_zero) AS ' With zero'
92
+ FROM monoids
93
+ WHERE ord>=4 AND is_regular=1 AND is_syntactic=0
94
+ GROUP BY ord
95
+ ORDER BY 'Order' ASC;
96
+ QUERY
97
+
98
+ result = db.execute2(query)
99
+
100
+ output = result.shift.map { |x| [x] }
101
+
102
+ result.each do |col|
103
+ col.each_with_index do |row,i|
104
+ (output[i] ||= []) << row.to_i
105
+ end
106
+ end
107
+
108
+ puts "Regulaere nichtsyntaktische Monoide:"
109
+ puts output.map { |row| row.join("\t") }.join("\n")
110
+ puts
111
+ puts
112
+
113
+ query = <<QUERY
114
+ SELECT
115
+ ord AS ' Order',
116
+ count(*) AS ' Total',
117
+ total(is_inverse) AS ' Inverse',
118
+ total(is_syntactic) AS ' Syntactic',
119
+ total(is_group) AS ' Groups',
120
+ total(is_commutative) AS 'Commutative',
121
+ total(is_j_trivial) AS ' J-trivial',
122
+ total(is_r_trivial) AS ' R-trivial',
123
+ total(is_l_trivial) AS ' L-trivial',
124
+ total(has_zero) AS ' With zero'
125
+ FROM monoids
126
+ WHERE ord>=4 AND is_regular=1 AND is_aperiodic=1 AND is_idempotent=1
127
+ GROUP BY ord
128
+ ORDER BY 'Order' ASC;
129
+ QUERY
130
+
131
+ result = db.execute2(query)
132
+
133
+ output = result.shift.map { |x| [x] }
134
+
135
+ result.each do |col|
136
+ col.each_with_index do |row,i|
137
+ (output[i] ||= []) << row.to_i
138
+ end
139
+ end
140
+
141
+ puts "Regulaere aperiodische und idempotente Monoide:"
142
+ puts output.map { |row| row.join("\t") }.join("\n")
143
+ puts
144
+ puts