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 opMul()(in auto ref BSM!n matrix) const pure
16     {
17         import std.range : iota, transversal, zip;
18         import std.algorithm.searching : canFind;
19         import std.algorithm.mutation : copy;
20         import std.algorithm.iteration : map;
21 
22         BSM!n r;
23         foreach (i, ref row; r)
24         {
25             n.iota.map!(j => zip(s_mat[i][], matrix[].transversal(j))
26                 .canFind!"a[0]&&a[1]").copy(row[]);
27         }
28 
29         return r;
30     }
31 
32     auto opMul()(in auto ref BCV!n vector) const pure
33     {
34         import std.range : zip;
35         import std.algorithm.searching : canFind;
36         import std.algorithm.mutation : copy;
37         import std.algorithm.iteration : map;
38 
39         BCV!n r;
40         s_mat[].map!(row => zip(row[], vector[]).canFind!"a[0]&&a[1]")
41             .copy(r[]);
42 
43         return r;
44     }
45 
46     static enum I = {
47         BSM!n id;
48         foreach (i, ref row; id)
49         {
50             row[i] = true;
51         }
52         return id;
53     }();
54 }
55 
56 // boolean column vector
57 struct BCV(size_t n) if (n > 0)
58 {
59     bool[n] c_vec;
60     alias c_vec this;
61 
62     static auto e(size_t k) pure
63     in
64     {
65         assert(k < n);
66     }
67     body
68     {
69         BCV!n v;
70         v[k] = true;
71         return v;
72     }
73 }
74 
75 unittest
76 {
77     immutable a = BSM!3([[true, false, true], [true, true, false],
78         [false, false, true]]);
79     immutable b = BSM!3([[false, true, true], [true, false, false],
80         [false, false, true]]);
81     immutable c = BSM!3([[false, true, true], [true, true, true],
82         [false, false, true]]);
83 
84     assert(a * b == c);
85 }
86 
87 unittest
88 {
89     immutable a = BSM!3([[true, false, true], [true, true, false],
90         [false, false, true]]);
91     immutable b = BCV!3([true, false, false]);
92     immutable c = BCV!3([true, true, false]);
93 
94     assert(a * b == c);
95 }
96 
97 import std.traits : TemplateArgsOf, TemplateOf;
98 
99 auto transpose(M)(in M a) pure if (__traits(isSame, TemplateOf!M, BSM))
100 {
101     BSM!(TemplateArgsOf!M) ta;
102     foreach (i, row; a)
103     {
104         foreach (j, e; row)
105         {
106             ta[j][i] = e;
107         }
108     }
109     return ta;
110 }
111 
112 auto isBijective(M)(in M a) pure if (__traits(isSame, TemplateOf!M, BSM))
113 {
114     import std.algorithm.searching : all, count;
115     return a[].all!(row => row[].count!"a" == 1);
116 }
117 
118 auto isIrreflexive(M)(in M a) pure if (__traits(isSame, TemplateOf!M, BSM))
119 {
120     foreach (i, row; a)
121     {
122         if (row[i])
123         {
124             return false;
125         }
126     }
127 
128     return true;
129 }
130 
131 auto isSymmetric(M)(in M a) pure if (__traits(isSame, TemplateOf!M, BSM))
132 {
133     foreach (i, row; a[0 .. $-1])
134     {
135         foreach (j, e; row[1 .. $])
136         {
137             if (row[j+1] != e)
138             {
139                 return false;
140             }
141         }
142     }
143 
144     return true;
145 }
146 
147 auto lowerRotator(size_t n)(size_t shift) @property pure
148 {
149     BSM!n r;
150     if (shift % n == 0)
151     {
152         r = BSM!n.I;
153     }
154     else
155     {
156         foreach (i, ref e; r)
157         {
158             e[(i + n - (shift % n)) % n] = true;
159         }
160     }
161     return r;
162 }
163 
164 auto upperRotator(size_t n)(size_t shift) @property pure
165 {
166     BSM!n r;
167     if (shift % n == 0)
168     {
169         r = BSM!n.I;
170     }
171     else
172     {
173         foreach (i, ref e; r)
174         {
175             e[(i + (shift % n)) % n] = true;
176         }
177     }
178     return r;
179 }
180 
181 auto permutation(size_t N)(in size_t[] substitution)
182 in
183 {
184     import std.algorithm.comparison : isPermutation;
185     import std.range : iota;
186 
187     assert(N.iota.isPermutation(substitution));
188 }
189 body
190 {
191     BSM!N p;
192     foreach (i, s; substitution)
193     {
194         p[s][i] = true;
195     }
196     return p;
197 }