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 import std.traits : isInstanceOf;
118 
119 auto transpose(M)(in M a) pure if (isInstanceOf!(BSM, M))
120 {
121     import std.traits : TemplateArgsOf;
122 
123     BSM!(TemplateArgsOf!M) ta;
124     foreach (i, row; a)
125     {
126         foreach (j, e; row)
127         {
128             ta[j][i] = e;
129         }
130     }
131     return ta;
132 }
133 
134 auto isBijective(M)(in M a) pure if (isInstanceOf!(BSM, M))
135 {
136     foreach (i, ref row; a)
137     {
138         size_t k;
139 
140         foreach (e; row)
141         {
142             if (e && ++k == 2)
143             {
144                 return false;
145             }
146         }
147 
148         if (k == 0)
149         {
150             return false;
151         }
152     }
153 
154     return true;
155 }
156 
157 auto isIrreflexive(M)(in M a) pure if (isInstanceOf!(BSM, M))
158 {
159     foreach (i, row; a)
160     {
161         if (row[i])
162         {
163             return false;
164         }
165     }
166 
167     return true;
168 }
169 
170 auto isSymmetric(M)(in M a) pure if (isInstanceOf!(BSM, M))
171 {
172     foreach (i, row; a[0 .. $ - 1])
173     {
174         foreach (j, e; row[1 .. $])
175         {
176             if (row[j + 1] != e)
177             {
178                 return false;
179             }
180         }
181     }
182 
183     return true;
184 }
185 
186 auto lowerRotator(size_t n)(size_t shift) @property pure
187 {
188     BSM!n r;
189     if (shift % n == 0)
190     {
191         r = BSM!n.I;
192     }
193     else
194     {
195         foreach (i, ref e; r)
196         {
197             e[(i + n - (shift % n)) % n] = true;
198         }
199     }
200     return r;
201 }
202 
203 auto upperRotator(size_t n)(size_t shift) @property pure
204 {
205     BSM!n r;
206     if (shift % n == 0)
207     {
208         r = BSM!n.I;
209     }
210     else
211     {
212         foreach (i, ref e; r)
213         {
214             e[(i + (shift % n)) % n] = true;
215         }
216     }
217     return r;
218 }
219 
220 auto permutation(size_t N)(in size_t[] substitution)
221 in
222 {
223     import std.algorithm.comparison : isPermutation;
224     import std.range : iota;
225 
226     assert(N.iota.isPermutation(substitution));
227 }
228 body
229 {
230     BSM!N p;
231     foreach (i, s; substitution)
232     {
233         p[s][i] = true;
234     }
235     return p;
236 }