rlsm 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,24 +1,19 @@
1
1
  = rlsm
2
+ rlsm stands for *R*egular *L*anguages and *S*yntactic *M*onoids.
2
3
 
3
- http://www.github.com/asmodis/rlsm
4
+ Source is availible from
5
+ http://github.com/asmodis/rlsm
6
+
7
+ RDoc-Documentation is availible from
8
+ http://rlsm.rubyforge.org
4
9
 
5
10
  == DESCRIPTION:
6
11
 
7
12
  This is a ruby implementation of three concepts:
8
- - Deterministic Finite Automata (DFA)
13
+ - Deterministic Finite Automata
9
14
  - Regular Expressions (in the sense of theoretical computer sience)
10
- - Monoids (an algebraic construct)
11
-
12
-
13
- == FEATURES/PROBLEMS:
14
-
15
- It is possible to convert
16
- Monoid -> DFA
17
- DFA -> RegExp
18
- RegExp -> DFA
19
- DFA -> Monoid
15
+ - Monoids
20
16
 
21
- Also it is possible to ask a monoid for some properties.
22
17
 
23
18
  == SYNOPSIS:
24
19
 
@@ -29,24 +24,16 @@ Also it is possible to ask a monoid for some properties.
29
24
  m.isomorph_to?(m) # => true
30
25
  m.commutative? # => false
31
26
 
32
- == REQUIREMENTS:
33
-
34
- Depends on
35
- - sqlite3-ruby
36
-
37
27
  == INSTALL:
38
28
 
39
- Hopefully a
40
-
41
- sudo gem install rlsm
29
+ gem install rlsm
42
30
 
43
- is sufficent.
44
31
 
45
32
  == LICENSE:
46
33
 
47
34
  (The MIT License)
48
35
 
49
- Copyright (c) 2008 Gunther Diemant <g.diemant@gmx.net>
36
+ Copyright (c) 2009 Gunther Diemant <g.diemant@gmx.net>
50
37
 
51
38
  Permission is hereby granted, free of charge, to any person obtaining
52
39
  a copy of this software and associated documentation files (the
data/Rakefile CHANGED
@@ -1,12 +1,84 @@
1
1
  # -*- ruby -*-
2
2
 
3
- require 'rubygems'
4
- require 'hoe'
5
- require './lib/rlsm.rb'
3
+ require File.join(File.dirname(__FILE__), 'lib', 'rlsm')
6
4
 
7
- Hoe.new('rlsm', RLSM::VERSION) do |p|
8
- #p.rubyforge_name = 'rlsm' # if different than lowercase project name
9
- p.developer('asmodis', 'g.diemant@gmx.net')
5
+ task :build_ext do
6
+ Dir.chdir File.join(File.dirname(__FILE__), 'ext') do
7
+ Dir.foreach('.') do |extension|
8
+ Dir.chdir extension do
9
+ if File.exists? 'extconf.rb'
10
+ ruby 'extconf.rb'
11
+ sh "make"
12
+ end
13
+ end
14
+ end
15
+ end
10
16
  end
11
17
 
12
- # vim: syntax=Ruby
18
+ task :test => :build_ext do
19
+ Dir.chdir File.join(File.dirname(__FILE__), 'test') do
20
+ Dir.glob("test_*").each do |file|
21
+ ruby file
22
+ end
23
+ end
24
+ end
25
+
26
+ task :create_manifest do
27
+ Dir.chdir(File.dirname(__FILE__)) do
28
+ File.open("Manifest", 'w') do |manifest|
29
+ FileList['lib/**/*.rb', 'ext/**/*.c','ext/**/*.rb', 'test/**/*'].to_a.each do |file|
30
+ manifest.puts file
31
+ end
32
+
33
+ manifest.puts "Rakefile"
34
+ manifest.puts "README"
35
+ end
36
+ end
37
+ end
38
+
39
+ task :create_gemspec => :create_manifest do
40
+ Dir.chdir(File.dirname(__FILE__)) do
41
+ readme = File.open("README")
42
+ manifest = File.open("Manifest")
43
+ filelist = "[" + manifest.to_a.map { |line| "'#{line.chomp}'" }.join(", ") + "]"
44
+ manifest.close
45
+
46
+ readme_string = '<<DESCRIPTION' + "\n" + readme.to_a.join + "\nDESCRIPTION"
47
+ readme.close
48
+
49
+ File.open(".gemspec", 'w') do |gemspec|
50
+ gemspec.puts <<GEMSPEC
51
+ # -*- ruby -*-
52
+
53
+ require "rake"
54
+
55
+ Gem::Specification.new do |s|
56
+ s.author = "Gunther Diemant"
57
+ s.email = "g.diemant@gmx.net"
58
+ s.homepage = "http://github.com/asmodis/rlsm"
59
+ s.rubyforge_project = 'rlsm'
60
+
61
+ s.name = 'rlsm'
62
+ s.version = '#{RLSM::VERSION}'
63
+ s.add_development_dependency('minitest')
64
+ s.add_development_dependency('thoughtbot-shoulda')
65
+ s.summary = "Library for investigating regular languages and syntactic monoids."
66
+ s.description = #{readme_string}
67
+
68
+ s.files = #{filelist}
69
+ s.test_files = FileList['test/test_*.rb']
70
+ s.extensions = FileList['ext/**/extconf.rb']
71
+
72
+ s.has_rdoc = true
73
+ s.extra_rdoc_files = ['README']
74
+ s.rdoc_options << '--main' << 'README'
75
+ end
76
+ GEMSPEC
77
+ end
78
+ end
79
+ end
80
+
81
+ task :create_gem => :create_gemspec do
82
+ sh "gem build .gemspec"
83
+ sh "mv *.gem gem/"
84
+ end
@@ -0,0 +1,137 @@
1
+ #include <ruby.h>
2
+
3
+ static int
4
+ c_subset_next(int* sub, int n, int k) {
5
+ int i = k - 1;
6
+
7
+ while(i >= 0 && sub[i] == n-k+i) { i--; }
8
+
9
+ if (i < 0)
10
+ return -1;
11
+
12
+ int j;
13
+ int sub_i = sub[i];
14
+ for (j=i; j < k; ++j) {
15
+ sub[j] = sub_i + 1 + j - i;
16
+ }
17
+
18
+ return 0;
19
+ }
20
+
21
+ static int
22
+ c_next_perm(int* perm, int n) {
23
+ int i = n-2;
24
+ while (i >= -1 && perm[i+1] < perm[i]) { i--; }
25
+ if ( i < 0 ) { return -1; }
26
+
27
+ int j = n-1;
28
+ while ( perm[j] < perm[i] ) { j--; }
29
+
30
+ int temp = perm[i];
31
+ perm[i] = perm[j];
32
+ perm[j] = temp;
33
+
34
+ int* tmp = (int*) ALLOCA_N(int, n);
35
+
36
+ int k;
37
+ for (k=0; k < n; ++k) { tmp[k] = perm[k]; }
38
+
39
+ for (k = i+1; k < n; ++k) {
40
+ perm[k] = tmp[n+i-k];
41
+ }
42
+
43
+ return 0;
44
+ }
45
+
46
+ static VALUE
47
+ ary2ruby(int* subset, int k, VALUE ary) {
48
+ VALUE result = rb_ary_new2(k);
49
+ int i;
50
+
51
+ for (i=0; i < k; ++i) {
52
+ rb_ary_store(result, i, RARRAY(ary)->ptr[subset[i]]);
53
+ }
54
+
55
+ return result;
56
+ }
57
+
58
+ static VALUE
59
+ powerset(VALUE self) {
60
+ int k;
61
+ int n = RARRAY(self)->len;
62
+ if (!rb_block_given_p()) {
63
+ VALUE result = rb_ary_new();
64
+ for (k=0; k <= n; ++k) {
65
+ int i,res;
66
+ int* subset = ALLOCA_N(int, k);
67
+ for (i=0; i < k; ++i) { subset[i] = i; }
68
+
69
+ while(1) {
70
+ rb_ary_push(result, ary2ruby(subset,k,self));
71
+ res = c_subset_next(subset, n, k);
72
+ if (res == -1)
73
+ break;
74
+ }
75
+ }
76
+ return result;
77
+ }
78
+ else {
79
+ for (k=0; k <= n; ++k) {
80
+ int i,res;
81
+ int* subset = ALLOCA_N(int, k);
82
+ for (i=0; i < k; ++i) { subset[i] = i; }
83
+
84
+ while(1) {
85
+ rb_yield(ary2ruby(subset,k,self));
86
+ res = c_subset_next(subset, n, k);
87
+ if (res == -1)
88
+ break;
89
+ }
90
+ }
91
+
92
+ return Qnil;
93
+ }
94
+ }
95
+
96
+ static VALUE
97
+ permutations(VALUE self) {
98
+ int res;
99
+ int n = RARRAY(self)->len;
100
+ int* perm = (int*) ALLOCA_N(int, n);
101
+ int t;
102
+ for (t=0; t < n; ++t) { perm[t] = t; }
103
+
104
+ if (rb_block_given_p()) {
105
+ while(1) {
106
+ rb_yield(ary2ruby(perm, n, self));
107
+ res = c_next_perm(perm, n);
108
+ if (res == -1)
109
+ break;
110
+ }
111
+ }
112
+ else {
113
+ VALUE result = rb_ary_new();
114
+ while(1) {
115
+ rb_ary_push(result,ary2ruby(perm, n, self));
116
+ res = c_next_perm(perm, n);
117
+ if (res == -1)
118
+ break;
119
+ }
120
+
121
+ return result;
122
+ }
123
+
124
+ return Qnil;
125
+ }
126
+
127
+ #ifdef __cplusplus
128
+ extern "C" {
129
+ #endif
130
+ void Init_array_cext() {
131
+ VALUE ary = rb_const_get(rb_cObject, rb_intern("Array"));
132
+ rb_define_method(ary, "powerset", (VALUE(*)(ANYARGS))powerset, 0);
133
+ rb_define_method(ary, "permutations", (VALUE(*)(ANYARGS))permutations, 0);
134
+ }
135
+ #ifdef __cplusplus
136
+ }
137
+ #endif
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile('array_cext')
@@ -0,0 +1,57 @@
1
+ #include <ruby.h>
2
+
3
+
4
+ static VALUE
5
+ non_associative_triple(VALUE self) {
6
+ VALUE table = rb_iv_get(self, "@table");
7
+ VALUE max = NUM2INT(rb_iv_get(self, "@order"));
8
+ VALUE base = rb_iv_get(self, "@elements");
9
+
10
+ int i,j,k;
11
+ for (i=0; i < max; ++i) {
12
+ for (j=0; j < max; ++j) {
13
+ for (k=0; k < max; ++k) {
14
+ int ij,jk, i_jk, ij_k;
15
+ ij = NUM2INT(RARRAY(table)->ptr[max*i + j]);
16
+ jk = NUM2INT(RARRAY(table)->ptr[max*j + k]);
17
+ i_jk = NUM2INT(RARRAY(table)->ptr[max*i + jk]);
18
+ ij_k = NUM2INT(RARRAY(table)->ptr[max*ij + k]);
19
+ if (ij_k != i_jk) {
20
+ return (rb_ary_new3(3,RARRAY(base)->ptr[i],RARRAY(base)->ptr[j],RARRAY(base)->ptr[k]));
21
+ }
22
+ }
23
+ }
24
+ }
25
+
26
+ return (Qnil);
27
+ }
28
+
29
+ static VALUE
30
+ is_commutative(VALUE self) {
31
+ VALUE table = rb_iv_get(self, "@table");
32
+ VALUE max = NUM2INT(rb_iv_get(self, "@order"));
33
+
34
+ int i,j;
35
+ for (i=0; i < max; ++i) {
36
+ for (j=0; j < max; ++j) {
37
+ if (NUM2INT(RARRAY(table)->ptr[max*i + j]) != NUM2INT(RARRAY(table)->ptr[max*j + i]))
38
+ return (Qfalse);
39
+ }
40
+ }
41
+
42
+ return (Qtrue);
43
+ }
44
+
45
+ #ifdef __cplusplus
46
+ extern "C" {
47
+ #endif
48
+ void Init_binop_cext() {
49
+ VALUE rlsm = rb_define_module("RLSM");
50
+ VALUE binop = rb_define_class_under(rlsm, "BinaryOperation", rb_cObject);
51
+
52
+ rb_define_private_method(binop, "is_commutative", (VALUE(*)(ANYARGS))is_commutative, 0);
53
+ rb_define_private_method(binop, "non_associative_triple", (VALUE(*)(ANYARGS))non_associative_triple, 0);
54
+ }
55
+ #ifdef __cplusplus
56
+ }
57
+ #endif
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile('binop_cext')
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile('monoid_cext')
@@ -0,0 +1,330 @@
1
+ #include <ruby.h>
2
+
3
+ typedef int bool;
4
+
5
+ static int
6
+ mi_index(VALUE ary, int index) {
7
+ int i;
8
+ for (i=0; i < RARRAY(ary)->len; ++i) {
9
+ if (NUM2INT(RARRAY(ary)->ptr[i]) == index) { return i; }
10
+ }
11
+
12
+ return -1;
13
+ }
14
+
15
+ static int*
16
+ mi_new_ary(int length, int val) {
17
+ int* result = (int*) calloc(length, sizeof(int));
18
+ int i;
19
+ for (i=0; i < length; ++i) { result[i] = val; }
20
+
21
+ return result;
22
+ }
23
+
24
+ static VALUE mi_ary2rb(const int* ary, int length) {
25
+ VALUE result = rb_ary_new2(length);
26
+ int i;
27
+ for (i=0; i < length; ++i) { rb_ary_store(result, i, INT2NUM(ary[i])); }
28
+
29
+ return result;
30
+ }
31
+
32
+ static int*
33
+ mi_helper_init_table(VALUE diagonal, int order) {
34
+ int* result = (int*) calloc(order*order, sizeof(int));
35
+
36
+ int i;
37
+ for (i = 0; i < order*order; ++i) {
38
+ if (i < order)
39
+ result[i] = i;
40
+ else if (i % order == 0)
41
+ result[i] = i / order;
42
+ else if (i % order == i / order)
43
+ result[i] = NUM2INT(RARRAY(diagonal)->ptr[i / order]);
44
+ else
45
+ result[i] = 0;
46
+ }
47
+
48
+ return result;
49
+ }
50
+
51
+ static bool
52
+ mi_is_perm_stable(VALUE diagonal, VALUE perm) {
53
+ int i;
54
+ for (i=0; i < RARRAY(diagonal)->len; ++i) {
55
+ int a = NUM2INT(RARRAY(diagonal)->ptr[i]);
56
+ int b = NUM2INT(RARRAY(perm)->ptr[NUM2INT(RARRAY(diagonal)->ptr[mi_index(perm, i)])]);
57
+
58
+ if ( a != b)
59
+ return 0;
60
+ }
61
+
62
+ return 1;
63
+ }
64
+
65
+ static bool
66
+ mi_is_invertable(VALUE diag, int index) {
67
+ int i, pot = NUM2INT(RARRAY(diag)->ptr[index]);
68
+
69
+ for (i=0; i < RARRAY(diag)->len; ++i) {
70
+ if (pot == 0) { return 1; }
71
+ pot = NUM2INT(RARRAY(diag)->ptr[pot]);
72
+ }
73
+
74
+ return 0;
75
+ }
76
+
77
+ static VALUE
78
+ mi_helper_select_perms(VALUE diagonal, VALUE perms, int order) {
79
+ VALUE result = rb_ary_new();
80
+ VALUE perm;
81
+ int i;
82
+ for (i=0; i < RARRAY(perms)->len; ++i) {
83
+ perm = RARRAY(perms)->ptr[i];
84
+ if (mi_is_perm_stable(diagonal, perm))
85
+ rb_ary_push(result, perm);
86
+ }
87
+
88
+ return result;
89
+ }
90
+
91
+ static int*
92
+ mi_helper_rc_restrictions(VALUE diagonal, int order) {
93
+ int* result = (int*) calloc(order, sizeof(int));
94
+ result[0] = 1;
95
+
96
+ int i;
97
+ for (i=1; i < order; ++i) {
98
+ result[i] = 1;
99
+ if (NUM2INT(RARRAY(diagonal)->ptr[i]) == i)
100
+ result[i] *= 2; /* idempotent */
101
+ if (mi_is_invertable(diagonal, i))
102
+ result[i] *= 3; /* invertible */
103
+ }
104
+
105
+ return result;
106
+ }
107
+
108
+ static bool
109
+ mi_is_diagonal_valid(int* diagonal, int ord, VALUE perms) {
110
+ int i,j;
111
+ VALUE perm;
112
+ for (i=0; i < RARRAY(perms)->len; ++i) {
113
+ perm = RARRAY(perms)->ptr[i];
114
+
115
+ for (j=0; j < ord; ++j) {
116
+ int ii, pdii;
117
+ ii = mi_index(perm, j);
118
+ if (diagonal[ii] == -1) { break; }
119
+
120
+ pdii = NUM2INT(RARRAY(perm)->ptr[diagonal[ii]]);
121
+ if (diagonal[j] < pdii) { break; }
122
+ if (diagonal[j] > pdii) { return 0; }
123
+ }
124
+ }
125
+
126
+ return 1;
127
+ }
128
+
129
+
130
+ static bool
131
+ mi_is_associative(const int* table, int order) {
132
+ int x1,x2,x3;
133
+ for (x1=1; x1 < order; ++x1) {
134
+ for (x2=1; x2 < order; ++x2) {
135
+ for (x3=1; x3 < order; ++x3) {
136
+ int x1x2, x2x3, x1_x2x3, x1x2_x3;
137
+
138
+ x1x2 = table[order*x1 + x2];
139
+ if (x1x2 == -1) { break; }
140
+
141
+ x2x3 = table[order*x2 + x3];
142
+ if (x2x3 == -1) { break; }
143
+
144
+ x1x2_x3 = table[order*x1x2 + x3];
145
+ if (x1x2_x3 == -1) { break; }
146
+
147
+ x1_x2x3 = table[order*x1 + x2x3];
148
+ if (x1_x2x3 == -1) { break; }
149
+
150
+ if (x1_x2x3 != x1x2_x3)
151
+ return 0;
152
+ }
153
+ }
154
+ }
155
+
156
+ return 1;
157
+ }
158
+
159
+ static bool
160
+ mi_is_iso_antiiso(const int* table, int order, VALUE perms) {
161
+ int p,i;
162
+ int max_index = order*order;
163
+ VALUE perm;
164
+
165
+ for (p = 0; p < RARRAY(perms)->len; ++p) {
166
+ int smaller_iso = 0, smaller_aiso = 0;
167
+ perm = RARRAY(perms)->ptr[p];
168
+ for (i = order+1; i < max_index; ++i) {
169
+ int ix1, ix2, ti, tii, taii, ptii, ptaii;
170
+ ix1 = mi_index(perm, i / order);
171
+ ix2 = mi_index(perm, i % order);
172
+
173
+ ti = table[i];
174
+ tii = table[order*ix1 + ix2];
175
+ taii = table[order*ix2 + ix1];
176
+
177
+ if (ti == -1 || tii == -1 || taii == -1 )
178
+ break;
179
+
180
+ ptii = NUM2INT(RARRAY(perm)->ptr[tii]);
181
+ ptaii = NUM2INT(RARRAY(perm)->ptr[taii]);
182
+
183
+ if (ti < ptii)
184
+ smaller_iso = 1;
185
+
186
+ if (ti < ptaii)
187
+ smaller_aiso = 1;
188
+
189
+ if (smaller_iso == 1 && smaller_aiso == 1)
190
+ break;
191
+
192
+ if ((smaller_iso == 0 && ti > ptii) || (smaller_aiso == 0 && ti > ptaii))
193
+ return 0;
194
+ }
195
+ }
196
+
197
+ return 1;
198
+ }
199
+
200
+ static bool
201
+ mi_is_rc_rest_satisfied(const int* table, int order, const int* rc_rest) {
202
+ int i,j,k;
203
+ for (i=1; i < order; ++i) {
204
+ if (rc_rest[i] != 1) {
205
+ if (rc_rest[i] % 2 == 0) {
206
+ for (j=1; j < order; ++j) {
207
+ if (table[order*i + j] == 0 || table[order*j + i] == 0)
208
+ return 0;
209
+ }
210
+ }
211
+
212
+ if (rc_rest[i] % 3 == 0) {
213
+ for (j=0; j < order; ++j) {
214
+ for (k=j+1; k < order; ++k) {
215
+ if (table[order*i + j] != -1 && table[order*i + j] == table[order*i + k] )
216
+ return 0;
217
+ if (table[order*j + i] != -1 && table[order*j + i] == table[order*k + i])
218
+ return 0;
219
+
220
+ }
221
+ }
222
+ }
223
+ }
224
+ }
225
+
226
+ return 1;
227
+ }
228
+
229
+ static bool
230
+ mi_table_valid(const int* table, int order, const int* rc_rest, VALUE perms) {
231
+ if (!mi_is_rc_rest_satisfied(table, order, rc_rest))
232
+ return 0;
233
+
234
+ if (!mi_is_associative(table, order))
235
+ return 0;
236
+
237
+ if (!mi_is_iso_antiiso(table, order, perms))
238
+ return 0;
239
+
240
+ return 1;
241
+ }
242
+
243
+
244
+ static VALUE
245
+ each_diagonal(VALUE self, VALUE rorder, VALUE perms) {
246
+ rb_need_block();
247
+
248
+ int order = NUM2INT(rorder);
249
+ int* diagonal = mi_new_ary(order, 0);
250
+ rb_yield(mi_ary2rb(diagonal, order));
251
+
252
+ int index = order - 1;
253
+ while(1) {
254
+ diagonal[index]++;
255
+ if (diagonal[index] >= order) {
256
+ if (index == 1) { return; } /* finished */
257
+ diagonal[index] = -1;
258
+ index--;
259
+ }
260
+ else if (mi_is_diagonal_valid(diagonal, order, perms)) {
261
+ if (index == order -1)
262
+ rb_yield(mi_ary2rb(diagonal, order));
263
+ else
264
+ index++;
265
+ }
266
+ }
267
+
268
+ return Qnil;
269
+ }
270
+
271
+ static VALUE
272
+ e_w_diagonal(VALUE self, VALUE diagonal, VALUE perms) {
273
+ int order = RARRAY(diagonal)->len, t_order = order*order;
274
+ int* table = mi_helper_init_table(diagonal, order);
275
+ VALUE rperms = mi_helper_select_perms(diagonal, perms, order);
276
+ int* rc_rest = mi_helper_rc_restrictions(diagonal, order);
277
+
278
+ if (mi_table_valid(table, order, rc_rest, rperms)) { rb_yield(mi_ary2rb(table, t_order)); }
279
+
280
+ int index = t_order - 2;
281
+ while (1) {
282
+ table[index]++;
283
+ if (table[index] >= order) {
284
+ if (index <= order + 2) { return; } /* finished */
285
+ table[index] = -1;
286
+ index--;
287
+ /* skip diagonal and first column */
288
+ if ((index % order == index / order) || (index % order == 0))
289
+ index--;
290
+ }
291
+ else if (mi_table_valid(table, order, rc_rest, rperms)) {
292
+ if (index == t_order - 2)
293
+ rb_yield(mi_ary2rb(table, t_order));
294
+ else {
295
+ index++;
296
+ /* skip diagonal and first column */
297
+ if ((index % order == index / order) || (index % order == 0))
298
+ index++;
299
+ }
300
+ }
301
+ }
302
+
303
+ return Qnil;
304
+ }
305
+
306
+ static VALUE
307
+ e_pos(VALUE self, VALUE table, VALUE rorder) {
308
+ int i, order = NUM2INT(rorder);
309
+ for(i=0; i < order; ++i) {
310
+ if (NUM2INT(RARRAY(table)->ptr[i]) != i || NUM2INT(RARRAY(table)->ptr[order*i]) != i) {
311
+ rb_raise(rb_const_get(rb_cObject, rb_intern("MonoidError")), "Neutral element isn't in first row.");
312
+ }
313
+ }
314
+
315
+ return Qnil;
316
+ }
317
+
318
+ #ifdef __cplusplus
319
+ extern "C" {
320
+ #endif
321
+ void Init_monoid_cext() {
322
+ VALUE rlsm = rb_define_module("RLSM");
323
+ VALUE monoid = rb_define_class_under(rlsm, "Monoid", rb_cObject);
324
+ rb_define_singleton_method(monoid, "each_diagonal", (VALUE(*)(ANYARGS))each_diagonal, 2);
325
+ rb_define_singleton_method(monoid, "each_with_diagonal", (VALUE(*)(ANYARGS))e_w_diagonal, 2);
326
+ rb_define_singleton_method(monoid, "enforce_identity_position", (VALUE(*)(ANYARGS))e_pos, 2);
327
+ }
328
+ #ifdef __cplusplus
329
+ }
330
+ #endif