UNPKG

4.79 kBJavaScriptView Raw
1const determinant = require('laplace-determinant')
2const inherits = require('inherits')
3const itemsPool = require('./itemsPool')
4const matrixMultiplication = require('matrix-multiplication')
5const multiDimArrayIndex = require('multidim-array-index')
6const no = require('not-defined')
7const operators = require('./operators.json')
8const staticProps = require('static-props')
9const TensorSpace = require('./TensorSpace')
10const tensorContraction = require('tensor-contraction')
11const toData = require('./toData')
12
13/**
14 * Space of m x n matrices
15 *
16 * ```
17 * var R = algebra.R
18 *
19 * var R2x2 = algebra.MatrixSpace(R)(2)
20 * ```
21 *
22 * @param {Object} Scalar
23 *
24 * @returns {Function} anonymous with signature (numRows[, numCols])
25 */
26
27function MatrixSpace (Scalar) {
28 var contraction = tensorContraction.bind(null, Scalar.addition)
29
30 /**
31 * @param {Number} numRows
32 * @param {Number} [numCols] defaults to a square matrix.
33 *
34 * @returns {Function} Matrix
35 */
36
37 return function (numRows, numCols) {
38 // numCols defaults to numRows
39 if (no(numCols)) numCols = numRows
40
41 const isSquare = (numRows === numCols)
42 const indices = [numRows, numCols]
43
44 const AbstractMatrix = TensorSpace(Scalar)(indices)
45
46 /**
47 * Calculates the matrix trace.
48 *
49 * https://en.wikipedia.org/wiki/Trace_(linear_algebra)
50 *
51 * @param {Object|Array} matrix
52 *
53 * @returns {Object} scalar
54 */
55
56 function trace (matrix) {
57 const matrixData = toData(matrix)
58
59 return contraction([0, 1], indices, matrixData)
60 }
61
62 /**
63 * Multiplies row by column to the right.
64 *
65 * @param {Object|Array} rightMatrix
66 *
67 * @returns {Object} matrix
68 */
69
70 function multiplication (leftMatrix, rightMatrix) {
71 const leftMatrixData = toData(leftMatrix)
72 const rightMatrixData = toData(rightMatrix)
73
74 const rowByColumnMultiplication = matrixMultiplication(Scalar)(numCols)
75
76 return rowByColumnMultiplication(leftMatrixData, rightMatrixData)
77 }
78
79 /**
80 * Calculates the transpose of a matrix.
81 *
82 * @param {Object|Array} matrix
83 *
84 * @returns {Array} matrix
85 */
86
87 function transpose (matrix) {
88 const matrixData = toData(matrix)
89 var transposedData = []
90
91 for (var i = 0; i < numRows; i++) {
92 for (var j = 0; j < numCols; j++) {
93 var index = multiDimArrayIndex([numRows, numCols], [i, j])
94 var transposedIndex = multiDimArrayIndex([numCols, numRows], [j, i])
95
96 transposedData[transposedIndex] = matrixData[index]
97 }
98 }
99
100 return transposedData
101 }
102
103 /**
104 * Matrix element.
105 */
106
107 function Matrix (data) {
108 AbstractMatrix.call(this, data)
109
110 staticProps(this)({
111 numCols,
112 numRows
113 })
114
115 function computeDeterminant () {
116 var det = determinant(data, Scalar, numRows)
117
118 return new Scalar(det)
119 }
120
121 if (isSquare) {
122 staticProps(this)({
123 trace: trace(data)
124 })
125
126 staticProps(this)({
127 determinant: computeDeterminant,
128 det: computeDeterminant
129 })
130 }
131
132 function transposed () {
133 const result = transpose(data)
134 const VectorSpace = itemsPool.get('VectorSpace')
135
136 if (numRows === 1) {
137 const Vector = VectorSpace(Scalar)(numCols)
138 return new Vector(result)
139 } else {
140 const Matrix = MatrixSpace(Scalar)(numCols, numRows)
141 return new Matrix(result)
142 }
143 }
144
145 staticProps(this)({
146 transposed,
147 tr: transposed
148 })
149 }
150
151 inherits(Matrix, AbstractMatrix)
152
153 if (isSquare) {
154 Matrix.trace = trace
155 }
156
157 Matrix.prototype.multiplication = function (rightMatrix) {
158 var leftMatrixData = this.data
159 var result = multiplication(leftMatrixData, rightMatrix)
160
161 var rightNumRows = numCols
162 var rightNumCols = result.length / rightNumRows
163
164 var Matrix = MatrixSpace(Scalar)(rightNumRows, rightNumCols)
165
166 return new Matrix(result)
167 }
168
169 // Static operators.
170
171 Matrix.multiplication = multiplication
172 Matrix.transpose = transpose
173
174 // Aliases
175
176 Matrix.tr = Matrix.transpose
177 Matrix.mul = Matrix.multiplication
178
179 Matrix.prototype.mul = Matrix.prototype.multiplication
180
181 operators.group.forEach((operator) => {
182 operators.aliasesOf[operator].forEach((alias) => {
183 Matrix[alias] = Matrix[operator]
184 Matrix.prototype[alias] = Matrix.prototype[operator]
185 })
186 })
187
188 operators.group.forEach((operator) => {
189 Matrix[operator] = AbstractMatrix[operator]
190 })
191
192 staticProps(Matrix)({
193 numCols,
194 numRows
195 })
196
197 return Matrix
198 }
199}
200
201itemsPool.set('MatrixSpace', MatrixSpace)
202
203module.exports = MatrixSpace