1 module matte.matrix; 2 3 import std.conv; 4 5 /** 6 * Creates a matrix with the given data 7 */ 8 Matrix!T matrix(T = float)(T[][] data) 9 in 10 { 11 assert(data.length > 0); 12 assert(data[0].length > 0); 13 } 14 body 15 { 16 auto mat = Matrix!T(data.length, data[0].length); 17 18 for(size_t i = 0; i < data.length; i++) 19 { 20 assert(data[i].length == data[0].length); 21 mat.data[i * mat.columns .. (i + 1) * mat.columns] = data[i][]; 22 } 23 24 return mat; 25 } 26 27 /** 28 * Creates a vector with the given number of dimensions. 29 */ 30 Matrix!T vector(T = float)(size_t dims) 31 { 32 return Matrix!T(dims, 1); 33 } 34 35 /** 36 * Creates an identity matrix of the given size. 37 */ 38 Matrix!T identity(T = float)(size_t size) 39 { 40 auto mat = Matrix!T(size, size); 41 42 for(size_t i = 0; i < size; i++) 43 { 44 mat[i, i] = 1; 45 } 46 47 return mat; 48 } 49 50 /** 51 * Creates a matrix full of zeros. 52 */ 53 Matrix!T zeros(T = float)(size_t numRows, size_t numColumns) 54 { 55 return Matrix!T(numRows, numColumns); 56 } 57 58 /** 59 * Creates a matrix full of ones. 60 */ 61 Matrix!T ones(T = float)(size_t numRows, size_t numColumns) 62 { 63 auto mat = Matrix!T(numRows, numColumns); 64 mat.elements[] = 1; 65 66 return mat; 67 } 68 69 struct Matrix(T) 70 { 71 public 72 { 73 this(size_t numRows, size_t numColumns) 74 in 75 { 76 assert(numRows > 0); 77 assert(numColumns > 0); 78 } 79 body 80 { 81 this.numRows = numRows; 82 this.numColumns = numColumns; 83 elements = new T[numRows * numColumns]; 84 elements[] = 0; 85 } 86 87 Matrix!T opBinary(string op)(Matrix!T rhs) 88 { 89 static if(op == "+" || op == "-") 90 { 91 assert(rhs.rows == numRows); 92 assert(rhs.columns == numColumns); 93 94 Matrix!T result = Matrix!T(numRows, numColumns); 95 mixin("result.elements[] = elements[] " ~ op ~ "rhs.elements[];"); 96 97 return result; 98 } 99 else static if(op == "*") 100 { 101 assert(numColumns == rhs.rows); 102 103 Matrix!T result = Matrix!T(numRows, rhs.columns); 104 105 for(size_t j = 0; j < result.rows; j++) 106 { 107 for(size_t i = 0; i < result.columns; i++) 108 { 109 result[j, i] = 0; 110 111 for(size_t k = 0; k < numColumns; k++) 112 { 113 result[j, i] = result[j, i] + this[j, k] * rhs[k, i]; 114 } 115 } 116 } 117 118 return result; 119 } 120 else 121 { 122 static assert(0); 123 } 124 } 125 126 Matrix!T opBinary(string op)(T scalar) 127 { 128 static if(op == "*") 129 { 130 Matrix!T result = Matrix!T(numRows, numColumns); 131 result.elements[] = elements[] * scalar; 132 133 return result; 134 } 135 else 136 { 137 static assert(0); 138 } 139 } 140 141 Matrix!T opBinaryRight(string op)(T scalar) 142 { 143 static if(op == "*") 144 { 145 return this * scalar; 146 } 147 else 148 { 149 static assert(0); 150 } 151 } 152 153 T opIndex(size_t j, size_t i) 154 in 155 { 156 assert(j < numRows); 157 assert(i < numColumns); 158 } 159 body 160 { 161 return elements[j * numColumns + i]; 162 } 163 164 T opIndexAssign(T value, size_t j, size_t i) 165 in 166 { 167 assert(j < numRows); 168 assert(i < numColumns); 169 } 170 body 171 { 172 return elements[j * numColumns + i] = value; 173 } 174 175 string toString() 176 { 177 string result; 178 179 for(size_t j = 0; j < numRows; j++) 180 { 181 for(size_t i = 0; i < numColumns; i++) 182 { 183 result ~= this[j, i].to!string; 184 185 if(i == (numColumns - 1)) 186 { 187 result ~= "\n"; 188 } 189 else 190 { 191 result ~= "\t"; 192 } 193 } 194 } 195 196 return result; 197 } 198 199 @property size_t rows() 200 { 201 return numRows; 202 } 203 204 @property size_t columns() 205 { 206 return numColumns; 207 } 208 209 @property float[] data() 210 { 211 return elements; 212 } 213 214 @property bool isSquare() 215 { 216 return numRows == numColumns; 217 } 218 219 @property Matrix!T transpose() 220 { 221 auto t = Matrix!T(numColumns, numRows); 222 223 for(size_t j = 0; j < numRows; j++) 224 { 225 for(size_t i = 0; i < numColumns; i++) 226 { 227 t[i, j] = this[j, i]; 228 } 229 } 230 231 return t; 232 } 233 234 @property T trace() 235 { 236 assert(numRows == numColumns); 237 238 T result = 0; 239 240 for(size_t i = 0; i < numRows; i++) 241 { 242 result += this[i, i]; 243 } 244 245 return result; 246 } 247 } 248 249 private 250 { 251 size_t numColumns; 252 size_t numRows; 253 T[] elements; 254 } 255 }