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 }