Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matrix creation and conversion methods #2155

Merged
merged 14 commits into from
May 9, 2021
Merged
3 changes: 2 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
["@babel/preset-env"]
],
"plugins": [
"@babel/plugin-transform-object-assign"
"@babel/plugin-transform-object-assign",
"@babel/transform-runtime"
],
"ignore": [
"lib/**/*.js"
Expand Down
14,819 changes: 14,247 additions & 572 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"unit"
],
"dependencies": {
"@babel/runtime": "^7.13.17",
"complex.js": "^2.0.11",
"decimal.js": "^10.2.1",
"escape-latex": "^1.2.0",
Expand All @@ -37,6 +38,7 @@
"devDependencies": {
"@babel/core": "7.13.14",
"@babel/plugin-transform-object-assign": "7.12.13",
"@babel/plugin-transform-runtime": "^7.13.15",
"@babel/preset-env": "7.13.12",
"@babel/register": "7.13.14",
"babel-loader": "8.2.2",
Expand Down
6 changes: 6 additions & 0 deletions src/expression/embeddedDocs/embeddedDocs.js
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,9 @@ import { splitUnitDocs } from './construction/splitUnit.js'
import { sparseDocs } from './construction/sparse.js'
import { numberDocs } from './construction/number.js'
import { matrixDocs } from './construction/matrix.js'
import { matrixFromFunctionDocs } from './function/matrix/matrixFromFunction.js'
import { matrixFromRowsDocs } from './function/matrix/matrixFromRows.js'
import { matrixFromColumnsDocs } from './function/matrix/matrixFromColumns.js'
import { indexDocs } from './construction/index.js'
import { fractionDocs } from './construction/fraction.js'
import { createUnitDocs } from './construction/createUnit.js'
Expand Down Expand Up @@ -424,6 +427,9 @@ export const embeddedDocs = {
inv: invDocs,
eigs: eigsDocs,
kron: kronDocs,
matrixFromFunction: matrixFromFunctionDocs,
matrixFromRows: matrixFromRowsDocs,
matrixFromColumns: matrixFromColumnsDocs,
map: mapDocs,
ones: onesDocs,
partitionSelect: partitionSelectDocs,
Expand Down
2 changes: 1 addition & 1 deletion src/expression/embeddedDocs/function/matrix/column.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export const columnDocs = {
'column(A, 1)',
'column(A, 2)'
],
seealso: ['row']
seealso: ['row', 'matrixFromColumns']
}
16 changes: 16 additions & 0 deletions src/expression/embeddedDocs/function/matrix/matrixFromColumns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const matrixFromColumnsDocs = {
name: 'matrixFromColumns',
category: 'Matrix',
syntax: [
'math.matrixFromColumns(...arr)',
'math.matrixFromColumns(row1, row2)',
'math.matrixFromColumns(row1, row2, row3)'
],
description: 'Create a dense matrix from vectors as individual columns.',
examples: [
'matrixFromColumns([1, 2, 3], [[4],[5],[6]])'
],
seealso: [
'matrix', 'matrixFromRows', 'matrixFromFunction', 'zeros'
]
}
22 changes: 22 additions & 0 deletions src/expression/embeddedDocs/function/matrix/matrixFromFunction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export const matrixFromFunctionDocs = {
name: 'matrixFromFunction',
category: 'Matrix',
syntax: [
'math.matrixFromFunction(size, fn)',
'math.matrixFromFunction(size, fn, format)',
'math.matrixFromFunction(size, fn, format, datatype)',
'math.matrixFromFunction(size, format, fn)',
'math.matrixFromFunction(size, format, datatype, fn)'
],
description: 'Create a matrix by evaluating a generating function at each index.',
examples: [
'f(I) = I[1] - I[2]',
'matrixFromFunction([3,3], f)',
'g(I) = I[1] - I[2] == 1 ? 4 : 0',
'matrixFromFunction([100, 100], "sparse", g)',
'matrixFromFunction([5], random)'
],
seealso: [
'matrix', 'matrixFromRows', 'matrixFromColumns', 'zeros'
]
}
16 changes: 16 additions & 0 deletions src/expression/embeddedDocs/function/matrix/matrixFromRows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const matrixFromRowsDocs = {
name: 'matrixFromRows',
category: 'Matrix',
syntax: [
'math.matrixFromRows(...arr)',
'math.matrixFromRows(row1, row2)',
'math.matrixFromRows(row1, row2, row3)'
],
description: 'Create a dense matrix from vectors as individual rows.',
examples: [
'matrixFromRows([1, 2, 3], [[4],[5],[6]])'
],
seealso: [
'matrix', 'matrixFromColumns', 'matrixFromFunction', 'zeros'
]
}
2 changes: 1 addition & 1 deletion src/expression/embeddedDocs/function/matrix/row.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ export const rowDocs = {
'row(A, 1)',
'row(A, 2)'
],
seealso: ['column']
seealso: ['column', 'matrixFromRows']
}
3 changes: 3 additions & 0 deletions src/factoriesAny.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export { createBignumber } from './type/bignumber/function/bignumber.js'
export { createComplex } from './type/complex/function/complex.js'
export { createFraction } from './type/fraction/function/fraction.js'
export { createMatrix } from './type/matrix/function/matrix.js'
export { createMatrixFromFunction } from './function/matrix/matrixFromFunction.js'
export { createMatrixFromRows } from './function/matrix/matrixFromRows.js'
export { createMatrixFromColumns } from './function/matrix/matrixFromColumns.js'
export { createSplitUnit } from './type/unit/function/splitUnit.js'
export { createUnaryMinus } from './function/arithmetic/unaryMinus.js'
export { createUnaryPlus } from './function/arithmetic/unaryPlus.js'
Expand Down
1 change: 1 addition & 0 deletions src/function/matrix/flatten.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const dependencies = ['typed', 'matrix']
export const createFlatten = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix }) => {
/**
* Flatten a multi dimensional matrix into a single dimensional matrix.
* It is guaranteed to always return a clone of the argument.
*
* Syntax:
*
Expand Down
86 changes: 86 additions & 0 deletions src/function/matrix/matrixFromColumns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { factory } from '../../utils/factory.js'

const name = 'matrixFromColumns'
const dependencies = ['typed', 'matrix', 'flatten', 'size']

export const createMatrixFromColumns = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, flatten, size }) => {
/**
* Create a dense matrix from vectors as individual columns.
* If you pass row vectors, they will be transposed (but not conjugated!)
*
* Syntax:
*
* math.matrixFromColumns(...arr)
* math.matrixFromColumns(col1, col2)
* math.matrixFromColumns(col1, col2, col3)
*
* Examples:
*
* math.matrixFromColumns([1, 2, 3], [[4],[5],[6]])
* math.matrixFromColumns(...vectors)
*
* See also:
*
* matrix, matrixFromRows, matrixFromFunction, zeros
*
* @param {...Array | ...Matrix} cols
* @return { number[][] | Matrix } if at least one of the arguments is an array, an array will be returned
*/
return typed(name, {
'...Array': function (arr) {
return _createArray(arr)
},
'...Matrix': function (arr) {
return matrix(_createArray(arr.map(m => m.toArray())))
}

// TODO implement this properly for SparseMatrix
})

function _createArray (arr) {
if (arr.length === 0) throw new TypeError('At least one column is needed to construct a matrix.')
const N = checkVectorTypeAndReturnLength(arr[0])

// create an array with empty rows
const result = []
for (let i = 0; i < N; i++) {
result[i] = []
}

// loop columns
for (const col of arr) {
const colLength = checkVectorTypeAndReturnLength(col)

if (colLength !== N) {
throw new TypeError('The vectors had different length: ' + (N | 0) + ' ≠ ' + (colLength | 0))
}

const f = flatten(col)

// push a value to each row
for (let i = 0; i < N; i++) {
result[i].push(f[i])
}
}

return result
}

function checkVectorTypeAndReturnLength (vec) {
const s = size(vec)

if (s.length === 1) { // 1D vector
return s[0]
} else if (s.length === 2) { // 2D vector
if (s[0] === 1) { // row vector
return s[1]
} else if (s[1] === 1) { // col vector
return s[0]
} else {
throw new TypeError('At least one of the arguments is not a vector.')
}
} else {
throw new TypeError('Only one- or two-dimensional vectors are supported.')
}
}
})
63 changes: 63 additions & 0 deletions src/function/matrix/matrixFromFunction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { factory } from '../../utils/factory.js'

const name = 'matrixFromFunction'
const dependencies = ['typed', 'matrix', 'isZero']

export const createMatrixFromFunction = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, isZero }) => {
/**
* Create a matrix by evaluating a generating function at each index.
*
* Syntax:
*
* math.matrixFromFunction(size, fn)
* math.matrixFromFunction(size, fn, format)
* math.matrixFromFunction(size, fn, format, datatype)
* math.matrixFromFunction(size, format, fn)
* math.matrixFromFunction(size, format, datatype, fn)
*
* Examples:
*
* math.matrixFromFunction([3,3], i => i[0] - i[1]) // an antisymmetric matrix
* math.matrixFromFunction([100, 100], 'sparse', i => i[0] - i[1] === 1 ? 4 : 0) // a sparse subdiagonal matrix
* math.matrixFromFunction([5], i => math.random()) // a random vector
*
* See also:
*
* matrix, zeros
*/
return typed(name, {
'Array | Matrix, function, string, string': function (size, fn, format, datatype) {
return _create(size, fn, format, datatype)
},
'Array | Matrix, function, string': function (size, fn, format) {
return _create(size, fn, format)
},
'Array | Matrix, function': function (size, fn) {
return _create(size, fn, 'dense')
},
'Array | Matrix, string, function': function (size, format, fn) {
return _create(size, fn, format)
},
'Array | Matrix, string, string, function': function (size, format, datatype, fn) {
return _create(size, fn, format, datatype)
}
})

function _create (size, fn, format, datatype) {
let m
if (datatype !== undefined) {
m = matrix(format, datatype)
} else {
m = matrix(format)
}

m.resize(size)
m.forEach(function (_, index) {
const val = fn(index)
if (isZero(val)) return
m.set(index, val)
})

return m
}
})
75 changes: 75 additions & 0 deletions src/function/matrix/matrixFromRows.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { factory } from '../../utils/factory.js'

const name = 'matrixFromRows'
const dependencies = ['typed', 'matrix', 'flatten', 'size']

export const createMatrixFromRows = /* #__PURE__ */ factory(name, dependencies, ({ typed, matrix, flatten, size }) => {
/**
* Create a dense matrix from vectors as individual rows.
* If you pass column vectors, they will be transposed (but not conjugated!)
*
* Syntax:
*
* math.matrixFromRows(...arr)
* math.matrixFromRows(row1, row2)
* math.matrixFromRows(row1, row2, row3)
*
* Examples:
*
* math.matrixFromRows([1, 2, 3], [[4],[5],[6]])
* math.matrixFromRows(...vectors)
*
* See also:
*
* matrix, matrixFromColumns, matrixFromFunction, zeros
*
* @param {...Array | ...Matrix} rows
* @return { number[][] | Matrix } if at least one of the arguments is an array, an array will be returned
*/
return typed(name, {
'...Array': function (arr) {
return _createArray(arr)
},
'...Matrix': function (arr) {
return matrix(_createArray(arr.map(m => m.toArray())))
}

// TODO implement this properly for SparseMatrix
})

function _createArray (arr) {
if (arr.length === 0) throw new TypeError('At least one row is needed to construct a matrix.')
const N = checkVectorTypeAndReturnLength(arr[0])

const result = []
for (const row of arr) {
const rowLength = checkVectorTypeAndReturnLength(row)

if (rowLength !== N) {
throw new TypeError('The vectors had different length: ' + (N | 0) + ' ≠ ' + (rowLength | 0))
}

result.push(flatten(row))
}

return result
}

function checkVectorTypeAndReturnLength (vec) {
const s = size(vec)

if (s.length === 1) { // 1D vector
return s[0]
} else if (s.length === 2) { // 2D vector
if (s[0] === 1) { // row vector
return s[1]
} else if (s[1] === 1) { // col vector
return s[0]
} else {
throw new TypeError('At least one of the arguments is not a vector.')
}
} else {
throw new TypeError('Only one- or two-dimensional vectors are supported.')
}
}
})
Loading