1 /*
2 Copyright electrolysis 2016.
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 boolean_matrix;
8 
9 // boolean square matrix
10 struct BSM(size_t n) if (n > 0)
11 {
12     bool[n][n] s_mat;
13     alias s_mat this;
14 
15     auto opBinary(string op)(in auto ref BSM!n matrix) const pure
16     {
17         static if (op == "*")
18         {
19             BSM!n r;
20 
21             foreach (i, ref row; s_mat)
22             {
23                 foreach (j, e; row)
24                 {
25                     if (e)
26                     {
27                         r[i][] |= matrix[j][];
28                     }
29                 }
30             }
31 
32             return r;
33         }
34         else
35         {
36             static assert(0, `Operator '` ~ op ~ `' is not implemented.`);
37         }
38     }
39 
40     auto opBinary(string op)(in auto ref BCV!n vector) const pure
41     {
42         static if (op == "*")
43         {
44             BCV!n r;
45 
46             foreach (i, ref row; s_mat)
47             {
48                 foreach (j, e; row)
49                 {
50                     if (e && vector[j])
51                     {
52                         r[i] = true;
53                         break;
54                     }
55                 }
56             }
57 
58             return r;
59         }
60         else
61         {
62             static assert(0, `Operator '` ~ op ~ `' is not implemented.`);
63         }
64     }
65 
66     static enum I = {
67         BSM!n id;
68         foreach (i, ref row; id)
69         {
70             row[i] = true;
71         }
72         return id;
73     }();
74 }
75 
76 // boolean column vector
77 struct BCV(size_t n) if (n > 0)
78 {
79     bool[n] c_vec;
80     alias c_vec this;
81 
82     static auto e(size_t k) pure
83     in
84     {
85         assert(k < n);
86     }
87     body
88     {
89         BCV!n v;
90         v[k] = true;
91         return v;
92     }
93 }
94 
95 unittest
96 {
97     immutable a = BSM!3([[true, false, true], [true, true, false],
98         [false, false, true]]);
99     immutable b = BSM!3([[false, true, true], [true, false, false],
100         [false, false, true]]);
101     immutable c = BSM!3([[false, true, true], [true, true, true],
102         [false, false, true]]);
103 
104     assert(a * b == c);
105 }
106 
107 unittest
108 {
109     immutable a = BSM!3([[true, false, true], [true, true, false],
110         [false, false, true]]);
111     immutable b = BCV!3([true, false, false]);
112     immutable c = BCV!3([true, true, false]);
113 
114     assert(a * b == c);
115 }
116 
117 unittest
118 {
119     immutable a = BCV!3([false, true, false]);
120 
121     assert(BCV!3.e(1) == a);
122 }
123 
124 import std.traits : isInstanceOf;
125 
126 auto transpose(M)(in M a) pure if (isInstanceOf!(BSM, M))
127 {
128     import std.traits : TemplateArgsOf;
129 
130     BSM!(TemplateArgsOf!M) ta;
131     foreach (i, row; a)
132     {
133         foreach (j, e; row)
134         {
135             ta[j][i] = e;
136         }
137     }
138     return ta;
139 }
140 
141 unittest
142 {
143     immutable a = BSM!3([[false, true, false], [false, true, true],
144         [true, false, false]]);
145     immutable b = BSM!3([[false, false, true], [true, true, false],
146         [false, true, false]]);
147 
148     assert(transpose(a) == b);
149 }
150 
151 auto isBijective(M)(in M a) pure if (isInstanceOf!(BSM, M))
152 {
153     foreach (i, ref row; a)
154     {
155         size_t k;
156 
157         foreach (j, e; row)
158         {
159             if (e)
160             {
161                 if (++k == 2)
162                 {
163                     return false;
164                 }
165                 else
166                 {
167                     foreach (ref row2; a[i + 1 .. $])
168                     {
169                         if (row2[j])
170                         {
171                             return false;
172                         }
173                     }
174                 }
175             }
176         }
177 
178         if (k == 0)
179         {
180             return false;
181         }
182     }
183 
184     return true;
185 }
186 
187 unittest
188 {
189     immutable a = BSM!3([[true, false, false], [false, false, true],
190         [false, true, false]]);
191     immutable b = BSM!3([[false, false, true], [false, false, true],
192         [true, true, false]]);
193     immutable c = BSM!3([[true, false, true], [false, true, false],
194         [false, false, false]]);
195     immutable d = BSM!3([[false, false, false], [false, true, false],
196         [false, false, false]]);
197 
198     assert(isBijective(a));
199     assert(!isBijective(b));
200     assert(!isBijective(c));
201     assert(!isBijective(d));
202 }
203 
204 auto isIrreflexive(M)(in M a) pure if (isInstanceOf!(BSM, M))
205 {
206     foreach (i, ref row; a)
207     {
208         if (row[i])
209         {
210             return false;
211         }
212     }
213 
214     return true;
215 }
216 
217 unittest
218 {
219     immutable a = BSM!3([[false, false, true], [false, false, true],
220         [true, true, false]]);
221     immutable b = BSM!3([[true, false, true], [false, false, true],
222         [true, false, false]]);
223 
224     assert(isIrreflexive(a));
225     assert(!isIrreflexive(b));
226 }
227 
228 auto isSymmetric(M)(in M a) pure if (isInstanceOf!(BSM, M))
229 {
230     foreach (i, ref row; a[0 .. $ - 1])
231     {
232         foreach (j, e; row[i + 1 .. $])
233         {
234             if (a[i + j + 1][i] != e)
235             {
236                 return false;
237             }
238         }
239     }
240 
241     return true;
242 }
243 
244 unittest
245 {
246     immutable a = BSM!3([[true, false, true], [false, false, true],
247         [true, true, false]]);
248     immutable b = BSM!3([[true, false, true], [false, false, true],
249         [true, false, false]]);
250 
251     assert(isSymmetric(a));
252     assert(!isSymmetric(b));
253 }
254 
255 auto cyclicPermutation(size_t n)(size_t shift) @property pure
256 {
257     BSM!n r;
258     if (shift % n == 0)
259     {
260         r = BSM!n.I;
261     }
262     else
263     {
264         foreach (i, ref e; r)
265         {
266             e[(i + (shift % n)) % n] = true;
267         }
268     }
269     return r;
270 }
271 
272 unittest
273 {
274     immutable a = BSM!3([[true, false, false], [false, true, false],
275         [false, false, true]]);
276     immutable b = BSM!3([[false, true, false], [false, false, true],
277         [true, false, false]]);
278 
279     assert(cyclicPermutation!3(0) == a);
280     assert(cyclicPermutation!3(21) == a);
281     assert(cyclicPermutation!3(1) == b);
282     assert(cyclicPermutation!3(22) == b);
283 }
284 
285 auto cyclicPermutationInv(size_t n)(size_t shift) @property pure
286 {
287     BSM!n r;
288     if (shift % n == 0)
289     {
290         r = BSM!n.I;
291     }
292     else
293     {
294         foreach (i, ref e; r)
295         {
296             e[(i + n - (shift % n)) % n] = true;
297         }
298     }
299     return r;
300 }
301 
302 unittest
303 {
304     immutable a = BSM!3([[true, false, false], [false, true, false],
305         [false, false, true]]);
306     immutable b = BSM!3([[false, false, true], [true, false, false],
307         [false, true, false]]);
308 
309     assert(cyclicPermutationInv!3(0) == a);
310     assert(cyclicPermutationInv!3(21) == a);
311     assert(cyclicPermutationInv!3(1) == b);
312     assert(cyclicPermutationInv!3(22) == b);
313 }
314 
315 auto permutation(size_t N)(in size_t[] substitution)
316 in
317 {
318     import std.algorithm.comparison : isPermutation;
319     import std.range : iota;
320 
321     assert(N.iota.isPermutation(substitution));
322 }
323 body
324 {
325     BSM!N p;
326     foreach (i, s; substitution)
327     {
328         p[s][i] = true;
329     }
330     return p;
331 }
332 
333 unittest
334 {
335     immutable a = BSM!3([[true, false, false], [false, true, false],
336         [false, false, true]]);
337     immutable b = BSM!3([[false, true, false], [false, false, true],
338         [true, false, false]]);
339     immutable c = BSM!3([[false, false, true], [false, true, false],
340         [true, false, false]]);
341 
342     assert(permutation!3([0, 1, 2]) == a);
343     assert(permutation!3([2, 0, 1]) == b);
344     assert(permutation!3([2, 1, 0]) == c);
345 }