mathjs
Version:
Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser with support for symbolic computation, comes with a large set of built-in functions and constants, and offers an integrated solution to work with dif
177 lines (157 loc) • 4.42 kB
JavaScript
const clone = require('../../utils/object').clone
const format = require('../../utils/string').format
function factory (type, config, load, typed) {
const latex = require('../../utils/latex')
const matrix = load(require('../../type/matrix/function/matrix'))
const DenseMatrix = type.DenseMatrix
const SparseMatrix = type.SparseMatrix
/**
* Transpose a matrix. All values of the matrix are reflected over its
* main diagonal. Only applicable to two dimensional matrices containing
* a vector (i.e. having size `[1,n]` or `[n,1]`). One dimensional
* vectors and scalars return the input unchanged.
*
* Syntax:
*
* math.transpose(x)
*
* Examples:
*
* const A = [[1, 2, 3], [4, 5, 6]]
* math.transpose(A) // returns [[1, 4], [2, 5], [3, 6]]
*
* See also:
*
* diag, inv, subset, squeeze
*
* @param {Array | Matrix} x Matrix to be transposed
* @return {Array | Matrix} The transposed matrix
*/
const transpose = typed('transpose', {
'Array': function (x) {
// use dense matrix implementation
return transpose(matrix(x)).valueOf()
},
'Matrix': function (x) {
// matrix size
const size = x.size()
// result
let c
// process dimensions
switch (size.length) {
case 1:
// vector
c = x.clone()
break
case 2:
// rows and columns
const rows = size[0]
const columns = size[1]
// check columns
if (columns === 0) {
// throw exception
throw new RangeError('Cannot transpose a 2D matrix with no columns (size: ' + format(size) + ')')
}
// process storage format
switch (x.storage()) {
case 'dense':
c = _denseTranspose(x, rows, columns)
break
case 'sparse':
c = _sparseTranspose(x, rows, columns)
break
}
break
default:
// multi dimensional
throw new RangeError('Matrix must be a vector or two dimensional (size: ' + format(this._size) + ')')
}
return c
},
// scalars
'any': function (x) {
return clone(x)
}
})
function _denseTranspose (m, rows, columns) {
// matrix array
const data = m._data
// transposed matrix data
const transposed = []
let transposedRow
// loop columns
for (let j = 0; j < columns; j++) {
// initialize row
transposedRow = transposed[j] = []
// loop rows
for (let i = 0; i < rows; i++) {
// set data
transposedRow[i] = clone(data[i][j])
}
}
// return matrix
return new DenseMatrix({
data: transposed,
size: [columns, rows],
datatype: m._datatype
})
}
function _sparseTranspose (m, rows, columns) {
// matrix arrays
const values = m._values
const index = m._index
const ptr = m._ptr
// result matrices
const cvalues = values ? [] : undefined
const cindex = []
const cptr = []
// row counts
const w = []
for (let x = 0; x < rows; x++) { w[x] = 0 }
// vars
let p, l, j
// loop values in matrix
for (p = 0, l = index.length; p < l; p++) {
// number of values in row
w[index[p]]++
}
// cumulative sum
let sum = 0
// initialize cptr with the cummulative sum of row counts
for (let i = 0; i < rows; i++) {
// update cptr
cptr.push(sum)
// update sum
sum += w[i]
// update w
w[i] = cptr[i]
}
// update cptr
cptr.push(sum)
// loop columns
for (j = 0; j < columns; j++) {
// values & index in column
for (let k0 = ptr[j], k1 = ptr[j + 1], k = k0; k < k1; k++) {
// C values & index
const q = w[index[k]]++
// C[j, i] = A[i, j]
cindex[q] = j
// check we need to process values (pattern matrix)
if (values) { cvalues[q] = clone(values[k]) }
}
}
// return matrix
return new SparseMatrix({
values: cvalues,
index: cindex,
ptr: cptr,
size: [columns, rows],
datatype: m._datatype
})
}
transpose.toTex = { 1: `\\left(\${args[0]}\\right)${latex.operators['transpose']}` }
return transpose
}
exports.name = 'transpose'
exports.factory = factory