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 }