Files
JavaScript/linear-algebra-javascript/src/la_lib.ts
Christian Bender d937885036 Add files via upload
2018-03-09 20:57:20 +01:00

343 lines
11 KiB
TypeScript

/*
author: Christian Bender
license: MIT-license
The namespace LinearAlgebra contains useful classes and functions for dealing with
linear algebra under JavaScript.
*/
namespace LinearAlgebra {
/*
class: Vector
This class represents a vector of arbitrary size and operations on it.
*/
export class Vector {
// the vector components
private components: number[];
// constructor
constructor(N: number, comps: number[] = []) {
this.components = new Array(N);
if (comps.length == 0) { // creates a zero vector of size N
for (var i = 0; i < N; i++) {
this.components[i] = 0.0;
}
} else { // assigns the components
if (N == comps.length) {
this.components = comps;
} else {
throw "Vector: invalide size!";
}
}
} // end of constructor
// returns the size of this vector.
// not the eulidean length!
size(): number {
return this.components.length;
}
// computes the eulidean length.
eulideanLength(): number {
var sum: number = 0;
for (var i = 0; i < this.components.length; i++) {
sum += this.components[i] * this.components[i];
}
return Math.sqrt(sum);
}
// getter for the components of the vector.
// returns a specified component (index)
component(index: number): number {
return this.components[index];
}
// setter for a specified component of this vector.
changeComponent(index: number, value: number): void {
if (index >= 0 && index < this.components.length) {
this.components[index] = value;
} else { // error case
throw "changeComponent: index out of bounds!";
}
}
// vector addition
add(other: Vector): Vector {
if (this.size() == other.size()) {
var SIZE = this.size();
var ans: Vector = new Vector(SIZE);
for (var i = 0; i < SIZE; i++) {
ans.changeComponent(i, (this.components[i] + other.component(i)));
}
return ans;
} else {
throw "add: vector must have same size!";
}
}
// vector subtraction
sub(other: Vector): Vector {
if (this.size() == other.size()) {
var SIZE = this.size();
var ans: Vector = new Vector(SIZE);
for (var i = 0; i < SIZE; i++) {
ans.changeComponent(i, (this.components[i] - other.component(i)));
}
return ans;
} else { // error case
throw "add: vector must have same size!";
}
}
// dot-product
dot(other: Vector): number {
var sum: number = 0;
if (other.size() == this.size()) {
const SIZE: number = other.size();
for (var i = 0; i < SIZE; i++) {
sum += this.components[i] * other.component(i);
}
return sum;
} else { // error case
throw "dot: vectors must have same size!";
}
}
// scalar multiplication
scalar(s: number): Vector {
const SIZE: number = this.size();
var ans: Vector = new Vector(SIZE);
for (var i = 0; i < SIZE; i++) {
ans.changeComponent(i, (this.components[i] * s));
}
return ans;
}
// returns a string representation of this vector.
toString(): string {
var ans: string = "(";
var SIZE: number = this.components.length;
for (var i = 0; i < SIZE; i++) {
if (i < SIZE - 1) {
ans += this.components[i] + ",";
} else {
ans += this.components[i] + ")";
}
}
return ans;
}
// converts this vector in a unit basis vector and returns it.
// the One is on position 'pos'
createUnitBasis(pos: number): Vector {
if (pos >= 0 && pos < this.components.length) {
for (var i = 0; i < this.components.length; i++) {
if (i == pos) {
this.components[i] = 1.0;
} else {
this.components[i] = 0.0;
}
}
} else { // error case
throw "createUnitBasis: index out of bounds";
}
return this;
}
// normalizes this vector and returns it.
norm(): Vector {
const SIZE: number = this.size();
var quotient = 1.0 / this.eulideanLength();
for (var i = 0; i < SIZE; i++) {
this.components[i] = this.components[i] * quotient;
}
return this;
}
// returns true if the vectors are equal otherwise false.
equal(other: Vector): boolean {
var ans: boolean = true;
const SIZE: number = this.size();
const EPSILON: number = 0.001;
if (SIZE == other.size()) {
for (var i = 0; i < SIZE; i++) {
if (Math.abs(this.components[i] - other.component(i)) > EPSILON) {
ans = false;
}
}
} else {
ans = false;
}
return ans;
}
} // end of class Vector
// -------------- global functions ---------------------------------
// returns a unit basis vector of size N with a One on position 'pos'
export function unitBasisVector(N: number, pos: number): Vector {
var ans = new Vector(N);
for (var i = 0; i < N; i++) {
if (i == pos) {
ans.changeComponent(i, 1.0);
} else {
ans.changeComponent(i, 0);
}
}
return ans;
}
// returns a random vector with integer components (between 'a' and 'b') of size N.
export function randomVectorInt(N: number, a: number, b: number): Vector {
var ans: Vector = new Vector(N);
for (var i = 0; i < N; i++) {
ans.changeComponent(i, (Math.floor((Math.random() * b) + a)));
}
return ans;
}
// returns a random vector with floating point components (between 'a' and 'b') of size N.
export function randomVectorFloat(N: number, a: number, b: number): Vector {
var ans: Vector = new Vector(N);
for (var i = 0; i < N; i++) {
ans.changeComponent(i, ((Math.random() * b) + a));
}
return ans;
}
// ------------------ end of global functions -----------------------------
/*
class: Matrix
This class represents a matrix of arbitrary size and operations on it.
*/
export class Matrix {
// private field that contains the actual matrix.
private matrix: number[][];
// private field for the dimension of the matrix
private rows: number;
private cols: number;
// constructor for zero-matrix or fix number matrix.
constructor(row: number, col: number, comps: number[][] = []) {
if (comps.length == 0) { // zero-matrix
this.matrix = new Array();
var rowVector: number[] = new Array();
for (var i = 0; i < row; i++) {
for (var j = 0; j < col; j++) {
rowVector[j] = 0;
}
this.matrix[i] = rowVector;
rowVector = new Array();
}
} else { // fix number matrix
this.matrix = comps;
}
this.rows = row;
this.cols = col;
}
// returns the specified component.
component(x: number, y: number): number {
if (x >= 0 && x < this.rows && y >= 0 && y < this.cols) {
return this.matrix[x][y];
} else { // error case
throw new Error("component: index out of bounds");
}
}
// changes the specified component with value 'value'.
changeComponent(x: number, y: number, value: number): void {
if (x >= 0 && x < this.rows && y >= 0 && y < this.cols) {
this.matrix[x][y] = value;
} else {
throw new Error("changeComponent: index out of bounds");
}
}
// returns a string representation of this matrix.
toString(): string {
var ans: string = "";
for (var i = 0; i < this.rows; i++) {
ans += "|";
for (var j = 0; j < this.cols; j++) {
if (j < this.cols - 1) {
ans += this.matrix[i][j] + ",";
} else {
if (i < this.rows - 1) {
ans += this.matrix[i][j] + "|\n";
} else {
ans += this.matrix[i][j] + "|";
}
}
}
}
return ans;
}
// returns the dimension rows x cols as number array
dimension(): number[] {
var ans: number[] = new Array();
ans[0] = this.rows;
ans[1] = this.cols;
return ans;
}
// matrix addition. returns the result.
add(other: Matrix): Matrix {
if (this.rows == other.dimension()[0]
&& this.cols == other.dimension()[1]) {
var ans = new Matrix(this.rows, this.cols);
for (var i = 0; i < this.rows; i++) {
for (var j = 0; j < this.cols; j++) {
ans.changeComponent(i, j, (this.matrix[i][j] + other.component(i, j)));
}
}
return ans;
} else {
throw new Error("add: matrices must have same dimension!");
}
}
// returns true if the matrices are equal, otherwise false.
equal(other: Matrix): boolean {
var ans: boolean = true;
const EPSILON: number = 0.001;
if (this.rows == other.dimension()[0]
&& this.cols == other.dimension()[1]) {
for (var i = 0; i < this.rows; i++) {
for (var j = 0; j < this.cols; j++) {
if (Math.abs(this.matrix[i][j] - other.component(i, j)) > EPSILON) {
ans = false;
}
}
}
} else {
ans = false;
}
return ans;
}
// matrix-scalar multiplication
scalar(c: number): Matrix {
var ans = new Matrix(this.rows, this.cols);
for (var i = 0; i < this.rows; i++) {
for (var j = 0; j < this.cols; j++) {
ans.changeComponent(i, j, (this.matrix[i][j] * c));
}
}
return ans;
}
} // end of class Matrix
} // end of namespace LinearAlgebra