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 /** @file aurorafw/math/matrix.d
39  * Variable Matrix file. This contains a variable matrix struct that
40  * represents a grid with size of M * N.
41  * @author Luís Ferreira <contact@lsferreira.net>
42  * @since snapshot20180509
43  */
44 
45 /** A struct that represents a variable matrix. A struct that store's
46  * N*M array, allows to manipulate it.
47  * @since snapshot20180930
48  */
49 @nogc pure @safe struct mat(T, size_t M, size_t N) {
50 	this(T num)
51 	in {
52 		static assert(M == N, "invalid diagonal matrix");
53 	}
54 	body {
55 		foreach(size_t i; 0..M)
56 			matrix[i * M + i] = num;
57 	}
58 
59 	this(immutable ref mat!(T, M, N) mat)
60 	{
61 		this = mat;
62 	}
63 
64 	this(T[M*N] arr)
65 	{
66 		matrix = arr;
67 	}
68 
69 	this(T[] arr)
70 	in {
71 		assert(arr.length == M * N, "array doesn't have the same size");
72 	}
73 	body {
74 		matrix = arr;
75 	}
76 
77 	pragma(inline) static mat!(T, M, N) zero()
78 	{
79 		mat!(T, M, N) ret;
80 		ret.matrix[0..N*M] = 0;
81 		return ret;
82 	}
83 
84 	pragma(inline) static mat!(T, M, N) identity()
85 	{
86 		mat!(T, M, N) ret;
87 		ret.setIdentity();
88 		return ret;
89 	}
90 
91 	void setIdentity() @property
92 	{
93 		foreach(size_t x; 0 .. M)
94 			foreach(size_t y; 0 .. N)
95 				if (y == x)
96 					matrix[x * M + y] = 1;
97 				else
98 					matrix[x * M + y] = 0;
99 	}
100 
101 	bool opEquals(mat!(T, M, N) mat) const
102 	{
103 		return matrix == mat.matrix;
104 	}
105 
106 	T opIndex(in size_t m, in size_t n) const
107 	in
108 	{
109 		assert (n < N && m < M, "index out of bounds");
110 	}
111 	body
112 	{
113 		return matrix[m * M + n];
114 	}
115 
116 	T opIndex(in size_t i) const
117 	in
118 	{
119 		assert (i < N * M, "index out of bounds");
120 	}
121 	body
122 	{
123 		return matrix[i];
124 	}
125 
126 	T opIndexAssign(in T val, in size_t m, in size_t n)
127 	in
128 	{
129 		assert (n < N && m < M, "index out of bounds");
130 	}
131 	body
132 	{
133 		return (matrix[m * M + n] = val);
134 	}
135 
136 	T[] opSliceAssign(in T val, in size_t i1, in size_t i2)
137 	in
138 	{
139 		assert (i1 < N * M && i2 < N * M, "index out of bounds");
140 	}
141 	body
142 	{
143 		return (matrix[i1..i2] = val);
144 	}
145 
146 	T[] opSliceAssign(in T val)
147 	{
148 		return (matrix[] = val);
149 	}
150 
151 	mat!(T, M, N) opAdd(mat!(T, M, N) val)
152 	{
153 		auto res = mat!(T, M, N)();
154 		foreach(i; 0 .. M)
155 			foreach(j; 0 .. N)
156 				res[i, j] = this[i, j] + val[i, j];
157 
158 		return res;
159 	}
160 
161 	mat!(T, M, N) opSub(mat!(T, M, N) val)
162 	{
163 		auto res = mat!(T, M, N)();
164 		foreach(i; 0 .. M)
165 			foreach(j; 0 .. N)
166 				res[i, j] = this[i, j] - val[i, j];
167 
168 		return res;
169 	}
170 
171 	mat!(T, M, N) opMul(mat!(T, M, N) val)
172 	{
173 		auto res = mat!(T, M, N)();
174 
175 		foreach (i; 0 .. M)
176 			foreach (j; 0 .. N)
177 			{
178 				T sumProduct = 0;
179 				foreach (k; 0 .. N)
180 					sumProduct += this[i, k] * val[k, j];
181 				res[i, j] = sumProduct;
182 			}
183 
184 		return res;
185 	}
186 
187 	mat!(T, M, N) opAddAssign(mat!(T, M, N) val)
188 	{
189 		this += val;
190 		return this;
191 	}
192 
193 	mat!(T, M, N) opSubAssign(mat!(T, M, N) val)
194 	{
195 		this -= val;
196 		return this;
197 	}
198 
199 	mat!(T, M, N) opMulAssign(mat!(T, M, N) val)
200 	{
201 		this *= val;
202 		return this;
203 	}
204 
205 	mat!(T, M, N) opMul(T val)
206 	{
207 		auto res = mat!(T, M, N)();
208 		foreach(i, v; matrix)
209 			res.matrix[i] = v * val;
210 		return res;
211 	}
212 
213 	mat!(T, M, N) opMulAssign(T val)
214 	{
215 		foreach(ref v; matrix)
216 			v*= val;
217 		return this;
218 	}
219 
220 	T[M*N] matrix;
221 }
222 
223 alias mat!(float, 2, 2) Matrix2x2f, Matrix2f, mat2;
224 alias mat!(float, 3, 3) Matrix3x3f, Matrix3f, mat3;
225 alias mat!(float, 4, 4) Matrix4x4f, Matrix4f, mat4;
226 alias mat!(double, 2, 2) Matrix2x2d, Matrix2d;
227 alias mat!(double, 3, 3) Matrix3x3d, Matrix3d;
228 alias mat!(double, 4, 4) Matrix4x4d, Matrix4d;