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 	this(T initNumber)
53 	in {
54 		static assert(M == N, "invalid diagonal matrix");
55 	}
56 	body {
57 		foreach(i; 0 .. M)
58 			matrix[i * M + i] = initNumber;
59 	}
60 
61 	this(immutable ref Matrix!(T, M, N) mat)
62 	{
63 		this.matrix = mat.matrix.dup;
64 	}
65 
66 	this(T[M*N] matrix)
67 	{
68 		this.matrix = matrix;
69 	}
70 
71 	this(T[] matrix)
72 	in {
73 		assert(matrix.length == M * N, "array doesn't have the same size");
74 	}
75 	body {
76 		this.matrix = matrix;
77 	}
78 
79 	pragma(inline) static Matrix!(T, M, N) zero()
80 	{
81 		Matrix!(T, M, N) ret;
82 
83 		return ret;
84 	}
85 
86 	pragma(inline) static Matrix!(T, M, N) identity()
87 	{
88 		Matrix!(T, M, N) ret;
89 		ret.setIdentity();
90 		return ret;
91 	}
92 
93 	void setIdentity()
94 	in {
95 		static assert(M == N);
96 	}
97 	body
98 	{
99 		foreach(size_t x; 0 .. M)
100 			foreach(size_t y; 0 .. N)
101 				if (y == x)
102 					matrix[x * M + y] = 1;
103 				else
104 					matrix[x * M + y] = 0;
105 	}
106 
107 	Matrix!(T, M, N) opBinary(string op)(T val)
108 	{
109 		Matrix!(T, M, N) ret;
110 		foreach(i; 0 .. M)
111 			foreach(j; 0 .. N)
112 				mixin("ret.matrix[i * M + j] = this.matrix[i * M + j] "~op~" val;");
113 		return ret;
114 	}
115 
116 	Matrix!(T, M, N) opBinaryRight(string op)(T rhs)
117 	{
118 		Matrix!(T, M, N) ret;
119 		foreach(i; 0 .. M)
120 			foreach(j; 0 .. N)
121 				mixin("ret.matrix[i * M + j] = rhs "~op~" this.matrix[i * M + j];");
122 		return ret;
123 	}
124 
125 	Matrix!(T, M, N) opBinary(string op)(Matrix!(T, M, N) val) if(op == "+" || op == "-")
126 	{
127 		Matrix!(T, M, N) ret;
128 		foreach(i; 0 .. M)
129 			foreach(j; 0 .. N)
130 				mixin("ret[i,j] = this[i,j]"~op~"val[i,j];");
131 
132 		return ret;
133 	}
134 
135 	Matrix!(T, M, N) opBinary(string op : "*")(Matrix!(T, M, N) val)
136 	{
137 		Matrix!(T, M, N) res;
138 
139 		foreach (i; 0 .. M)
140 			foreach (j; 0 .. N)
141 			{
142 				T sumProduct = 0;
143 				foreach (k; 0 .. N)
144 					sumProduct += this[i, k] * val[k, j];
145 				res[i, j] = sumProduct;
146 			}
147 
148 		return res;
149 	}
150 
151 	bool opEquals(Matrix!(T, M, N) mat) const
152 	{
153 		return matrix == mat.matrix;
154 	}
155 
156 	T opIndex(in size_t m, in size_t n) const
157 	in
158 	{
159 		assert (n < N && m < M, "index out of bounds");
160 	}
161 	body
162 	{
163 		return matrix[m * M + n];
164 	}
165 
166 	T opIndex(in size_t i) const
167 	in
168 	{
169 		assert (i < N * M, "index out of bounds");
170 	}
171 	body
172 	{
173 		return matrix[i];
174 	}
175 
176 	T opIndexAssign(in T val, in size_t m, in size_t n)
177 	in
178 	{
179 		assert (n < N && m < M, "index out of bounds");
180 	}
181 	body
182 	{
183 		return (matrix[m * M + n] = val);
184 	}
185 
186 	T[] opSliceAssign(in T val, in size_t i1, in size_t i2)
187 	in
188 	{
189 		assert (i1 < N * M && i2 < N * M, "index out of bounds");
190 	}
191 	body
192 	{
193 		return (matrix[i1..i2] = val);
194 	}
195 
196 	T[] opSliceAssign(in T val)
197 	{
198 		return (matrix[] = val);
199 	}
200 
201 	T[M*N] matrix;
202 }
203 
204 alias Matrix!(float, 2, 2) Matrix2x2f, Matrix2f, mat2;
205 alias Matrix!(float, 3, 3) Matrix3x3f, Matrix3f, mat3;
206 alias Matrix!(float, 4, 4) Matrix4x4f, Matrix4f, mat4;
207 alias Matrix!(double, 2, 2) Matrix2x2d, Matrix2d;
208 alias Matrix!(double, 3, 3) Matrix3x3d, Matrix3d;
209 alias Matrix!(double, 4, 4) Matrix4x4d, Matrix4d;
210 
211 
212 @("Matrix: Zeros")
213 @safe
214 unittest {
215 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).zero;
216 	int[3*3] matZeros =
217 		[0, 0, 0,
218 		 0, 0, 0,
219 		 0, 0, 0];
220 
221 	assert(matZeros == mat.matrix);
222 }
223 
224 @("Matrix: Identity")
225 @safe
226 unittest {
227 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).identity;
228 	int[3*3] matIdentity =
229 		[1, 0, 0,
230 		 0, 1, 0,
231 		 0, 0, 1];
232 
233 	assert(matIdentity == mat.matrix);
234 }
235 
236 
237 @("Matrix: Add operation")
238 @safe
239 unittest {
240 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).identity;
241 	int[3 * 3] matAdd =
242 		[2, 1, 1,
243 		 1, 2, 1,
244 		 1, 1, 2];
245 
246 	assert(matAdd == (mat + 1).matrix);
247 }
248 
249 
250 @("Matrix: Subtract operation")
251 @safe
252 unittest {
253 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).identity;
254 	int[3 * 3] matSub =
255 		[0, -1, -1,
256 		 -1, 0, -1,
257 		 -1, -1, 0];
258 
259 	assert(matSub == (mat - 1).matrix);
260 }
261 
262 
263 @("Matrix: Multiplication operation")
264 @safe
265 unittest {
266 	Matrix!(int, 3, 3) mat = Matrix!(int, 3, 3).identity;
267 	int[3 * 3] matMul =
268 		[2, 0, 0,
269 		 0, 2, 0,
270 		 0, 0, 2];
271 
272 	assert(matMul == (2 * mat).matrix);
273 }
274 
275 @("Matrix: Change val index")
276 @safe
277 unittest {
278 	Matrix2x2f mat = Matrix2x2f.identity;
279 	mat[0, 0] = 2.0f;
280 
281 	float[2 * 2] matIndex =
282 		[2.0f, 0.0f,
283 		 0.0f, 1.0f];
284 
285 	assert(matIndex == mat.matrix);
286 }
287 
288 @("Matrix: Access val index")
289 @safe
290 unittest {
291 	Matrix2x2d mat = Matrix2x2d.identity;
292 
293 	assert(1.0 == mat[1,1]);
294 	assert(0.0 == mat[0,1]);
295 }