UNPKG

5.87 kBJavaScriptView Raw
1const inherits = require('inherits')
2const itemsPool = require('./itemsPool')
3const matrixMultiplication = require('matrix-multiplication')
4const operators = require('./operators.json')
5const staticProps = require('static-props')
6const TensorSpace = require('./TensorSpace')
7const toData = require('./toData')
8
9/**
10 * Space of vectors
11 *
12 * ```
13 * var V = VectorSpace(R)(2)
14 *
15 * var v = new V([1, 2])
16 * ```
17 *
18 * @param {Object} Scalar
19 *
20 * @returns {Function} anonymous with signature (dimension)
21 */
22
23function VectorSpace (Scalar) {
24 const addition = Scalar.addition
25 const multiplication = Scalar.multiplication
26 const subtraction = Scalar.subtraction
27
28 /**
29 * @param {Number} dimension
30 *
31 * @returns {Function} Vector
32 */
33
34 return function (dimension) {
35 const indices = [dimension]
36
37 const AbstractVector = TensorSpace(Scalar)(indices)
38
39 /**
40 * Computes the cross product of two vectors.
41 *
42 * It is defined only in dimension 3.
43 *
44 * @param {Object|Array} vector1
45 * @param {Object|Array} vector2
46 *
47 * @returns {Array} vector
48 */
49
50 function crossProduct (vector1, vector2) {
51 const vectorData1 = toData(vector1)
52 const vectorData2 = toData(vector2)
53
54 const ux = vectorData1[0]
55 const uy = vectorData1[1]
56 const uz = vectorData1[2]
57
58 const vx = vectorData2[0]
59 const vy = vectorData2[1]
60 const vz = vectorData2[2]
61
62 var vector = []
63
64 vector.push(subtraction(multiplication(uy, vz), multiplication(uz, vy)))
65 vector.push(subtraction(multiplication(uz, vx), multiplication(ux, vz)))
66 vector.push(subtraction(multiplication(ux, vy), multiplication(uy, vx)))
67
68 return vector
69 }
70
71 /**
72 * Multiply a column vector by matrix on right side
73 * @param {Object|Array} vector
74 *
75 * @returns {Object} scalar
76 */
77
78 function multiplicationByMatrix (leftVector, rightMatrix) {
79 const leftVectorData = toData(leftVector)
80 const rightMatrixData = toData(rightMatrix)
81
82 const rowByColumnMultiplication = matrixMultiplication(Scalar)(dimension)
83
84 return rowByColumnMultiplication(leftVectorData, rightMatrixData)
85 }
86
87 /**
88 * Norm of a vector
89 *
90 * Given v = (x1, x2, ... xN)
91 *
92 * norm is defined as n = x1 * x1 + x2 * x2 + ... + xN * xN
93 *
94 * @param {Object|Array} vector
95 *
96 * @returns {Object} scalar
97 */
98
99 function norm (vector) {
100 const data = toData(vector)
101
102 var value = multiplication(data[0], data[0])
103
104 for (var i = 1; i < dimension; i++) {
105 value = addition(value, multiplication(data[i], data[i]))
106 }
107
108 return new Scalar(value)
109 }
110
111 /**
112 * Scalar product
113 *
114 * https://en.wikipedia.org/wiki/Dot_product
115 *
116 * @param {Object|Array} vector1
117 * @param {Object|Array} vector2
118 *
119 * @returns {*} scalar
120 */
121
122 function scalarProduct (vector1, vector2) {
123 // TODO use tensor product and then contraction (trace)
124 const vectorData1 = toData(vector1)
125 const vectorData2 = toData(vector2)
126
127 if (vectorData1.length !== vectorData2.length) {
128 throw new TypeError('Vectors have not the same dimension')
129 }
130
131 var result = multiplication(vectorData1[0], vectorData2[0])
132
133 for (var i = 1; i < dimension; i++) {
134 result = addition(result, multiplication(vectorData1[i], vectorData2[i]))
135 }
136
137 return result
138 }
139
140 /**
141 * Vector element.
142 */
143
144 function Vector (data) {
145 AbstractVector.call(this, data)
146
147 staticProps(this)({
148 norm: norm(data),
149 dimension
150 })
151 }
152
153 inherits(Vector, AbstractVector)
154
155 Vector.prototype.scalarProduct = function (vector) {
156 const data = this.data
157
158 const result = scalarProduct(data, vector)
159
160 return new Scalar(result)
161 }
162
163 // Cross product is defined only in dimension 3.
164 function crossProductMethod (vector) {
165 const data = this.data
166
167 const result = crossProduct(data, vector)
168
169 return new Vector(result)
170 }
171
172 if (dimension === 3) {
173 Vector.crossProduct = crossProduct
174
175 Vector.prototype.crossProduct = crossProductMethod
176 Vector.prototype.cross = crossProductMethod
177 }
178
179 Vector.prototype.multiplication = function (rightMatrix) {
180 const MatrixSpace = itemsPool.get('MatrixSpace')
181
182 const leftVectorData = this.data
183 const result = multiplicationByMatrix(leftVectorData, rightMatrix)
184
185 // TODO rightNumRows equals dimension
186 // but the vector should be transposed.
187 // Add transpose operator for vectors, then use it implicitly.
188 const rightNumRows = dimension
189 const rightNumCols = result.length / rightNumRows
190
191 const Matrix = MatrixSpace(Scalar)(rightNumRows, rightNumCols)
192
193 return new Matrix(result)
194 }
195
196 // Static operators.
197
198 Vector.multiplication = multiplicationByMatrix
199 Vector.norm = norm
200 Vector.scalarProduct = scalarProduct
201
202 operators.comparison.forEach((operator) => {
203 Vector[operator] = AbstractVector[operator]
204 })
205
206 operators.set.forEach((operator) => {
207 Vector[operator] = AbstractVector[operator]
208 })
209
210 operators.group.forEach((operator) => {
211 Vector[operator] = AbstractVector[operator]
212 })
213
214 // Aliases
215
216 Vector.mul = multiplicationByMatrix
217 Vector.prototype.mul = Vector.prototype.multiplication
218
219 const myOperators = ['scalarProduct'].concat(operators.group)
220
221 myOperators.forEach((operator) => {
222 operators.aliasesOf[operator].forEach((alias) => {
223 Vector[alias] = Vector[operator]
224 Vector.prototype[alias] = Vector.prototype[operator]
225 })
226 })
227
228 if (dimension === 3) {
229 Vector.cross = crossProduct
230 }
231
232 return Vector
233 }
234}
235
236itemsPool.set('VectorSpace', VectorSpace)
237
238module.exports = VectorSpace