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 }