mirror of
https://github.com/josdejong/mathjs.git
synced 2025-12-08 19:46:04 +00:00
* added type inference * added back accidentally removed return statement and made it so that the explicitly defined type is returned at the end * made sure that mixed types are ignored in the process data types check * fixed issue with undefined _data for SparseMatrix and linting issues * simplified syntax and added type inferencing to src/type/matrix/utils and src/function/matrix/dot.js * shortened the final part of the type inferencing and moved it to matrix creation in multiply --------- Co-authored-by: Jos de Jong <wjosdejong@gmail.com>
167 lines
4.4 KiB
JavaScript
167 lines
4.4 KiB
JavaScript
import { factory } from '../../utils/factory.js'
|
|
import { isMatrix } from '../../utils/is.js'
|
|
|
|
const name = 'dot'
|
|
const dependencies = ['typed', 'addScalar', 'multiplyScalar', 'conj', 'size']
|
|
|
|
export const createDot = /* #__PURE__ */ factory(name, dependencies, ({ typed, addScalar, multiplyScalar, conj, size }) => {
|
|
/**
|
|
* Calculate the dot product of two vectors. The dot product of
|
|
* `A = [a1, a2, ..., an]` and `B = [b1, b2, ..., bn]` is defined as:
|
|
*
|
|
* dot(A, B) = conj(a1) * b1 + conj(a2) * b2 + ... + conj(an) * bn
|
|
*
|
|
* Syntax:
|
|
*
|
|
* math.dot(x, y)
|
|
*
|
|
* Examples:
|
|
*
|
|
* math.dot([2, 4, 1], [2, 2, 3]) // returns number 15
|
|
* math.multiply([2, 4, 1], [2, 2, 3]) // returns number 15
|
|
*
|
|
* See also:
|
|
*
|
|
* multiply, cross
|
|
*
|
|
* @param {Array | Matrix} x First vector
|
|
* @param {Array | Matrix} y Second vector
|
|
* @return {number} Returns the dot product of `x` and `y`
|
|
*/
|
|
return typed(name, {
|
|
'Array | DenseMatrix, Array | DenseMatrix': _denseDot,
|
|
'SparseMatrix, SparseMatrix': _sparseDot
|
|
})
|
|
|
|
function _validateDim (x, y) {
|
|
const xSize = _size(x)
|
|
const ySize = _size(y)
|
|
let xLen, yLen
|
|
|
|
if (xSize.length === 1) {
|
|
xLen = xSize[0]
|
|
} else if (xSize.length === 2 && xSize[1] === 1) {
|
|
xLen = xSize[0]
|
|
} else {
|
|
throw new RangeError('Expected a column vector, instead got a matrix of size (' + xSize.join(', ') + ')')
|
|
}
|
|
|
|
if (ySize.length === 1) {
|
|
yLen = ySize[0]
|
|
} else if (ySize.length === 2 && ySize[1] === 1) {
|
|
yLen = ySize[0]
|
|
} else {
|
|
throw new RangeError('Expected a column vector, instead got a matrix of size (' + ySize.join(', ') + ')')
|
|
}
|
|
|
|
if (xLen !== yLen) throw new RangeError('Vectors must have equal length (' + xLen + ' != ' + yLen + ')')
|
|
if (xLen === 0) throw new RangeError('Cannot calculate the dot product of empty vectors')
|
|
|
|
return xLen
|
|
}
|
|
|
|
function _denseDot (a, b) {
|
|
const N = _validateDim(a, b)
|
|
|
|
const adata = isMatrix(a) ? a._data : a
|
|
const adt = isMatrix(a) ? a._datatype || a.getDataType() : undefined
|
|
|
|
const bdata = isMatrix(b) ? b._data : b
|
|
const bdt = isMatrix(b) ? b._datatype || b.getDataType() : undefined
|
|
|
|
// are these 2-dimensional column vectors? (as opposed to 1-dimensional vectors)
|
|
const aIsColumn = _size(a).length === 2
|
|
const bIsColumn = _size(b).length === 2
|
|
|
|
let add = addScalar
|
|
let mul = multiplyScalar
|
|
|
|
// process data types
|
|
if (adt && bdt && adt === bdt && typeof adt === 'string' && adt !== 'mixed') {
|
|
const dt = adt
|
|
// find signatures that matches (dt, dt)
|
|
add = typed.find(addScalar, [dt, dt])
|
|
mul = typed.find(multiplyScalar, [dt, dt])
|
|
}
|
|
|
|
// both vectors 1-dimensional
|
|
if (!aIsColumn && !bIsColumn) {
|
|
let c = mul(conj(adata[0]), bdata[0])
|
|
for (let i = 1; i < N; i++) {
|
|
c = add(c, mul(conj(adata[i]), bdata[i]))
|
|
}
|
|
return c
|
|
}
|
|
|
|
// a is 1-dim, b is column
|
|
if (!aIsColumn && bIsColumn) {
|
|
let c = mul(conj(adata[0]), bdata[0][0])
|
|
for (let i = 1; i < N; i++) {
|
|
c = add(c, mul(conj(adata[i]), bdata[i][0]))
|
|
}
|
|
return c
|
|
}
|
|
|
|
// a is column, b is 1-dim
|
|
if (aIsColumn && !bIsColumn) {
|
|
let c = mul(conj(adata[0][0]), bdata[0])
|
|
for (let i = 1; i < N; i++) {
|
|
c = add(c, mul(conj(adata[i][0]), bdata[i]))
|
|
}
|
|
return c
|
|
}
|
|
|
|
// both vectors are column
|
|
if (aIsColumn && bIsColumn) {
|
|
let c = mul(conj(adata[0][0]), bdata[0][0])
|
|
for (let i = 1; i < N; i++) {
|
|
c = add(c, mul(conj(adata[i][0]), bdata[i][0]))
|
|
}
|
|
return c
|
|
}
|
|
}
|
|
|
|
function _sparseDot (x, y) {
|
|
_validateDim(x, y)
|
|
|
|
const xindex = x._index
|
|
const xvalues = x._values
|
|
|
|
const yindex = y._index
|
|
const yvalues = y._values
|
|
|
|
// TODO optimize add & mul using datatype
|
|
let c = 0
|
|
const add = addScalar
|
|
const mul = multiplyScalar
|
|
|
|
let i = 0
|
|
let j = 0
|
|
while (i < xindex.length && j < yindex.length) {
|
|
const I = xindex[i]
|
|
const J = yindex[j]
|
|
|
|
if (I < J) {
|
|
i++
|
|
continue
|
|
}
|
|
if (I > J) {
|
|
j++
|
|
continue
|
|
}
|
|
if (I === J) {
|
|
c = add(c, mul(xvalues[i], yvalues[j]))
|
|
i++
|
|
j++
|
|
}
|
|
}
|
|
|
|
return c
|
|
}
|
|
|
|
// TODO remove this once #1771 is fixed
|
|
function _size (x) {
|
|
return isMatrix(x) ? x.size() : size(x)
|
|
}
|
|
})
|