1 /*
2                                     __
3                                    / _|
4   __ _ _   _ _ __ ___  _ __ __ _  | |_ ___  ___ ___
5  / _` | | | | '__/ _ \| '__/ _` | |  _/ _ \/ __/ __|
6 | (_| | |_| | | | (_) | | | (_| | | || (_) \__ \__ \
7  \__,_|\__,_|_|  \___/|_|  \__,_| |_| \___/|___/___/
8 
9 Copyright (C) 2018-2019 Aurora Free Open Source Software.
10 
11 This file is part of the Aurora Free Open Source Software. This
12 organization promote free and open source software that you can
13 redistribute and/or modify under the terms of the GNU Lesser General
14 Public License Version 3 as published by the Free Software Foundation or
15 (at your option) any later version approved by the Aurora Free Open Source
16 Software Organization. The license is available in the package root path
17 as 'LICENSE' file. Please review the following information to ensure the
18 GNU Lesser General Public License version 3 requirements will be met:
19 https://www.gnu.org/licenses/lgpl.html .
20 
21 Alternatively, this file may be used under the terms of the GNU General
22 Public License version 3 or later as published by the Free Software
23 Foundation. Please review the following information to ensure the GNU
24 General Public License requirements will be met:
25 http://www.gnu.org/licenses/gpl-3.0.html.
26 
27 NOTE: All products, services or anything associated to trademarks and
28 service marks used or referenced on this file are the property of their
29 respective companies/owners or its subsidiaries. Other names and brands
30 may be claimed as the property of others.
31 
32 For more info about intellectual property visit: aurorafoss.org or
33 directly send an email to: contact (at) aurorafoss.org .
34 */
35 
36 module aurorafw.math.matrix;
37 
38 //FIXME: Fix documentation
39 
40 /** @file aurorafw/math/matrix.d
41  * Variable Matrix file. This contains a variable matrix struct that
42  * represents a grid with size of M * N.
43  * @author Luís Ferreira <contact@lsferreira.net>
44  * @since snapshot20180509
45  */
46 
47 /** A struct that represents a variable matrix. A struct that store's
48  * N*M array, allows to manipulate it.
49  * @since snapshot20180930
50  */
51 @nogc pure @safe struct Matrix(T, size_t M, size_t N)
52 {
53 	this(T initNumber)
54 	in
55 	{
56 		static assert(M == N, "invalid diagonal matrix");
57 	}
58 	do
59 	{
60 		foreach (i; 0 .. M)
61 			matrix[i * M + i] = initNumber;
62 	}
63 
64 	this(immutable ref Matrix!(T, M, N) mat)
65 	{
66 		this.matrix = mat.matrix.dup;
67 	}
68 
69 	this(T[M * N] matrix)
70 	{
71 		this.matrix = matrix;
72 	}
73 
74 	this(T[] matrix)
75 	in
76 	{
77 		assert(matrix.length == M * N, "array doesn't have the same size");
78 	}
79 	do
80 	{
81 		this.matrix = matrix;
82 	}
83 
84 	pragma(inline) static Matrix!(T, M, N) zero()
85 	{
86 		Matrix!(T, M, N) ret;
87 
88 		return ret;
89 	}
90 
91 	pragma(inline) static Matrix!(T, M, N) identity()
92 	{
93 		Matrix!(T, M, N) ret;
94 		ret.setIdentity();
95 		return ret;
96 	}
97 
98 	void setIdentity()
99 	in
100 	{
101 		static assert(M == N);
102 	}
103 	do
104 	{
105 		foreach (size_t x; 0 .. M)
106 			foreach (size_t y; 0 .. N)
107 				if (y == x)
108 					matrix[x * M + y] = 1;
109 				else
110 					matrix[x * M + y] = 0;
111 	}
112 
113 	Matrix!(T, M, N) opBinary(string op)(T val)
114 	{
115 		Matrix!(T, M, N) ret;
116 		foreach (i; 0 .. M)
117 			foreach (j; 0 .. N)
118 				mixin("ret.matrix[i * M + j] = this.matrix[i * M + j] " ~ op ~ " val;");
119 		return ret;
120 	}
121 
122 	Matrix!(T, M, N) opBinaryRight(string op)(T rhs)
123 	{
124 		Matrix!(T, M, N) ret;
125 		foreach (i; 0 .. M)
126 			foreach (j; 0 .. N)
127 				mixin("ret.matrix[i * M + j] = rhs " ~ op ~ " this.matrix[i * M + j];");
128 		return ret;
129 	}
130 
131 	Matrix!(T, M, N) opBinary(string op)(Matrix!(T, M, N) val) if (op == "+" || op == "-")
132 	{
133 		Matrix!(T, M, N) ret;
134 		foreach (i; 0 .. M)
135 			foreach (j; 0 .. N)
136 				mixin("ret[i,j] = this[i,j]" ~ op ~ "val[i,j];");
137 
138 		return ret;
139 	}
140 
141 	Matrix!(T, M, N) opBinary(string op : "*")(Matrix!(T, M, N) val)
142 	{
143 		Matrix!(T, M, N) res;
144 
145 		foreach (i; 0 .. M)
146 			foreach (j; 0 .. N)
147 			{
148 				T sumProduct = 0;
149 				foreach (k; 0 .. N)
150 					sumProduct += this[i, k] * val[k, j];
151 				res[i, j] = sumProduct;
152 			}
153 
154 		return res;
155 	}
156 
157 	bool opEquals(Matrix!(T, M, N) mat) const
158 	{
159 		return matrix == mat.matrix;
160 	}
161 
162 	T opIndex(in size_t m, in size_t n) const
163 	in
164 	{
165 		assert(n < N && m < M, "index out of bounds");
166 	}
167 	do
168 	{
169 		return matrix[m * M + n];
170 	}
171 
172 	T opIndex(in size_t i) const
173 	in
174 	{
175 		assert(i < N * M, "index out of bounds");
176 	}
177 	do
178 	{
179 		return matrix[i];
180 	}
181 
182 	T opIndexAssign(in T val, in size_t m, in size_t n)
183 	in
184 	{
185 		assert(n < N && m < M, "index out of bounds");
186 	}
187 	do
188 	{
189 		return (matrix[m * M + n] = val);
190 	}
191 
192 	T[] opSliceAssign(in T val, in size_t i1, in size_t i2)
193 	in
194 	{
195 		assert(i1 < N * M && i2 < N * M, "index out of bounds");
196 	}
197 	do
198 	{
199 		return (matrix[i1 .. i2] = val);
200 	}
201 
202 	T[] opSliceAssign(in T val)
203 	{
204 		return (matrix[] = val);
205 	}
206 
207 	T[M * N] matrix;
208 }
209 
210 alias Matrix2x2f = Matrix!(float, 2, 2), Matrix2f = Matrix!(float, 2, 2), mat2 = Matrix!(float, 2, 2);
211 alias Matrix3x3f = Matrix!(float, 3, 3), Matrix3f = Matrix!(float, 3, 3), mat3 = Matrix!(float, 3, 3);
212 alias Matrix4x4f = Matrix!(float, 4, 4), Matrix4f = Matrix!(float, 4, 4), mat4 = Matrix!(float, 4, 4);
213 alias Matrix2x2d = Matrix!(double, 2, 2), Matrix2d = Matrix!(double, 2, 2);
214 alias Matrix3x3d = Matrix!(double, 3, 3), Matrix3d = Matrix!(double, 3, 3);
215 alias Matrix4x4d = Matrix!(double, 4, 4), Matrix4d = Matrix!(double, 4, 4);
216 
217 @("Matrix: Zeros")
218 @safe
219 unittest
220 {
221 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).zero;
222 	int[3 * 3] matZeros =
223 		[0, 0, 0,
224 			0, 0, 0,
225 			0, 0, 0];
226 
227 	assert(matZeros == mat.matrix);
228 }
229 
230 @("Matrix: Identity")
231 @safe
232 unittest
233 {
234 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).identity;
235 	int[3 * 3] matIdentity =
236 		[1, 0, 0,
237 			0, 1, 0,
238 			0, 0, 1];
239 
240 	assert(matIdentity == mat.matrix);
241 }
242 
243 @("Matrix: Add operation")
244 @safe
245 unittest
246 {
247 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).identity;
248 	int[3 * 3] matAdd =
249 		[2, 1, 1,
250 			1, 2, 1,
251 			1, 1, 2];
252 
253 	assert(matAdd == (mat + 1).matrix);
254 }
255 
256 @("Matrix: Subtract operation")
257 @safe
258 unittest
259 {
260 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).identity;
261 	int[3 * 3] matSub =
262 		[0, -1, -1,
263 			-1, 0, -1,
264 			-1, -1, 0];
265 
266 	assert(matSub == (mat - 1).matrix);
267 }
268 
269 @("Matrix: Multiplication operation")
270 @safe
271 unittest
272 {
273 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).identity;
274 	int[3 * 3] matMul =
275 		[2, 0, 0,
276 			0, 2, 0,
277 			0, 0, 2];
278 
279 	assert(matMul == (2 * mat).matrix);
280 }
281 
282 @("Matrix: Change val index")
283 @safe
284 unittest
285 {
286 	Matrix2x2f mat = Matrix2x2f.identity;
287 	mat[0, 0] = 2.0f;
288 
289 	float[2 * 2] matIndex =
290 		[2.0f, 0.0f,
291 			0.0f, 1.0f];
292 
293 	assert(matIndex == mat.matrix);
294 }
295 
296 @("Matrix: Access val index")
297 @safe
298 unittest
299 {
300 	Matrix2x2d mat = Matrix2x2d.identity;
301 
302 	assert(1.0 == mat[1, 1]);
303 	assert(0.0 == mat[0, 1]);
304 }