1 /** 2 * Matrix 3 */ 4 module d2d.math.Matrix; 5 6 import std.algorithm; 7 import std.array; 8 import std.math; 9 import std.parallelism; 10 import d2d.math; 11 12 /** 13 * A matrix is just like a mathematical matrix where it is similar to essentially a 2d array of of the given type 14 * Template parameters are the type, how many rows, and how many columns 15 * TODO: rref, frustums, transformations 16 */ 17 class Matrix(T, uint rows, uint columns) { 18 19 T[columns][rows] elements; ///The elements of the matrix; stored as an array of rows (i.e. row vectors) 20 21 /** 22 * Recursively finds the determinant of the matrix if the matrix is square 23 * Task is done in O(n!) for an nxn matrix, so determinants of matrices of at most size 3x3 are already defined to be more efficient 24 * Not very efficient for large matrices 25 */ 26 static if (rows == columns) { 27 @property T determinant() { 28 //Degenerate cases: 29 static if (rows == 1) { 30 return elements.front.front; 31 } 32 else static if (rows == 2) { 33 return elements[0][0] * elements[1][1] - elements[0][1] * elements[1][0]; 34 } 35 else static if (rows == 3) { 36 return elements[0][0] * elements[1][1] * elements[2][2] 37 + elements[0][1] * elements[1][2] * elements[2][0] 38 + elements[0][2] * elements[1][0] * elements[2][1] 39 - elements[0][2] * elements[1][1] * elements[2][0] 40 - elements[0][1] * elements[1][0] * elements[2][2] 41 - elements[0][0] * elements[1][2] * elements[2][1]; 42 } 43 else { 44 T determinant; 45 foreach (i; 0 .. columns) { 46 determinant += (-1).pow(i) * this.elements[0][i] * (new Matrix!(T, 47 rows - 1, columns - 1)(this.elements[1 .. $].map!(a => a[0 .. i] ~ a[i + 1 .. $]) 48 .array).determinant); 49 } 50 return determinant; 51 } 52 } 53 } 54 55 /** 56 * Constructs a matrix from a two-dimensional array of elements 57 */ 58 this(T[][] elements) { 59 foreach (i, row; elements) { 60 foreach (j, element; row) { 61 this.elements[i][j] = element; 62 } 63 } 64 } 65 66 /** 67 * Constructs a matrix from a two-dimensional array of elements 68 */ 69 this(T[columns][rows] elements) { 70 this.elements = elements; 71 } 72 73 /** 74 * Constructs a matrix that is identically one value 75 */ 76 this(T element) { 77 T[columns] row = element; 78 this.elements[] = row; 79 } 80 81 /** 82 * Constructs a matrix as an identity matrix 83 */ 84 this() { 85 T[rows][columns] elements; 86 foreach (index, ref element; (cast(T[]) elements).parallel) { 87 elements[index][index] = 1; 88 } 89 } 90 91 /** 92 * Copy constructor for a matrix; creates a copy of the given matrix 93 */ 94 this(Matrix!(T, rows, columns) toCopy) { 95 this(toCopy.elements); 96 } 97 98 /** 99 * Sets the nth row of the matrix 100 */ 101 void setRow(uint index, Vector!(T, columns) r) { 102 this.elements[index] = r.components; 103 } 104 105 /** 106 * Returns the nth row of the matrix 107 */ 108 Vector!(T, columns) getRow(uint index) { 109 return new Vector!(T, columns)(this.elements[index]); 110 } 111 112 /** 113 * Sets the nth column of the matrix 114 */ 115 void setColumn(uint index, Vector!(T, rows) c) { 116 foreach (i, ref row; this.elements) { 117 row[index] = c[i]; 118 } 119 } 120 121 /** 122 * Returns the nth column of the matrix 123 */ 124 Vector!(T, rows) getColumn(uint index) { 125 Vector!(T, rows) c = new Vector!(T, rows)(); 126 foreach (i, row; this.elements) { 127 c[i] = row[index]; 128 } 129 return c; 130 } 131 132 /** 133 * Allows assigning the matrix to a static two-dimensional array to set all components of the matrix 134 */ 135 void opAssign(T[][] rhs) { 136 foreach (i, row; rhs) { 137 foreach (j, element; row) { 138 this.elements[i][j] = element; 139 } 140 } 141 } 142 143 /** 144 * Allows assigning the matrix to a static two-dimensional array to set all components of the matrix 145 */ 146 void opAssign(T[columns][rows] rhs) { 147 this.elements = rhs; 148 } 149 150 /** 151 * Allows assigning the matrix to a single value to set all elements of the matrix to such a value 152 */ 153 void opAssign(T rhs) { 154 T[columns] row = rhs; 155 this.elements[] = row; 156 } 157 158 }