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