nerdamer-ts
Version:
javascript light-weight symbolic math expression evaluator
281 lines • 9.73 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Vector = void 0;
const Utils_1 = require("../Core/Utils");
const Symbol_1 = require("./Symbol");
const Core_1 = require("../Functions/Core");
const Settings_1 = require("../Settings");
const LaTeX_1 = require("../LaTeX/LaTeX");
const Text_1 = require("../Core/Text");
// noinspection JSUnusedGlobalSymbols
class Vector {
constructor(v) {
this.custom = true;
if ((0, Utils_1.isVector)(v))
this.elements = v.items.slice(0);
else if (Array.isArray(v))
this.elements = v.slice(0);
else
this.elements = [].slice.call(arguments);
}
/**
* Generate a vector from and array
* @param {type} a
* @returns {Vector}
*/
static fromArray(a) {
let v = new Vector();
v.elements = a;
return v;
}
/**
* Convert a Set to a Vector
* @param {Set} set
* @returns {Vector}
*/
static fromSet(set) {
return Vector.fromArray(set.elements);
}
/**
* Generates a pre-filled array
* @param {int} n
* @param {any} val
* @returns {any[]}
*/
static arrayPrefill(n, val) {
let a = [];
val = val || 0;
for (let i = 0; i < n; i++) {
a[i] = val;
}
return a;
}
// Returns element i of the vector
e(i) {
return (i < 1 || i > this.elements.length) ? null : this.elements[i - 1];
}
set(i, val) {
if (!(0, Utils_1.isSymbol)(val))
val = new Symbol_1.Symbol(val);
this.elements[i] = val;
}
// Returns the number of elements the vector has
dimensions() {
return this.elements.length;
}
// Returns the modulus ('length') of the vector
modulus() {
return (0, Utils_1.block)('SAFE', () => {
return (0, Core_1.pow)((this.dot(this.clone())), new Symbol_1.Symbol(0.5));
}, undefined, this);
}
// Returns true iff the vector is equal to the argument
eql(vector) {
let n = this.elements.length;
let V = vector.elements || vector;
if (n !== V.length) {
return false;
}
do {
if (Math.abs((0, Core_1.subtract)(this.elements[n - 1], V[n - 1]).valueOf()) > Settings_1.Settings.PRECISION) {
return false;
}
} while (--n);
return true;
}
// Returns a clone of the vector
clone() {
let V = new Vector(), l = this.elements.length;
for (let i = 0; i < l; i++) {
//Rule: all items within the vector must have a clone method.
V.elements.push(this.elements[i].clone());
}
if (this.getter) {
V.getter = this.getter.clone();
}
return V;
}
// Maps the vector to another vector according to the given function
map(fn) {
let elements = [];
this.each(function (x, i) {
elements.push(fn(x, i));
});
return new Vector(elements);
}
// Calls the iterator for each element of the vector in turn
each(fn) {
let n = this.elements.length, k = n, i;
do {
i = k - n;
fn(this.elements[i], i + 1);
} while (--n);
}
// Returns a new vector created by normalizing the receiver
toUnitVector() {
return (0, Utils_1.block)('SAFE', () => {
let r = this.modulus();
if (r.valueOf() === 0) {
return this.clone();
}
return this.map((x) => {
return (0, Core_1.divide)(x, r);
});
}, undefined, this);
}
// Returns the angle between the vector and the argument (also a vector)
angleFrom(vector) {
return (0, Utils_1.block)('SAFE', () => {
let V = vector.elements || vector;
let n = this.elements.length;
if (n !== V.length) {
return null;
}
let dot = new Symbol_1.Symbol(0), mod1 = new Symbol_1.Symbol(0), mod2 = new Symbol_1.Symbol(0);
// Work things out in parallel to save time
this.each((x, i) => {
dot = (0, Core_1.add)(dot, (0, Core_1.multiply)(x, V[i - 1]));
mod1 = (0, Core_1.add)(mod1, (0, Core_1.multiply)(x, x)); // will not conflict in safe block
mod2 = (0, Core_1.add)(mod2, (0, Core_1.multiply)(V[i - 1], V[i - 1])); // will not conflict in safe block
});
mod1 = (0, Core_1.pow)(mod1, new Symbol_1.Symbol(0.5));
mod2 = (0, Core_1.pow)(mod2, new Symbol_1.Symbol(0.5));
let product = (0, Core_1.multiply)(mod1, mod2);
if (product.valueOf() === 0) {
return null;
}
let theta = (0, Core_1.divide)(dot, product);
let theta_val = theta.valueOf();
if (theta_val < -1) {
theta = -1;
}
if (theta_val > 1) {
theta = 1;
}
return new Symbol_1.Symbol(Math.acos(theta));
}, undefined, this);
}
// Returns true iff the vector is parallel to the argument
isParallelTo(vector) {
let angle = this.angleFrom(vector).valueOf();
return (angle === null) ? null : (angle <= Settings_1.Settings.PRECISION);
}
// Returns true iff the vector is antiparallel to the argument
isAntiparallelTo(vector) {
let angle = this.angleFrom(vector).valueOf();
return (angle === null) ? null : (Math.abs(angle - Math.PI) <= Settings_1.Settings.PRECISION);
}
// Returns true iff the vector is perpendicular to the argument
isPerpendicularTo(vector) {
let dot = this.dot(vector);
return (dot === null) ? null : (Math.abs(dot) <= Settings_1.Settings.PRECISION);
}
// Returns the result of adding the argument to the vector
add(vector) {
return (0, Utils_1.block)('SAFE', () => {
let V = vector.elements || vector;
if (this.elements.length !== V.length) {
return null;
}
return this.map((x, i) => {
return (0, Core_1.add)(x, V[i - 1]);
});
}, undefined, this);
}
// Returns the result of subtracting the argument from the vector
subtract(vector) {
return (0, Utils_1.block)('SAFE', () => {
let V = vector.elements || vector;
if (this.elements.length !== V.length) {
return null;
}
return this.map((x, i) => {
return (0, Core_1.subtract)(x, V[i - 1]);
});
}, undefined, this);
}
// Returns the result of multiplying the elements of the vector by the argument
multiply(k) {
return this.map(function (x) {
return x.clone() * k.clone();
});
}
x(k) {
return this.multiply(k);
}
// Returns the scalar product of the vector with the argument
// Both vectors must have equal dimensionality
dot(vector) {
return (0, Utils_1.block)('SAFE', () => {
let V = vector.elements || vector;
let product = new Symbol_1.Symbol(0), n = this.elements.length;
if (n !== V.length) {
return null;
}
do {
product = (0, Core_1.add)(product, (0, Core_1.multiply)(this.elements[n - 1], V[n - 1]));
} while (--n);
return product;
}, undefined, this);
}
// Returns the vector product of the vector with the argument
// Both vectors must have dimensionality 3
cross(vector) {
let B = vector.elements || vector;
if (this.elements.length !== 3 || B.length !== 3) {
return null;
}
let A = this.elements;
return (0, Utils_1.block)('SAFE', function () {
return new Vector([
(0, Core_1.subtract)((0, Core_1.multiply)(A[1], B[2]), (0, Core_1.multiply)(A[2], B[1])),
(0, Core_1.subtract)((0, Core_1.multiply)(A[2], B[0]), (0, Core_1.multiply)(A[0], B[2])),
(0, Core_1.subtract)((0, Core_1.multiply)(A[0], B[1]), (0, Core_1.multiply)(A[1], B[0]))
]);
}, undefined, this);
}
// Returns the (absolute) largest element of the vector
max() {
let m = 0, n = this.elements.length, k = n, i;
do {
i = k - n;
if (Math.abs(this.elements[i].valueOf()) > Math.abs(m.valueOf())) {
m = this.elements[i];
}
} while (--n);
return m;
}
magnitude() {
let magnitude = new Symbol_1.Symbol(0);
this.each(function (e) {
magnitude = (0, Core_1.add)(magnitude, (0, Core_1.pow)(e, new Symbol_1.Symbol(2)));
});
return (0, Core_1.sqrt)(magnitude);
}
// Returns the index of the first match found
indexOf(x) {
let index = null, n = this.elements.length, k = n, i;
do {
i = k - n;
if (index === null && this.elements[i].valueOf() === x.valueOf()) {
index = i + 1;
}
} while (--n);
return index;
}
text() {
return (0, Text_1.text)(this);
}
toString() {
return this.text();
}
latex(option) {
let tex = [];
for (let i = 0; i < this.elements.length; i++) {
tex.push(LaTeX_1.LaTeX.latex.call(LaTeX_1.LaTeX, this.elements[i], option));
}
return '[' + tex.join(', ') + ']';
}
}
exports.Vector = Vector;
//# sourceMappingURL=Vector.js.map