1 /*
2 Copyright Kazuya Takahashi 2016-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 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     do
88     {
89         BCV!n v;
90         v[k] = true;
91         return v;
92     }
93 }
94 
95 unittest
96 {
97     immutable a = BSM!3([
98             [true, false, true], [true, true, false], [false, false, true]
99             ]);
100     immutable b = BSM!3([
101             [false, true, true], [true, false, false], [false, false, true]
102             ]);
103     immutable c = BSM!3([
104             [false, true, true], [true, true, true], [false, false, true]
105             ]);
106 
107     assert(a * b == c);
108 }
109 
110 unittest
111 {
112     immutable a = BSM!3([
113             [true, false, true], [true, true, false], [false, false, true]
114             ]);
115     immutable b = BCV!3([true, false, false]);
116     immutable c = BCV!3([true, true, false]);
117 
118     assert(a * b == c);
119 }
120 
121 unittest
122 {
123     immutable a = BCV!3([false, true, false]);
124 
125     assert(BCV!3.e(1) == a);
126 }
127 
128 import std.traits : isInstanceOf;
129 
130 auto transpose(M)(in M a) pure if (isInstanceOf!(BSM, M))
131 {
132     import std.traits : TemplateArgsOf;
133 
134     BSM!(TemplateArgsOf!M) ta;
135     foreach (i, row; a)
136     {
137         foreach (j, e; row)
138         {
139             ta[j][i] = e;
140         }
141     }
142     return ta;
143 }
144 
145 unittest
146 {
147     immutable a = BSM!3([
148             [false, true, false], [false, true, true], [true, false, false]
149             ]);
150     immutable b = BSM!3([
151             [false, false, true], [true, true, false], [false, true, false]
152             ]);
153 
154     assert(transpose(a) == b);
155 }
156 
157 auto isBijective(M)(in M a) pure if (isInstanceOf!(BSM, M))
158 {
159     foreach (i, ref row; a)
160     {
161         size_t k;
162 
163         foreach (j, e; row)
164         {
165             if (e)
166             {
167                 if (++k == 2)
168                 {
169                     return false;
170                 }
171                 else
172                 {
173                     foreach (ref row2; a[i + 1 .. $])
174                     {
175                         if (row2[j])
176                         {
177                             return false;
178                         }
179                     }
180                 }
181             }
182         }
183 
184         if (k == 0)
185         {
186             return false;
187         }
188     }
189 
190     return true;
191 }
192 
193 unittest
194 {
195     immutable a = BSM!3([
196             [true, false, false], [false, false, true], [false, true, false]
197             ]);
198     immutable b = BSM!3([
199             [false, false, true], [false, false, true], [true, true, false]
200             ]);
201     immutable c = BSM!3([
202             [true, false, true], [false, true, false], [false, false, false]
203             ]);
204     immutable d = BSM!3([
205             [false, false, false], [false, true, false], [false, false, false]
206             ]);
207 
208     assert(isBijective(a));
209     assert(!isBijective(b));
210     assert(!isBijective(c));
211     assert(!isBijective(d));
212 }
213 
214 auto isIrreflexive(M)(in M a) pure if (isInstanceOf!(BSM, M))
215 {
216     foreach (i, ref row; a)
217     {
218         if (row[i])
219         {
220             return false;
221         }
222     }
223 
224     return true;
225 }
226 
227 unittest
228 {
229     immutable a = BSM!3([
230             [false, false, true], [false, false, true], [true, true, false]
231             ]);
232     immutable b = BSM!3([
233             [true, false, true], [false, false, true], [true, false, false]
234             ]);
235 
236     assert(isIrreflexive(a));
237     assert(!isIrreflexive(b));
238 }
239 
240 auto isSymmetric(M)(in M a) pure if (isInstanceOf!(BSM, M))
241 {
242     foreach (i, ref row; a[0 .. $ - 1])
243     {
244         foreach (j, e; row[i + 1 .. $])
245         {
246             if (a[i + j + 1][i] != e)
247             {
248                 return false;
249             }
250         }
251     }
252 
253     return true;
254 }
255 
256 unittest
257 {
258     immutable a = BSM!3([
259             [true, false, true], [false, false, true], [true, true, false]
260             ]);
261     immutable b = BSM!3([
262             [true, false, true], [false, false, true], [true, false, false]
263             ]);
264 
265     assert(isSymmetric(a));
266     assert(!isSymmetric(b));
267 }