var inherits = require('inherits')
var itemsPool = require('./itemsPool')
var matrixMultiplication = require('matrix-multiplication')
var operators = require('./operators.json')
var staticProps = require('static-props')
var TensorSpace = require('./TensorSpace')
var toData = require('./toData')
/**
* Space of vectors
*
* ```
* var V = VectorSpace(R)(2)
*
* var v = new V([1, 2])
* ```
*
* @param {Object} Scalar
*
* @returns {Function} anonymous with signature (dimension)
*/
function VectorSpace (Scalar) {
var addition = Scalar.addition
var multiplication = Scalar.multiplication
var subtraction = Scalar.subtraction
/**
* @param {Number} dimension
*
* @returns {Function} Vector
*/
return function (dimension) {
var indices = [dimension]
var AbstractVector = TensorSpace(Scalar)(indices)
/**
* Computes the cross product of two vectors.
*
* It is defined only in dimension 3.
*
* @param {Object|Array} vector1
* @param {Object|Array} vector2
*
* @returns {Array} vector
*/
function crossProduct (vector1, vector2) {
var vectorData1 = toData(vector1)
var vectorData2 = toData(vector2)
var ux = vectorData1[0]
var uy = vectorData1[1]
var uz = vectorData1[2]
var vx = vectorData2[0]
var vy = vectorData2[1]
var vz = vectorData2[2]
var vector = []
vector.push(subtraction(multiplication(uy, vz), multiplication(uz, vy)))
vector.push(subtraction(multiplication(uz, vx), multiplication(ux, vz)))
vector.push(subtraction(multiplication(ux, vy), multiplication(uy, vx)))
return vector
}
/**
* Multiply a column vector by matrix on right side
* @param {Object|Array} vector
*
* @returns {Object} scalar
*/
function multiplicationByMatrix (leftVector, rightMatrix) {
var leftVectorData = toData(leftVector)
var rightMatrixData = toData(rightMatrix)
var rowByColumnMultiplication = matrixMultiplication(Scalar)(dimension)
return rowByColumnMultiplication(leftVectorData, rightMatrixData)
}
/**
* Norm of a vector
*
* Given v = (x1, x2, ... xN)
*
* norm is defined as n = x1 * x1 + x2 * x2 + ... + xN * xN
*
* @param {Object|Array} vector
*
* @returns {Object} scalar
*/
function norm (vector) {
var data = toData(vector)
var value = multiplication(data[0], data[0])
for (var i = 1; i < dimension; i++) {
value = addition(value, multiplication(data[i], data[i]))
}
return new Scalar(value)
}
/**
* Scalar product
*
* https://en.wikipedia.org/wiki/Dot_product
*
* @param {Object|Array} vector1
* @param {Object|Array} vector2
*
* @returns {*} scalar
*/
function scalarProduct (vector1, vector2) {
// TODO use tensor product and then contraction (trace)
var vectorData1 = toData(vector1)
var vectorData2 = toData(vector2)
Iif (vectorData1.length !== vectorData2.length) {
throw new TypeError('Vectors have not the same dimension')
}
var result = multiplication(vectorData1[0], vectorData2[0])
for (var i = 1; i < dimension; i++) {
result = addition(result, multiplication(vectorData1[i], vectorData2[i]))
}
return result
}
/**
* Vector element.
*/
function Vector (data) {
AbstractVector.call(this, data)
staticProps(this)({
norm: norm(data),
dimension
})
}
inherits(Vector, AbstractVector)
staticProps(Vector)({ dimension })
Vector.prototype.scalarProduct = function (vector) {
var data = this.data
var result = scalarProduct(data, vector)
return new Scalar(result)
}
// Cross product is defined only in dimension 3.
function crossProductMethod (vector) {
var data = this.data
var result = crossProduct(data, vector)
return new Vector(result)
}
if (dimension === 3) {
Vector.crossProduct = crossProduct
Vector.prototype.crossProduct = crossProductMethod
Vector.prototype.cross = crossProductMethod
}
Vector.prototype.multiplication = function (rightMatrix) {
var MatrixSpace = itemsPool.get('MatrixSpace')
var leftVectorData = this.data
var result = multiplicationByMatrix(leftVectorData, rightMatrix)
// TODO rightNumRows equals dimension
// but the vector should be transposed.
// Add transpose operator for vectors, then use it implicitly.
var rightNumRows = dimension
var rightNumCols = result.length / rightNumRows
var Matrix = MatrixSpace(Scalar)(rightNumRows, rightNumCols)
return new Matrix(result)
}
// Static operators.
Vector.multiplication = multiplicationByMatrix
Vector.norm = norm
Vector.scalarProduct = scalarProduct
operators.comparison.forEach((operator) => {
Vector[operator] = AbstractVector[operator]
})
operators.set.forEach((operator) => {
Vector[operator] = AbstractVector[operator]
})
operators.group.forEach((operator) => {
Vector[operator] = AbstractVector[operator]
})
// Aliases
Vector.mul = multiplicationByMatrix
Vector.prototype.mul = Vector.prototype.multiplication
var myOperators = ['scalarProduct'].concat(operators.group)
myOperators.forEach((operator) => {
operators.aliasesOf[operator].forEach((alias) => {
Vector[alias] = Vector[operator]
Vector.prototype[alias] = Vector.prototype[operator]
})
})
if (dimension === 3) {
Vector.cross = crossProduct
}
return Vector
}
}
itemsPool.set('VectorSpace', VectorSpace)
module.exports = VectorSpace
|