1 /*
2 Copyright Kazuya Takahashi 2018.
3 Distributed under the Boost Software License, Version 1.0.
4 (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 */
6 
7 module structure;
8 
9 struct SetElement(size_t cardinalityOfSet) if (cardinalityOfSet > 0)
10 {
11     import boolean_matrix : BCV;
12 
13     immutable size_t id;
14 
15     this(size_t id)
16     {
17         this.id = id;
18     }
19 
20     this(BCV!cardinalityOfSet entity)
21     {
22         import std.algorithm.searching : countUntil;
23 
24         id = entity[].countUntil(true);
25     }
26 
27     private @property entity() const
28     {
29         return cast(immutable) BCV!cardinalityOfSet.e(id);
30     }
31 }
32 
33 unittest
34 {
35     import boolean_matrix : BCV;
36 
37     auto elem1 = SetElement!4(2);
38     assert(elem1.id == 2);
39     assert(elem1.entity == BCV!4([false, false, true, false]));
40 
41     auto elem2 = SetElement!5(BCV!5([false, false, false, true, false]));
42     assert(elem2.id == 3);
43     assert(elem2.entity == BCV!5([false, false, false, true, false]));
44 }
45 
46 struct PermutationElement(size_t degree) if (degree > 0)
47 {
48     import boolean_matrix : BSM;
49 
50     immutable(BSM!degree) entity;
51     this(BSM!degree entity)
52     {
53         this.entity = entity;
54     }
55 
56     auto opBinary(string op)(in auto ref PermutationElement!degree g) const pure
57     {
58         static if (op == "*")
59         {
60             return immutable(PermutationElement!degree)(this.entity * g.entity);
61         }
62         else
63         {
64             static assert(0, `Operator '` ~ op ~ `' is not implemented.`);
65         }
66     }
67 
68     auto opBinary(string op)(in auto ref SetElement!degree s) const pure
69     {
70         static if (op == "*")
71         {
72             return immutable(SetElement!degree)(this.entity * s.entity);
73         }
74         else
75         {
76             static assert(0, `Operator '` ~ op ~ `' is not implemented.`);
77         }
78     }
79 
80     auto transpose() const pure
81     {
82         import boolean_matrix : transpose;
83 
84         return immutable(PermutationElement!degree)(entity.transpose);
85     }
86 
87     // Delegates "isXXX" properties to boolean_matrix.
88     @property opDispatch(string s)() const pure if (s.length > 2 && s[0 .. 2] == "is")
89     {
90         import boolean_matrix;
91 
92         return mixin(s)(entity);
93     }
94 }
95 
96 unittest
97 {
98     import boolean_matrix : BSM;
99 
100     immutable a = PermutationElement!3(BSM!3([
101                 [true, false, true], [true, true, false], [false, false, true]
102             ]));
103     immutable b = PermutationElement!3(BSM!3([
104                 [false, true, true], [true, false, false], [false, false, true]
105             ]));
106     immutable c = PermutationElement!3(BSM!3([
107                 [false, true, true], [true, true, true], [false, false, true]
108             ]));
109 
110     assert(a * b == c);
111 }
112 
113 unittest
114 {
115     import boolean_matrix : BCV, BSM;
116 
117     immutable a = PermutationElement!3(BSM!3([
118                 [true, false, true], [true, true, false], [false, false, true]
119             ]));
120     immutable b = SetElement!3(BCV!3([true, false, false]));
121     immutable c = SetElement!3(BCV!3([true, true, false]));
122 
123     assert(a * b == c);
124 }
125 
126 auto cyclicPermutation(size_t degree)(size_t shift) pure
127 {
128     import boolean_matrix : BSM;
129 
130     BSM!degree r;
131     if (shift % degree == 0)
132     {
133         r = BSM!degree.I;
134     }
135     else
136     {
137         foreach (i, ref e; r)
138         {
139             e[(i + (shift % degree)) % degree] = true;
140         }
141     }
142     return PermutationElement!degree(r);
143 }
144 
145 unittest
146 {
147     import boolean_matrix : BSM;
148 
149     immutable a = PermutationElement!3(BSM!3([
150                 [true, false, false], [false, true, false], [false, false, true]
151             ]));
152     immutable b = PermutationElement!3(BSM!3([
153                 [false, true, false], [false, false, true], [true, false, false]
154             ]));
155 
156     assert(cyclicPermutation!3(0) == a);
157     assert(cyclicPermutation!3(21) == a);
158     assert(cyclicPermutation!3(1) == b);
159     assert(cyclicPermutation!3(22) == b);
160 }
161 
162 auto cyclicPermutationInv(size_t degree)(size_t shift) pure
163 {
164     import boolean_matrix : BSM;
165 
166     BSM!degree r;
167     if (shift % degree == 0)
168     {
169         r = BSM!degree.I;
170     }
171     else
172     {
173         foreach (i, ref e; r)
174         {
175             e[(i + degree - (shift % degree)) % degree] = true;
176         }
177     }
178     return PermutationElement!degree(r);
179 }
180 
181 unittest
182 {
183     import boolean_matrix : BSM;
184 
185     immutable a = PermutationElement!3(BSM!3([
186                 [true, false, false], [false, true, false], [false, false, true]
187             ]));
188     immutable b = PermutationElement!3(BSM!3([
189                 [false, false, true], [true, false, false], [false, true, false]
190             ]));
191 
192     assert(cyclicPermutationInv!3(0) == a);
193     assert(cyclicPermutationInv!3(21) == a);
194     assert(cyclicPermutationInv!3(1) == b);
195     assert(cyclicPermutationInv!3(22) == b);
196 }
197 
198 unittest
199 {
200     assert(cyclicPermutation!6(3) == cyclicPermutationInv!6(3).transpose);
201     assert(cyclicPermutation!6(51) == cyclicPermutationInv!6(51).transpose);
202     assert(cyclicPermutation!6(1).transpose == cyclicPermutationInv!6(1));
203     assert(cyclicPermutation!6(22).transpose == cyclicPermutationInv!6(22));
204 }
205 
206 auto permutation(size_t degree)(in size_t[] substitution)
207 in
208 {
209     import std.algorithm.comparison : isPermutation;
210     import std.range : iota;
211 
212     assert(degree.iota.isPermutation(substitution));
213 }
214 do
215 {
216     import boolean_matrix : BSM;
217 
218     BSM!degree p;
219     foreach (i, s; substitution)
220     {
221         p[s][i] = true;
222     }
223     return PermutationElement!degree(p);
224 }
225 
226 unittest
227 {
228     import boolean_matrix : BSM;
229 
230     immutable a = PermutationElement!3(BSM!3([
231                 [true, false, false], [false, true, false], [false, false, true]
232             ]));
233     immutable b = PermutationElement!3(BSM!3([
234                 [false, true, false], [false, false, true], [true, false, false]
235             ]));
236     immutable c = PermutationElement!3(BSM!3([
237                 [false, false, true], [false, true, false], [true, false, false]
238             ]));
239 
240     assert(permutation!3([0, 1, 2]) == a);
241     assert(permutation!3([2, 0, 1]) == b);
242     assert(permutation!3([2, 1, 0]) == c);
243 }