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.
- data/{README.txt → README} +10 -23
- data/Rakefile +79 -7
- data/ext/array/array_c_ext.c +137 -0
- data/ext/array/extconf.rb +2 -0
- data/ext/binop/binop_c_ext.c +57 -0
- data/ext/binop/extconf.rb +2 -0
- data/ext/monoid/extconf.rb +2 -0
- data/ext/monoid/monoid_c_ext.c +330 -0
- data/lib/rlsm.rb +10 -14
- data/lib/rlsm/binary_operation.rb +151 -0
- data/lib/rlsm/dfa.rb +418 -602
- data/lib/rlsm/helper.rb +12 -0
- data/lib/rlsm/monoid.rb +454 -694
- data/lib/rlsm/regexp.rb +125 -0
- data/lib/rlsm/regexp_parser.rb +450 -0
- data/test/helpers.rb +66 -0
- data/test/test_binop.rb +119 -0
- data/test/test_dfa.rb +435 -0
- data/test/test_monoid.rb +552 -0
- data/test/test_regexp.rb +440 -0
- metadata +109 -37
- data/History.txt +0 -6
- data/Manifest.txt +0 -18
- data/bin/smon +0 -39
- data/data/monoids.db +0 -0
- data/lib/database.rb +0 -95
- data/lib/monkey_patching/array_ext.rb +0 -50
- data/lib/rlsm/re.rb +0 -504
- data/lib/smon/base.rb +0 -284
- data/lib/smon/db.rb +0 -98
- data/lib/smon/dot.rb +0 -65
- data/lib/smon/latex.rb +0 -313
- data/lib/smon/smon.rb +0 -183
- data/stdarb.tex +0 -118
data/lib/rlsm/helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class RLSMError < StandardError; end # :nodoc:
|
2
|
+
class ParseError < RLSMError; end # :nodoc:
|
3
|
+
class BinOpError < RLSMError; end # :nodoc:
|
4
|
+
class MonoidError < RLSMError; end # :nodoc:
|
5
|
+
class DFAError < RLSMError; end # :nodoc:
|
6
|
+
class RegExpError < RLSMError; end # :nodoc:
|
7
|
+
|
8
|
+
module RLSM
|
9
|
+
def self.require_extension(extension)
|
10
|
+
require File.join(File.dirname(__FILE__), '..', '..', 'ext', extension, extension + '_cext')
|
11
|
+
end
|
12
|
+
end
|
data/lib/rlsm/monoid.rb
CHANGED
@@ -1,790 +1,550 @@
|
|
1
|
-
require File.
|
1
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
2
|
+
require File.join(File.dirname(__FILE__), 'binary_operation')
|
3
|
+
require File.join(File.dirname(__FILE__), 'dfa')
|
4
|
+
RLSM::require_extension 'array'
|
5
|
+
RLSM::require_extension 'monoid'
|
6
|
+
|
7
|
+
module RLSM
|
8
|
+
class Monoid
|
9
|
+
private_class_method :new
|
10
|
+
|
11
|
+
def self.each(order)
|
12
|
+
raise ArgumentError, "Given order must be > 0" if order <= 0
|
13
|
+
|
14
|
+
if order == 1 #trivial case
|
15
|
+
yield new(RLSM::BinaryOperation.original_new([0], ['0'], { '0' => 0}))
|
16
|
+
return
|
17
|
+
end
|
2
18
|
|
3
|
-
=
|
4
|
-
=
|
5
|
-
|
6
|
-
A _monoid_ is a tuple <tt>(M,B)</tt> where
|
7
|
-
* +M+ is a set of _elements_
|
8
|
-
* <tt>B:M x M -> M</tt> is a _binary_ _operation_
|
9
|
-
with the following properties
|
10
|
-
* the binary operation is associative ( <tt>B(a,B(b,c)) = B(B(a,b),c)</tt> for all <tt>a,b,c</tt> in +M+)
|
11
|
-
* It exists an element +e+ in +M+ with <tt>B(a,e) = B(e,a) = a</tt> for all +a+ in +M+ (the neutral element).
|
19
|
+
elements = (0...order).to_a.map { |x| x.to_s }
|
20
|
+
mapping = {}
|
21
|
+
elements.each_with_index { |x,i| mapping[x] = i }
|
12
22
|
|
13
|
-
|
23
|
+
#calculate the permutations once
|
24
|
+
permutations = (1...order).to_a.permutations.map { |p| p.unshift 0 }
|
14
25
|
|
15
|
-
|
26
|
+
each_diagonal(order,permutations) do |diagonal|
|
27
|
+
each_with_diagonal(diagonal,permutations) do |table|
|
28
|
+
yield new(RLSM::BinaryOperation.original_new(table, elements, mapping))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
16
32
|
|
17
|
-
|
33
|
+
|
34
|
+
attr_accessor :elements, :order, :binary_operation
|
18
35
|
|
36
|
+
#Like new, but without validation.
|
37
|
+
def self.new!(description)
|
38
|
+
new RLSM::BinaryOperation.new!(description)
|
39
|
+
end
|
19
40
|
|
20
|
-
|
21
|
-
|
41
|
+
#Creates a Monoid with the binary operation described in +description+.
|
42
|
+
#Validates that the BinaryOperation is assoviative and the neutral element
|
43
|
+
#is in the first row.
|
44
|
+
#
|
45
|
+
#See also BinaryOperation::new.
|
46
|
+
def self.[](description)
|
47
|
+
binop = RLSM::BinaryOperation.new(description)
|
48
|
+
binop.enforce_associativity
|
49
|
+
enforce_identity_position(binop.table, binop.order)
|
50
|
+
|
51
|
+
new(binop)
|
52
|
+
end
|
22
53
|
|
23
|
-
| e | a | b | <-- this row gives only a correspondence between
|
24
|
-
---+---+---+---+ columns and monoid elements (analog the first column,
|
25
|
-
e | e | a | b | which gives a correspondence between rows and elements).
|
26
|
-
---+---+---+---+
|
27
|
-
a | a | a | b |
|
28
|
-
---+---+---+---+
|
29
|
-
b | b | a | b |
|
30
|
-
---+---+---+---+
|
31
54
|
|
32
|
-
|
55
|
+
#:notnew:
|
56
|
+
#*Remark*: No validation is performed. Use it only when you're really know what to do.
|
57
|
+
#Use Monoid::[] instead (or Monoid::new!).
|
58
|
+
def initialize(binop)
|
59
|
+
@binary_operation = binop
|
60
|
+
@elements = @binary_operation.elements
|
61
|
+
@order = @elements.size
|
33
62
|
|
34
|
-
|
35
|
-
|
36
|
-
* Each entry must be a monoid element
|
63
|
+
instance_eval(&block) if block_given?
|
64
|
+
end
|
37
65
|
|
38
|
-
|
66
|
+
#Calculates the product of the given elements.
|
67
|
+
def [](*args)
|
68
|
+
case args.size
|
69
|
+
when 0,1
|
70
|
+
raise ArgumentError, "At least two elements must be provided."
|
71
|
+
when 2
|
72
|
+
@binary_operation[*args]
|
73
|
+
else
|
74
|
+
args[0,2] = @binary_operation[args[0],args[1]]
|
75
|
+
self[*args]
|
76
|
+
end
|
77
|
+
end
|
39
78
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
holds for all <tt>x,y</tt> in +M+. The map +I+ is then called an _isomorphism_.
|
79
|
+
#Two monoids are equal if they have the same binary operation on the same set.
|
80
|
+
def ==(other)
|
81
|
+
return nil unless RLSM::Monoid === other
|
44
82
|
|
45
|
-
|
46
|
-
|
47
|
-
|
83
|
+
@binary_operation.table == other.binary_operation.table and
|
84
|
+
@binary_operation.elements == other.binary_operation.elements
|
85
|
+
end
|
48
86
|
|
49
|
-
|
50
|
-
|
51
|
-
|
87
|
+
#Checks if +self+ is a proper submonoid of +other+.
|
88
|
+
def <(other)
|
89
|
+
return nil unless RLSM::Monoid === other
|
90
|
+
return false if @order >= other.order
|
91
|
+
|
92
|
+
@elements.each do |e1|
|
93
|
+
@elements.each do |e2|
|
94
|
+
begin
|
95
|
+
return false if self[e1,e2] != other[e1,e2]
|
96
|
+
rescue BinOpError
|
97
|
+
return false
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
52
101
|
|
53
|
-
|
54
|
-
|
55
|
-
holds. An element +r+ of +M+ is called a _right_-_zero_ iff for all +x+ in +M+
|
56
|
-
xr = r
|
57
|
-
holds. An element +z+ of +M+ is called a _zero_ _element_ iff for all +x+ in +M+
|
58
|
-
zx = xz = z
|
59
|
-
holds. If it exists, the zero element is unique.
|
102
|
+
true
|
103
|
+
end
|
60
104
|
|
61
|
-
|
105
|
+
#Checks if +self+ is a submonoid of (or equal to) +other+.
|
106
|
+
def <=(other)
|
107
|
+
(self == other) || (self < other)
|
108
|
+
end
|
62
109
|
|
63
|
-
|
110
|
+
def >(other) #:nodoc:
|
111
|
+
other < self
|
112
|
+
end
|
64
113
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
holds for all <tt>x,y</tt> in +M+ and +M+ is a subset of +N+.
|
114
|
+
def >=(other) #:nodoc:
|
115
|
+
other <= self
|
116
|
+
end
|
69
117
|
|
70
|
-
|
118
|
+
#Returns the submonoid generated by +set+.
|
119
|
+
#
|
120
|
+
#*Remark*: The returned value is only an Array, no Monoid. Use get_submonoid for this.
|
121
|
+
def generated_set(set)
|
122
|
+
if set.include? @elements.first
|
123
|
+
gen_set = set.map { |element| element.to_s }
|
124
|
+
else
|
125
|
+
gen_set = set.map { |element| element.to_s } | @elements[0,1]
|
126
|
+
end
|
71
127
|
|
72
|
-
|
73
|
-
|
74
|
-
|
128
|
+
unfinished = true
|
129
|
+
|
130
|
+
while unfinished
|
131
|
+
unfinished = false
|
132
|
+
|
133
|
+
gen_set.each do |el1|
|
134
|
+
gen_set.each do |el2|
|
135
|
+
element = self[el1,el2]
|
136
|
+
unless gen_set.include? element
|
137
|
+
gen_set << element
|
138
|
+
unfinished = true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
gen_set.sort(&element_sorter)
|
145
|
+
end
|
75
146
|
|
76
|
-
|
147
|
+
#Returns the submonoid generated by set.
|
148
|
+
def get_submonoid(set)
|
149
|
+
elements = generated_set(set)
|
77
150
|
|
78
|
-
|
79
|
-
|
80
|
-
Ma := {xa | x in M}
|
81
|
-
aM := {ax | x in M}
|
82
|
-
MaM := {xay | x,y in M}
|
83
|
-
and call +Ma+ the _left_ _ideal_ of +a+, +aM+ the _right_ _ideal_ of +a+ and +MaM+ the (_two_-_sided_) _ideal_ of +a+.
|
151
|
+
set_to_monoid(elements)
|
152
|
+
end
|
84
153
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
a =D= b :<=> it exists a c in +M+ such that a =L= c and c =R= b
|
91
|
-
These relations are called the _Green_-_relations_ of the monoid +M+.
|
154
|
+
#Returns an array of all submonoids (including the trivial monoid and the monoid itself).
|
155
|
+
def submonoids
|
156
|
+
candidates = get_submonoid_candidates
|
157
|
+
candidates.map { |set| set_to_monoid(set) }
|
158
|
+
end
|
92
159
|
|
93
|
-
|
160
|
+
#Returns an array of all proper submonoids.
|
161
|
+
def proper_submonoids
|
162
|
+
candidates = get_submonoid_candidates.select do |cand|
|
163
|
+
cand.size > 1 and cand.size < @order
|
164
|
+
end
|
94
165
|
|
95
|
-
|
166
|
+
candidates.map { |set| set_to_monoid(set) }
|
167
|
+
end
|
168
|
+
|
169
|
+
#Returns the smallest set (first in terms of cardinality, then lexicographically) which generates the monoid.
|
170
|
+
def generating_subset
|
171
|
+
sorted_subsets.find { |set| generated_set(set).size == @order }
|
172
|
+
end
|
96
173
|
|
97
|
-
|
174
|
+
#Checks if +self+ is isomorph to +other+
|
175
|
+
def =~(other)
|
176
|
+
bijective_maps_to(other).any? { |map| isomorphism?(map,other) }
|
177
|
+
end
|
178
|
+
|
179
|
+
#Synonym for =~
|
180
|
+
def isomorph?(other)
|
181
|
+
self =~ other
|
182
|
+
end
|
98
183
|
|
99
|
-
|
100
|
-
|
101
|
-
|
184
|
+
#Checks if +self+ is antiisomorph to +other+.
|
185
|
+
def antiisomorph?(other)
|
186
|
+
bijective_maps_to(other).any? { |map| antiisomorphism?(map,other) }
|
187
|
+
end
|
102
188
|
|
103
|
-
|
189
|
+
#If an argument is given, checks if this element is idempotent. Otherwise checks if the monoid itself is idempotent.
|
190
|
+
def idempotent?(element = nil)
|
191
|
+
if element
|
192
|
+
self[element,element] == element
|
193
|
+
else
|
194
|
+
@elements.all? { |el| idempotent?(el) }
|
195
|
+
end
|
196
|
+
end
|
104
197
|
|
105
|
-
|
198
|
+
#Returns the order of an element.
|
199
|
+
def order_of(element)
|
200
|
+
generated_set([element]).size
|
201
|
+
end
|
106
202
|
|
107
|
-
|
108
|
-
|
203
|
+
#Returns the principal right ideal of the element.
|
204
|
+
def right_ideal(element)
|
205
|
+
@elements.map { |el| self[element,el] }.uniq.sort(&element_sorter)
|
206
|
+
end
|
109
207
|
|
110
|
-
|
111
|
-
|
112
|
-
|
208
|
+
#Returns the principal left ideal of the element.
|
209
|
+
def left_ideal(element)
|
210
|
+
@elements.map { |el| self[el,element] }.uniq.sort(&element_sorter)
|
211
|
+
end
|
113
212
|
|
114
|
-
|
115
|
-
|
213
|
+
#Returns the principal (twosided) ideal of the element.
|
214
|
+
def ideal(element)
|
215
|
+
result = []
|
216
|
+
@elements.each do |el1|
|
217
|
+
@elements.each do |el2|
|
218
|
+
result << self[el1,element,el2]
|
219
|
+
end
|
220
|
+
end
|
116
221
|
|
117
|
-
|
118
|
-
|
119
|
-
* Each entry is an element of the monoid
|
120
|
-
* The first row and column belongs to the neutral element
|
222
|
+
result.uniq.sort(&element_sorter)
|
223
|
+
end
|
121
224
|
|
122
|
-
|
225
|
+
#Returns the neutral element of the monoid.
|
226
|
+
def identity
|
227
|
+
@elements.first
|
228
|
+
end
|
123
229
|
|
124
|
-
|
230
|
+
#Checks if +element+ is the neutral element.
|
231
|
+
def identity?(element)
|
232
|
+
element == identity
|
233
|
+
end
|
125
234
|
|
126
|
-
|
127
|
-
|
128
|
-
|
235
|
+
#If a argument is given, checks if +element+ is the zero element. If no arguement is given, checks if a zero element exists.
|
236
|
+
def zero?(element = nil)
|
237
|
+
if element
|
238
|
+
return false if @order == 1
|
239
|
+
@elements.all? do |el|
|
240
|
+
self[el,element] == element and self[element,el] == element
|
241
|
+
end
|
242
|
+
else
|
243
|
+
!!zero
|
244
|
+
end
|
245
|
+
end
|
129
246
|
|
130
|
-
|
131
|
-
|
132
|
-
|
247
|
+
#Returns the zero element if it exists. Return +nil+ if no zero element exists.
|
248
|
+
def zero
|
249
|
+
@elements.find { |el| zero?(el) }
|
250
|
+
end
|
133
251
|
|
134
|
-
|
252
|
+
#Checks if +element+ is a left zero element.
|
253
|
+
def left_zero?(element)
|
254
|
+
return false if @order == 1
|
255
|
+
@elements.all? { |x| self[element,x] == element }
|
256
|
+
end
|
135
257
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
258
|
+
#Checks if +element+ is a right zero element.
|
259
|
+
def right_zero?(element)
|
260
|
+
return false if @order == 1
|
261
|
+
@elements.all? { |x| self[x,element] == element }
|
262
|
+
end
|
140
263
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
@binary_operation = get_binary_operation_from binary_operation
|
146
|
-
@elements = @binary_operation.first.uniq unless @binary_operation.empty?
|
147
|
-
@order = @binary_operation.size
|
264
|
+
#Returns an array with all right zero elements.
|
265
|
+
def right_zeros
|
266
|
+
@elements.select { |el| right_zero?(el) }
|
267
|
+
end
|
148
268
|
|
149
|
-
|
269
|
+
#Returns an array with all left zero elements.
|
270
|
+
def left_zeros
|
271
|
+
@elements.select { |el| left_zero?(el) }
|
272
|
+
end
|
150
273
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
274
|
+
#Returns an array with all idempotent elements.
|
275
|
+
def idempotents
|
276
|
+
@elements.select { |el| idempotent?(el) }
|
277
|
+
end
|
155
278
|
|
156
|
-
|
279
|
+
#Checks if the monoid is a group.
|
280
|
+
def group?
|
281
|
+
idempotents.size == 1
|
282
|
+
end
|
157
283
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
args.flatten!
|
163
|
-
check_args(args)
|
284
|
+
#Checks if the monoid is commutative.
|
285
|
+
def commutative?
|
286
|
+
@binary_operation.commutative?
|
287
|
+
end
|
164
288
|
|
165
|
-
if
|
166
|
-
|
167
|
-
|
168
|
-
else
|
169
|
-
args[0,2] = self[args[0,2]]
|
170
|
-
return self[*args]
|
289
|
+
#Checks if the monoid is monogenic, i.e it is generated by a single element.
|
290
|
+
def monogenic?
|
291
|
+
generating_subset.size == 1
|
171
292
|
end
|
172
|
-
end
|
173
293
|
|
174
|
-
|
175
|
-
|
176
|
-
=
|
177
|
-
|
178
|
-
|
179
|
-
return false if @order != other.order
|
294
|
+
#Calculates the L-class of an element.
|
295
|
+
def l_class(element)
|
296
|
+
li = left_ideal(element)
|
297
|
+
@elements.select { |el| left_ideal(el) == li }
|
298
|
+
end
|
180
299
|
|
181
|
-
#
|
182
|
-
|
183
|
-
|
184
|
-
|
300
|
+
#Calculates the R-class of an element.
|
301
|
+
def r_class(element)
|
302
|
+
r = right_ideal(element)
|
303
|
+
@elements.select { |el| right_ideal(el) == r }
|
304
|
+
end
|
185
305
|
|
186
|
-
|
187
|
-
|
306
|
+
#Calculates the J-class of an element.
|
307
|
+
def j_class(element)
|
308
|
+
d = ideal(element)
|
309
|
+
@elements.select { |el| ideal(el) == d }
|
188
310
|
end
|
189
311
|
|
190
|
-
#
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
=begin rdoc
|
195
|
-
Checks if this monoid is anti-isomorph to +other+, if so returns true.
|
196
|
-
=end
|
197
|
-
def anti_isomorph_to?(other)
|
198
|
-
transposed = (0...@order).map do |i|
|
199
|
-
@binary_operation.map { |row| row[i].clone }
|
200
|
-
end
|
201
|
-
|
202
|
-
RLSM::Monoid.new(transposed).isomorph_to?(other)
|
203
|
-
end
|
204
|
-
|
205
|
-
=begin rdoc
|
206
|
-
Checks if the monoid is equal to +other+, i.e. the identity map is an isomorphism.
|
207
|
-
=end
|
208
|
-
def ==(other)
|
209
|
-
return false unless @elements == other.elements
|
210
|
-
return false unless @binary_operation == other.binary_operation
|
211
|
-
|
212
|
-
true
|
213
|
-
end
|
214
|
-
|
215
|
-
=begin rdoc
|
216
|
-
Checks if the monoid is commutative, if so returns true.
|
217
|
-
=end
|
218
|
-
def commutative?
|
219
|
-
@elements.product(@elements).all? { |x,y| self[x,y] == self[y,x] }
|
220
|
-
end
|
221
|
-
|
222
|
-
=begin rdoc
|
223
|
-
Returns the submonoid which is generated by the given elements. If one of the given elements isn't a monoid element, an MonoidException is raised.
|
224
|
-
=end
|
225
|
-
def get_submonoid(*args)
|
226
|
-
element_indices = get_closure_of(args).map { |x| @elements.index(x) }
|
227
|
-
|
228
|
-
RLSM::Monoid.new(@binary_operation.values_at(*element_indices).
|
229
|
-
map { |r| r.values_at *element_indices } )
|
230
|
-
end
|
231
|
-
|
232
|
-
=begin rdoc
|
233
|
-
Returns an array of all submonoids of this monoid. The array is sorted in lexicographical order of the submonoid elements.
|
234
|
-
=end
|
235
|
-
def submonoids
|
236
|
-
@elements.powerset.map { |s| get_closure_of(s) }.uniq.sort_lex.map do |s|
|
237
|
-
get_submonoid(s)
|
238
|
-
end
|
239
|
-
end
|
240
|
-
|
241
|
-
=begin rdoc
|
242
|
-
Returns an array of all proper submonoids of this monoid. The array is sorted in lexicographical order of the submonoid elements.
|
243
|
-
=end
|
244
|
-
def proper_submonoids
|
245
|
-
submonoids.reject { |m| [1,@order].include? m.order }
|
246
|
-
end
|
247
|
-
|
248
|
-
=begin rdoc
|
249
|
-
Returns true if this monoid is a submonoid of +other+.
|
250
|
-
=end
|
251
|
-
def submonoid_of?(other)
|
252
|
-
other.submonoids.include? self
|
253
|
-
end
|
254
|
-
|
255
|
-
#A synonym for submonoid_of?
|
256
|
-
def <=(other)
|
257
|
-
submonoid_of?(other)
|
258
|
-
end
|
259
|
-
|
260
|
-
=begin rdoc
|
261
|
-
Returns true if this monoid is a proper submonoid of +other+.
|
262
|
-
=end
|
263
|
-
def proper_submonoid_of?(other)
|
264
|
-
other.proper_submonoids.include? self
|
265
|
-
end
|
266
|
-
|
267
|
-
#A synonym for proper_submonoid_of?
|
268
|
-
def <(other)
|
269
|
-
proper_submonoid_of?(other)
|
270
|
-
end
|
271
|
-
|
272
|
-
=begin rdoc
|
273
|
-
Returns true if this monoid has +other+ as a submonoid
|
274
|
-
=end
|
275
|
-
def has_as_submonoid?(other)
|
276
|
-
other.submonoid_of?(self)
|
277
|
-
end
|
278
|
-
|
279
|
-
#A synonym for has_as_submonoid?
|
280
|
-
def >=(other)
|
281
|
-
has_as_submonoid?(other)
|
282
|
-
end
|
283
|
-
|
284
|
-
=begin rdoc
|
285
|
-
Returns true if this monoid has +other+ as a proper submonoid
|
286
|
-
=end
|
287
|
-
def has_as_proper_submonoid?(other)
|
288
|
-
other.proper_submonoid_of?(self)
|
289
|
-
end
|
290
|
-
|
291
|
-
#A synonym for has_as_proper_submonoid?
|
292
|
-
def >(other)
|
293
|
-
has_as_proper_submonoid?(other)
|
294
|
-
end
|
295
|
-
|
296
|
-
=begin rdoc
|
297
|
-
Returns the lexicographical smallest subset which generates the monoid
|
298
|
-
=end
|
299
|
-
def generating_subset
|
300
|
-
@elements.powerset.find { |s| get_closure_of(s).size == @order }
|
301
|
-
end
|
302
|
-
|
303
|
-
=begin rdoc
|
304
|
-
Returns the right ideal of the given element. Raises a MonoidException if the given element isn't in the monoid.
|
305
|
-
=end
|
306
|
-
def right_ideal_of(element)
|
307
|
-
check_args(element)
|
308
|
-
|
309
|
-
@binary_operation[@elements.index(element)].uniq.sort
|
310
|
-
end
|
311
|
-
|
312
|
-
=begin rdoc
|
313
|
-
Returns the left ideal of the given element. Raises a MonoidException if the given element isn't in the monoid.
|
314
|
-
=end
|
315
|
-
def left_ideal_of(element)
|
316
|
-
check_args(element)
|
317
|
-
|
318
|
-
i = @elements.index(element)
|
319
|
-
@binary_operation.map { |row| row[i] }.uniq.sort
|
320
|
-
end
|
321
|
-
|
322
|
-
=begin rdoc
|
323
|
-
Returns the (two-sided) ideal of the given element. Raises a MonoidException if the given element isn't in the monoid.
|
324
|
-
=end
|
325
|
-
def ideal_of(element)
|
326
|
-
@elements.product(@elements).inject([]) do |res,xy|
|
327
|
-
x,y = xy.first, xy.last
|
328
|
-
res << self[x,element,y] unless res.include? self[x,element,y]
|
329
|
-
res.sort
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
=begin rdoc
|
334
|
-
Returns the L-class of the given element. Raises a MonoidException if the given element isn't a monoid element.
|
335
|
-
=end
|
336
|
-
def l_class_of(element)
|
337
|
-
l = left_ideal_of(element)
|
338
|
-
@elements.select { |x| left_ideal_of(x) == l }
|
339
|
-
end
|
340
|
-
|
341
|
-
=begin rdoc
|
342
|
-
Returns all different L-classes of the monoid ordered by the lexicographical smallest element of each class
|
343
|
-
=end
|
344
|
-
def l_classes
|
345
|
-
@elements.map { |x| l_class_of(x) }.uniq
|
346
|
-
end
|
347
|
-
|
348
|
-
=begin rdoc
|
349
|
-
Returns true if the monoid is L-trivial.
|
350
|
-
=end
|
351
|
-
def l_trivial?
|
352
|
-
l_classes.all? { |l| l.size == 1 }
|
353
|
-
end
|
354
|
-
|
355
|
-
=begin rdoc
|
356
|
-
Returns the R-class of the given element. Raises a MonoidException if the given element isn't a monoid element.
|
357
|
-
=end
|
358
|
-
def r_class_of(element)
|
359
|
-
r = right_ideal_of(element)
|
360
|
-
@elements.select { |x| right_ideal_of(x) == r }
|
361
|
-
end
|
362
|
-
=begin rdoc
|
363
|
-
Returns all different R-classes of the monoid ordered by the lexicographical smallest element of each class
|
364
|
-
=end
|
365
|
-
def r_classes
|
366
|
-
@elements.map { |x| r_class_of(x) }.uniq
|
367
|
-
end
|
368
|
-
|
369
|
-
=begin rdoc
|
370
|
-
Returns true if the monoid is R-trivial.
|
371
|
-
=end
|
372
|
-
def r_trivial?
|
373
|
-
r_classes.all? { |r| r.size == 1 }
|
374
|
-
end
|
375
|
-
|
376
|
-
=begin rdoc
|
377
|
-
Returns the H-class of the given element. Raises a MonoidException if the given element isn't a monoid element.
|
378
|
-
=end
|
379
|
-
def h_class_of(element)
|
380
|
-
l_class_of(element) & r_class_of(element)
|
381
|
-
end
|
382
|
-
|
383
|
-
=begin rdoc
|
384
|
-
Returns all different H-classes of the monoid ordered by the lexicographical smallest element of each class
|
385
|
-
=end
|
386
|
-
def h_classes
|
387
|
-
@elements.map { |x| h_class_of(x) }.uniq
|
388
|
-
end
|
389
|
-
|
390
|
-
=begin rdoc
|
391
|
-
Returns true if the monoid is H-trivial.
|
392
|
-
=end
|
393
|
-
def h_trivial?
|
394
|
-
h_classes.all? { |h| h.size == 1 }
|
395
|
-
end
|
396
|
-
|
397
|
-
=begin rdoc
|
398
|
-
Returns the D-class of the given element. Raises a MonoidException if the given element isn't a monoid element.
|
399
|
-
=end
|
400
|
-
def d_class_of(element)
|
401
|
-
d = ideal_of(element)
|
402
|
-
@elements.select { |x| ideal_of(x) == d }
|
403
|
-
end
|
404
|
-
|
405
|
-
=begin rdoc
|
406
|
-
Returns all different D-classes of the monoid ordered by the lexicographical smallest element of each class
|
407
|
-
=end
|
408
|
-
def d_classes
|
409
|
-
@elements.map { |x| d_class_of(x) }.uniq
|
410
|
-
end
|
411
|
-
|
412
|
-
=begin rdoc
|
413
|
-
Returns true if the monoid is D-trivial.
|
414
|
-
=end
|
415
|
-
def d_trivial?
|
416
|
-
d_classes.all? { |d| d.size == 1 }
|
417
|
-
end
|
418
|
-
|
419
|
-
#Synonym for d_class_of (in a finite monoid =D= is the same as =J=)
|
420
|
-
def j_class_of(element)
|
421
|
-
d_class_of(element)
|
422
|
-
end
|
423
|
-
|
424
|
-
#Synonym for d_classes (in a finite monoid =D= is the same as =J=)
|
425
|
-
def j_classes
|
426
|
-
d_classes
|
427
|
-
end
|
428
|
-
|
429
|
-
#Synonym for d_trivial? (in a finite monoid =D= is the same as =J=)
|
430
|
-
def j_trivial?
|
431
|
-
d_trivial?
|
432
|
-
end
|
433
|
-
|
434
|
-
=begin rdoc
|
435
|
-
Returns true if the given element is idempotent.
|
436
|
-
=end
|
437
|
-
def idempotent?(x = nil)
|
438
|
-
x ? x == self[x,x] : @elements.all? { |x| idempotent?(x) }
|
439
|
-
end
|
440
|
-
|
441
|
-
=begin rdoc
|
442
|
-
Returns all idempotent elements of the monoid.
|
443
|
-
=end
|
444
|
-
def idempotents
|
445
|
-
@elements.select { |x| idempotent?(x) }
|
446
|
-
end
|
447
|
-
|
448
|
-
=begin rdoc
|
449
|
-
Returns true if the monoid is also a group.
|
450
|
-
=end
|
451
|
-
def group?
|
452
|
-
idempotents.size == 1
|
453
|
-
end
|
454
|
-
|
455
|
-
=begin rdoc
|
456
|
-
Returns true if the given element is a left zero. Raises a MonoidException if the given element isn't a monoid element.
|
457
|
-
=end
|
458
|
-
def left_zero?(element)
|
459
|
-
return false if @order == 1
|
460
|
-
@elements.all? { |x| self[element,x] == element }
|
461
|
-
end
|
462
|
-
|
463
|
-
=begin rdoc
|
464
|
-
Returns all left zeros of the monoid.
|
465
|
-
=end
|
466
|
-
def left_zeros
|
467
|
-
@elements.select { |x| left_zero?(x) }
|
468
|
-
end
|
469
|
-
|
470
|
-
=begin rdoc
|
471
|
-
Returns true if the given element is a right zero. Raises a MonoidException if the given element isn't a monoid element.
|
472
|
-
=end
|
473
|
-
def right_zero?(element)
|
474
|
-
return false if @order == 1
|
475
|
-
@elements.all? { |x| self[x,element] == element }
|
476
|
-
end
|
477
|
-
|
478
|
-
=begin rdoc
|
479
|
-
Returns all right zeros of the monoid.
|
480
|
-
=end
|
481
|
-
def right_zeros
|
482
|
-
@elements.select { |x| right_zero?(x) }
|
483
|
-
end
|
484
|
-
|
485
|
-
=begin rdoc
|
486
|
-
Returns the neutral element.
|
487
|
-
=end
|
488
|
-
def neutral_element
|
489
|
-
@elements.first.dup
|
490
|
-
end
|
491
|
-
|
492
|
-
=begin rdoc
|
493
|
-
Returns the zero element if it exists, nil otherwise.
|
494
|
-
=end
|
495
|
-
def zero_element
|
496
|
-
@elements.find { |x| left_zero?(x) and right_zero?(x) }
|
497
|
-
end
|
498
|
-
|
499
|
-
|
500
|
-
=begin rdoc
|
501
|
-
Returns true if the given set (as an array) is disjunctive.
|
502
|
-
=end
|
503
|
-
def subset_disjunctive?(set)
|
504
|
-
check_args(set)
|
505
|
-
|
506
|
-
tup = @elements.product(@elements)
|
507
|
-
|
508
|
-
tup.all? do |a,b|
|
509
|
-
a == b or tup.any? do |x,y|
|
510
|
-
set.include?(self[x,a,y]) ^ set.include?(self[x,b,y])
|
511
|
-
end
|
312
|
+
#Calculates the H-class of an element.
|
313
|
+
def h_class(element)
|
314
|
+
l_class(element) & r_class(element)
|
512
315
|
end
|
513
|
-
end
|
514
316
|
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
@elements.powerset.find { |s| subset_disjunctive? s }
|
520
|
-
end
|
317
|
+
#Synonym for j_class (in a finite monoid the J and D relation are the same).
|
318
|
+
def d_class(element)
|
319
|
+
j_class(element)
|
320
|
+
end
|
521
321
|
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
def all_disjunctive_subsets
|
526
|
-
@elements.powerset.select { |s| subset_disjunctive? s }
|
527
|
-
end
|
528
|
-
|
529
|
-
=begin rdoc
|
530
|
-
Returns true if the monoid is syntactic.
|
531
|
-
=end
|
532
|
-
def syntactic?
|
533
|
-
!disjunctive_subset.nil?
|
534
|
-
end
|
535
|
-
|
536
|
-
=begin rdoc
|
537
|
-
Returns true if the monoid is aperiodic. (A synonym for h_trivial?)
|
538
|
-
=end
|
539
|
-
def aperiodic?
|
540
|
-
h_trivial?
|
541
|
-
end
|
542
|
-
|
543
|
-
def to_s # :nodoc:
|
544
|
-
sep = ''
|
545
|
-
sep = ',' if @elements.any? { |x| x.length > 1 }
|
546
|
-
@binary_operation.map { |row| row.join(sep) }.join(' ')
|
547
|
-
end
|
548
|
-
|
549
|
-
def inspect # :nodoc:
|
550
|
-
"<#{self.class}: #{to_s}>"
|
551
|
-
end
|
552
|
-
|
553
|
-
=begin rdoc
|
554
|
-
Arranges the elements in such a way that the generators follows directly the neutral element.
|
555
|
-
=end
|
556
|
-
def normalize
|
557
|
-
#new element order
|
558
|
-
elements =
|
559
|
-
[@elements.first] +
|
560
|
-
generating_subset +
|
561
|
-
(@elements[(1..-1)] - generating_subset)
|
562
|
-
|
563
|
-
indices = elements.map { |x| @elements.index(x) }
|
564
|
-
|
565
|
-
#Adjust the binaray operation
|
566
|
-
@binary_operation = @binary_operation.values_at(*indices).map do |row|
|
567
|
-
row.values_at(*indices)
|
568
|
-
end
|
569
|
-
|
570
|
-
#Adjust the elements
|
571
|
-
@elements = elements
|
572
|
-
|
573
|
-
self
|
574
|
-
end
|
575
|
-
|
576
|
-
=begin rdoc
|
577
|
-
Renames the elements to 1,a,b,c,d,e,... (see also elements=). It may be a little bit confusing if the monoid has more than 27 elements, because then the 28th element is named 'aa' which should not confused with the product in the monoid.
|
578
|
-
=end
|
579
|
-
def rename_elements
|
580
|
-
#Create the new elements
|
581
|
-
eles = ['1']
|
582
|
-
if @order > 1
|
583
|
-
eles << 'a'
|
584
|
-
eles << eles.last.succ while eles.size < @order
|
585
|
-
end
|
586
|
-
|
587
|
-
self.elements = eles
|
588
|
-
self
|
589
|
-
end
|
590
|
-
|
591
|
-
=begin rdoc
|
592
|
-
Renames the elements to the given array. Each array entry will be converted to a string.
|
593
|
-
|
594
|
-
A MonoidException will be raised if
|
595
|
-
* the given array has the wrong size
|
596
|
-
* the given array has duplicated elements (e.g. ['a','b','a'])
|
597
|
-
=end
|
598
|
-
def elements=(els)
|
599
|
-
els.map! { |x| x.to_s }
|
600
|
-
|
601
|
-
if els.size != @order
|
602
|
-
raise MonoidException, "Wrong number of elements given!"
|
603
|
-
elsif els.uniq!
|
604
|
-
raise MonoidException, "Given elements aren't unique!"
|
605
|
-
end
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
@binary_operation.map! do |row|
|
610
|
-
row.map { |x| els[@elements.index(x)] }
|
611
|
-
end
|
612
|
-
|
613
|
-
@elements = els
|
614
|
-
end
|
615
|
-
=begin rdoc
|
616
|
-
Returns a DFA which has the elements as states, the binary operation as transitions and the neutral element as initial state.
|
617
|
-
|
618
|
-
As optional parameter one may pass an array of elements which should become the final states. If the monoid is syntactic, these finals must be a disjunctive subset.
|
619
|
-
|
620
|
-
Also if the monoid is syntactic the set returned by disjunctive subset will be used as the finals as default.
|
621
|
-
=end
|
622
|
-
def to_dfa(finals = [])
|
623
|
-
check_args *finals
|
624
|
-
if generating_subset == []
|
625
|
-
return RLSM::DFA.new(:alphabet => [], :states => @elements,
|
626
|
-
:initial => neutral_element,
|
627
|
-
:finals => finals, :transitions => [])
|
322
|
+
#Synonym for h_trivial?.
|
323
|
+
def aperiodic?
|
324
|
+
h_trivial?
|
628
325
|
end
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
326
|
+
|
327
|
+
##
|
328
|
+
# :method: l_classes
|
329
|
+
# Returns all L-classes of the monoid.
|
330
|
+
|
331
|
+
##
|
332
|
+
# :method: r_classes
|
333
|
+
# Returns all R-classes of the monoid.
|
334
|
+
|
335
|
+
##
|
336
|
+
# :method: j_classes
|
337
|
+
# Returns all J-classes of the monoid.
|
338
|
+
|
339
|
+
##
|
340
|
+
# :method: h_classes
|
341
|
+
# Returns all H-classes of the monoid.
|
342
|
+
|
343
|
+
##
|
344
|
+
# :method: d_classes
|
345
|
+
# Returns all D-classes of the monoid.
|
346
|
+
|
347
|
+
##
|
348
|
+
# :method: l_trivial?
|
349
|
+
# Checks if all L-classes consist of one element.
|
350
|
+
|
351
|
+
##
|
352
|
+
# :method: r_trivial?
|
353
|
+
# Checks if all R-classes consist of one element.
|
354
|
+
|
355
|
+
##
|
356
|
+
# :method: j_trivial?
|
357
|
+
# Checks if all J-classes consist of one element.
|
358
|
+
|
359
|
+
##
|
360
|
+
# :method: h_trivial?
|
361
|
+
# Checks if all H-classes consist of one element.
|
362
|
+
|
363
|
+
##
|
364
|
+
# :method: d_trivial?
|
365
|
+
# Checks if all D-classes consist of one element.
|
366
|
+
|
367
|
+
##
|
368
|
+
# Method missing magic...
|
369
|
+
def method_missing(name) #:nodoc:
|
370
|
+
case name.to_s
|
371
|
+
when /([jlrhd])_classes/
|
372
|
+
green_classes($1)
|
373
|
+
when /([jlrhd])_trivial?/
|
374
|
+
green_trivial?($1)
|
633
375
|
else
|
634
|
-
|
635
|
-
raise MonoidException, "Given finals aren't a disjunctive subset."
|
636
|
-
end
|
376
|
+
super
|
637
377
|
end
|
638
378
|
end
|
639
379
|
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
380
|
+
#Checks if the given set is a disjunctive subset.
|
381
|
+
def subset_disjunctive?(set)
|
382
|
+
tupels = []
|
383
|
+
@elements.each do |el1|
|
384
|
+
@elements.each do |el2|
|
385
|
+
tupels << [el1, el2]
|
386
|
+
end
|
387
|
+
end
|
644
388
|
|
645
|
-
|
646
|
-
|
389
|
+
tupels.all? do |a,b|
|
390
|
+
a == b or tupels.any? do |x,y|
|
391
|
+
set.include?(self[x,a,y]) ^ set.include?(self[x,b,y])
|
392
|
+
end
|
393
|
+
end
|
394
|
+
end
|
647
395
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
396
|
+
#Returns a disjunctive subset if any exists. Returns +nil+ otherwise.
|
397
|
+
def disjunctive_subset
|
398
|
+
@elements.powerset.find { |s| subset_disjunctive? s }
|
399
|
+
end
|
652
400
|
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
401
|
+
#Returns an array with all disjunctive subsets.
|
402
|
+
def all_disjunctive_subsets
|
403
|
+
@elements.powerset.select { |s| subset_disjunctive? s }
|
404
|
+
end
|
657
405
|
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
generating_subset.each do |l|
|
662
|
-
@elements.each do |s|
|
663
|
-
trans << [l,s,self[s,l]]
|
664
|
-
end
|
406
|
+
#Checks if the monoid is syntactic, i.e. if it has a disjunctive subset.
|
407
|
+
def syntactic?
|
408
|
+
!!disjunctive_subset
|
665
409
|
end
|
666
|
-
trans
|
667
|
-
end
|
668
410
|
|
669
|
-
|
670
|
-
|
671
|
-
|
411
|
+
def to_s # :nodoc:
|
412
|
+
result = ""
|
413
|
+
sep = @elements.any? { |x| x.length > 1 } ? ',' : ''
|
414
|
+
@binary_operation.table.each_with_index do |el,i|
|
415
|
+
result += @binary_operation.elements[el]
|
416
|
+
if (i+1) % (@order) == 0
|
417
|
+
result += ' '
|
418
|
+
else
|
419
|
+
result += sep unless i = @order**2 - 1
|
420
|
+
end
|
421
|
+
end
|
672
422
|
|
673
|
-
|
674
|
-
raise MonoidException, "Bad argument: #{bad[0]}"
|
675
|
-
elsif bad.size > 1
|
676
|
-
raise MonoidException, "Bad arguments: #{bad.join(',')}"
|
423
|
+
result
|
677
424
|
end
|
678
|
-
end
|
679
425
|
|
680
|
-
|
681
|
-
|
682
|
-
|
426
|
+
def inspect # :nodoc:
|
427
|
+
"<#{self.class}: #{to_s}>"
|
428
|
+
end
|
683
429
|
|
684
|
-
#
|
685
|
-
|
430
|
+
#Returns the monoid.
|
431
|
+
def to_monoid
|
432
|
+
self
|
433
|
+
end
|
686
434
|
|
687
|
-
|
688
|
-
|
689
|
-
|
435
|
+
#Returns a regular expression which represents a language with a syntactic monoid isomorph to +self+.
|
436
|
+
def to_regexp
|
437
|
+
to_dfa.to_regexp
|
438
|
+
end
|
439
|
+
|
440
|
+
#Returns a DFA which represents a language with a syntactic monoid isomorph to +self+.
|
441
|
+
def to_dfa(finals = nil)
|
442
|
+
finals = finals || disjunctive_subset || []
|
690
443
|
|
691
|
-
|
692
|
-
unless
|
693
|
-
|
694
|
-
searching = true
|
444
|
+
if syntactic?
|
445
|
+
unless all_disjunctive_subsets.include? finals
|
446
|
+
raise MonoidError, "#{finals} isn't a disjunctive subset."
|
695
447
|
end
|
696
448
|
end
|
697
|
-
end
|
698
449
|
|
699
|
-
|
700
|
-
end
|
450
|
+
string = "}s#{@elements.index(identity)} "
|
701
451
|
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
452
|
+
finals.each do |element|
|
453
|
+
string += "*s#{@elements.index(element)} "
|
454
|
+
end
|
455
|
+
|
456
|
+
generating_subset.each do |let|
|
457
|
+
@elements.each do |start|
|
458
|
+
string += "s#{@elements.index(start)}-#{let}->s#{@elements.index(self[start,let])} "
|
459
|
+
end
|
710
460
|
end
|
461
|
+
|
462
|
+
RLSM::DFA.new string
|
711
463
|
end
|
712
|
-
end
|
713
464
|
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
465
|
+
private
|
466
|
+
def set_to_monoid(set)
|
467
|
+
description = set.map do |el1|
|
468
|
+
set.map { |el2| self[el1,el2] }.join(",")
|
469
|
+
end
|
470
|
+
|
471
|
+
RLSM::Monoid[ description.join(' ') ]
|
472
|
+
end
|
719
473
|
|
720
|
-
|
721
|
-
|
474
|
+
def element_sorter
|
475
|
+
Proc.new { |el1,el2| @elements.index(el1) <=> @elements.index(el2)}
|
476
|
+
end
|
722
477
|
|
723
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
478
|
+
def subset_sorter
|
479
|
+
Proc.new do |set1,set2|
|
480
|
+
if set1.size == set2.size
|
481
|
+
set1.map { |el| @elements.index(el) } <=>
|
482
|
+
set2.map { |el| @elements.index(el) }
|
483
|
+
else
|
484
|
+
set1.size <=> set2.size
|
485
|
+
end
|
486
|
+
end
|
728
487
|
end
|
729
|
-
end
|
730
488
|
|
731
|
-
|
732
|
-
|
733
|
-
validate_elements
|
734
|
-
validate_neutral_element
|
735
|
-
validate_associativity
|
736
|
-
end
|
489
|
+
def sorted_subsets
|
490
|
+
subsets = @elements.powerset
|
737
491
|
|
738
|
-
|
739
|
-
if @binary_operation.empty?
|
740
|
-
raise(MonoidException,
|
741
|
-
"No binary operation given!")
|
492
|
+
subsets.sort(&subset_sorter)
|
742
493
|
end
|
494
|
+
|
495
|
+
def get_submonoid_candidates
|
496
|
+
submons = []
|
497
|
+
|
498
|
+
@elements.powerset.each do |set|
|
499
|
+
candidate = generated_set(set)
|
500
|
+
submons << candidate unless submons.include? candidate
|
501
|
+
end
|
743
502
|
|
744
|
-
|
745
|
-
raise(MonoidException,
|
746
|
-
"A binary operation must be quadratic!")
|
503
|
+
submons.sort(&subset_sorter)
|
747
504
|
end
|
748
|
-
end
|
749
505
|
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
506
|
+
def bijective_maps_to(other)
|
507
|
+
return [] if @order != other.order
|
508
|
+
|
509
|
+
other.elements.permutations.map do |perm|
|
510
|
+
Hash[*@elements.zip(perm).flatten]
|
511
|
+
end
|
755
512
|
end
|
756
513
|
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
514
|
+
def isomorphism?(map,other)
|
515
|
+
@elements.each do |el1|
|
516
|
+
@elements.each do |el2|
|
517
|
+
return false if map[self[el1,el2]] != other[map[el1],map[el2]]
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
true
|
761
522
|
end
|
762
|
-
end
|
763
523
|
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
|
524
|
+
def antiisomorphism?(map,other)
|
525
|
+
@elements.each do |el1|
|
526
|
+
@elements.each do |el2|
|
527
|
+
return false if map[self[el1,el2]] != other[map[el2],map[el1]]
|
528
|
+
end
|
769
529
|
end
|
770
|
-
|
771
|
-
|
530
|
+
|
531
|
+
true
|
772
532
|
end
|
773
|
-
end
|
774
533
|
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
534
|
+
def green_classes(type)
|
535
|
+
not_tested = @elements.dup
|
536
|
+
classes = []
|
537
|
+
|
538
|
+
until not_tested.empty?
|
539
|
+
classes << self.send((type + '_class').to_sym, not_tested.first)
|
540
|
+
not_tested = not_tested.reject { |el| classes.last.include? el }
|
541
|
+
end
|
542
|
+
|
543
|
+
classes.sort(&subset_sorter)
|
781
544
|
end
|
782
545
|
|
783
|
-
|
784
|
-
|
785
|
-
err_str = "#{nat[0]}(#{nat[1]}#{nat[2]}) != (#{nat[0]}#{nat[1]})#{nat[2]}"
|
786
|
-
raise(MonoidException,
|
787
|
-
"Given binary operation is not associative: #{err_str}")
|
546
|
+
def green_trivial?(type)
|
547
|
+
@elements.all? { |el| self.send((type + '_class').to_sym, el).size == 1 }
|
788
548
|
end
|
789
|
-
end
|
790
|
-
end
|
549
|
+
end # of class Monoid
|
550
|
+
end # of module RLSM
|