rlsm 1.1.0 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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