From d937885036a2380b65653b804a0674c9ead8c075 Mon Sep 17 00:00:00 2001 From: Christian Bender Date: Fri, 9 Mar 2018 20:57:20 +0100 Subject: [PATCH] Add files via upload --- linear-algebra-javascript/README.md | 114 +++++++ linear-algebra-javascript/package-lock.json | 171 ++++++++++ linear-algebra-javascript/package.json | 17 + linear-algebra-javascript/src/la_lib.js | 325 +++++++++++++++++++ linear-algebra-javascript/src/la_lib.ts | 342 ++++++++++++++++++++ linear-algebra-javascript/test/test.js | 170 ++++++++++ 6 files changed, 1139 insertions(+) create mode 100644 linear-algebra-javascript/README.md create mode 100644 linear-algebra-javascript/package-lock.json create mode 100644 linear-algebra-javascript/package.json create mode 100644 linear-algebra-javascript/src/la_lib.js create mode 100644 linear-algebra-javascript/src/la_lib.ts create mode 100644 linear-algebra-javascript/test/test.js diff --git a/linear-algebra-javascript/README.md b/linear-algebra-javascript/README.md new file mode 100644 index 000000000..8c0fd79ab --- /dev/null +++ b/linear-algebra-javascript/README.md @@ -0,0 +1,114 @@ +# Linear algebra library for JavaScript + +This library contains some useful classes and functions for dealing with linear algebra in JavaScript. +The library was orginal written in **TypeScript** and then compiles into pure JavaScript. + +--- + +## Overview + +- class Vector : This class represents a vector of arbitray size and operations on it. + - constructor Vector(N) : creates a zero vector of size N + - constructor Vector(N, components) : creates a vector of size N with the given components. + - createUnitBasis(pos) : converts this vector in a unit basis vector and returns it. + - component(pos) : returns the specified component (indexing at 0) + - changeComponent(pos, value) : change the specified component. + - toString() : returns a string representation of this vector. + - size() : returns the size of the vector. (not the eulidean length!) + - eulideanLength() : computes the eulidean length of this vector. + - add(other) : vector addition, returns the rersult. + - sub(other) : vector subtraction, returns the rersult. + - dot(other) : computes the dot-product and returns it. + - scalar(s) : scalar (s) multiplication. returns the result. + - norm() : normalizes this vector and returns it. + - equal(other) : returns true if the vectors are equal, otherwise false. + +- function unitBasisVector(N,pos) : returns a unit basis vector of size N with a One on position 'pos' +- function randomVectorInt(N,a,b) : returns a random vector with integer components (between 'a' and 'b') of size N. +- function randomVectorFloat(N,a,b) : returns a random vector with floating point components (between 'a' and 'b') of size N. + +- class Matrix : This class represents a matrix of arbitrary size and operations on it. + - constructor(rows, cols) : creates a zero matrix of dimension rows x cols. + - constructor(rows, cols, components) : creates a matrix with fix numbers of dimension rows x cols. + - component(x,y) : returns the specified component. + - changeComponent(x,y,value) : changes the specified component with the new value 'value'. + - toString() : returns a string representation of this matrix. + - dimension() : returns the dimension of this matrix as number arras [rows,cols]. + - add(other) : returns the result of the matrix addition. + - equal(other) : returns true if the matrices are equal, otherwise false. + - scalar(c) : returns the result of the matrix-scalar multiplication. +--- + +## Documentation + +The module is well documented in its source code. Look in the TypeScript file ```la_lib.ts```. + +--- + +## Usage + +You will find the library in the **src** directory its called ```la_lib.js```. You simply need to +include this library in your project **(you don't install anything)**. After that: + +```js + var x = LinearAlgebra.Vector(...); +``` + +The namespace LinearAlgebra contains useful classes and functions for dealing with linear algebra under JavaScript. + +Some examples: + +```js +// ---------------------------- Examples ------------------------------------------ + +// creates vectors +var x = new LinearAlgebra.Vector(5, [1, 2, 3, 4, 5]); +var y = new LinearAlgebra.Vector(5, [1, 2, 3, 4, 5]); + +// prints size of the vector +console.log(x.size()); // ==> 5 + +// changes the 2-th component with 7 +//x.changeComponent(2,7); + +// print the 2-th component. +console.log(x.component(2)); // ==> 3 + +// prints the full vector as string. +console.log(x.toString()); // ==> (1,2,3,4,5) + +// vector addition +console.log(x.add(y).toString()); // ==> (2,3,6,8,10) + +//console.log(x.createUnitBasis(1).toString()); + +// computes the dot-product +console.log(x.dot(y)); // ==> 55 + +// computes and prints the scalar-product +console.log(x.scalar(5).toString()); // ==> (5,10,15,20,25) + +// creates a unit basis vector +console.log(LinearAlgebra.unitBasisVector(3, 0).toString()); // ==> (1,0,0) + +// creates random vectors +console.log(LinearAlgebra.randomVectorInt(3, 0, 5).toString()); +console.log(LinearAlgebra.randomVectorFloat(3, 0, 5).toString()); +``` + +--- + +## Tests + +Go in the directory of the project and type in: +```npm install``` +```npm test``` +The test-suite use the JavaScript test-framework **mocha**. + +--- + +## Contributing + +You can contribute to this project. Feel free and pull request some new features or documention. +**TODO:** Global functions for special matrices. +**TODO:** Documention of the classes and functions. \ No newline at end of file diff --git a/linear-algebra-javascript/package-lock.json b/linear-algebra-javascript/package-lock.json new file mode 100644 index 000000000..1492a09ee --- /dev/null +++ b/linear-algebra-javascript/package-lock.json @@ -0,0 +1,171 @@ +{ + "name": "linear-algebra-javascript", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==" + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "diff": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", + "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "growl": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", + "integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==" + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.2.tgz", + "integrity": "sha512-nmlYKMRpJZLxgzk0bRhcvlpjSisbi0x1JiRl7kctadOMPmecUie7WwCZmcyth+PzX5txKbpcMIvDZCAlx9ISxg==", + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.11.0", + "debug": "3.1.0", + "diff": "3.3.1", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.3", + "he": "1.1.1", + "mkdirp": "0.5.1", + "supports-color": "4.4.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "requires": { + "has-flag": "2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} diff --git a/linear-algebra-javascript/package.json b/linear-algebra-javascript/package.json new file mode 100644 index 000000000..1631a3f9a --- /dev/null +++ b/linear-algebra-javascript/package.json @@ -0,0 +1,17 @@ +{ + "name": "linear-algebra-javascript", + "version": "1.0.0", + "description": "simple linear algebra library for JavaScript", + "main": "index.js", + "directories": { + "test": "test" + }, + "scripts": { + "test": "mocha" + }, + "author": "Christian Bender", + "license": "MIT", + "dependencies": { + "mocha": "^5.0.2" + } +} diff --git a/linear-algebra-javascript/src/la_lib.js b/linear-algebra-javascript/src/la_lib.js new file mode 100644 index 000000000..cd4d8e23f --- /dev/null +++ b/linear-algebra-javascript/src/la_lib.js @@ -0,0 +1,325 @@ +/* + author: Christian Bender + license: MIT-license + + The namespace LinearAlgebra contains useful classes and functions for dealing with + linear algebra under JavaScript. +*/ +var LinearAlgebra; +(function (LinearAlgebra) { + /* + class: Vector + This class represents a vector of arbitrary size and operations on it. + */ + var Vector = /** @class */ (function () { + // constructor + function Vector(N, comps) { + if (comps === void 0) { comps = []; } + this.components = new Array(N); + if (comps.length == 0) { + for (var i = 0; i < N; i++) { + this.components[i] = 0.0; + } + } + else { + 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! + Vector.prototype.size = function () { + return this.components.length; + }; + // computes the eulidean length. + Vector.prototype.eulideanLength = function () { + var sum = 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) + Vector.prototype.component = function (index) { + return this.components[index]; + }; + // setter for a specified component of this vector. + Vector.prototype.changeComponent = function (index, value) { + if (index >= 0 && index < this.components.length) { + this.components[index] = value; + } + else { + throw "changeComponent: index out of bounds!"; + } + }; + // vector addition + Vector.prototype.add = function (other) { + if (this.size() == other.size()) { + var SIZE = this.size(); + var ans = 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 + Vector.prototype.sub = function (other) { + if (this.size() == other.size()) { + var SIZE = this.size(); + var ans = 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!"; + } + }; + // dot-product + Vector.prototype.dot = function (other) { + var sum = 0; + if (other.size() == this.size()) { + var SIZE = other.size(); + for (var i = 0; i < SIZE; i++) { + sum += this.components[i] * other.component(i); + } + return sum; + } + else { + throw "dot: vectors must have same size!"; + } + }; + // scalar multiplication + Vector.prototype.scalar = function (s) { + var SIZE = this.size(); + var ans = 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. + Vector.prototype.toString = function () { + var ans = "("; + var SIZE = 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' + Vector.prototype.createUnitBasis = function (pos) { + 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 { + throw "createUnitBasis: index out of bounds"; + } + return this; + }; + // normalizes this vector and returns it. + Vector.prototype.norm = function () { + var SIZE = 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. + Vector.prototype.equal = function (other) { + var ans = true; + var SIZE = this.size(); + var EPSILON = 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; + }; + return Vector; + }()); // end of class Vector + LinearAlgebra.Vector = Vector; + // -------------- global functions --------------------------------- + // returns a unit basis vector of size N with a One on position 'pos' + function unitBasisVector(N, pos) { + 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; + } + LinearAlgebra.unitBasisVector = unitBasisVector; + // returns a random vector with integer components (between 'a' and 'b') of size N. + function randomVectorInt(N, a, b) { + var ans = new Vector(N); + for (var i = 0; i < N; i++) { + ans.changeComponent(i, (Math.floor((Math.random() * b) + a))); + } + return ans; + } + LinearAlgebra.randomVectorInt = randomVectorInt; + // returns a random vector with floating point components (between 'a' and 'b') of size N. + function randomVectorFloat(N, a, b) { + var ans = new Vector(N); + for (var i = 0; i < N; i++) { + ans.changeComponent(i, ((Math.random() * b) + a)); + } + return ans; + } + LinearAlgebra.randomVectorFloat = randomVectorFloat; + // ------------------ end of global functions ----------------------------- + /* + class: Matrix + This class represents a matrix of arbitrary size and operations on it. + */ + var Matrix = /** @class */ (function () { + // constructor for zero-matrix or fix number matrix. + function Matrix(row, col, comps) { + if (comps === void 0) { comps = []; } + if (comps.length == 0) { + this.matrix = new Array(); + var rowVector = 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 { + this.matrix = comps; + } + this.rows = row; + this.cols = col; + } + // returns the specified component. + Matrix.prototype.component = function (x, y) { + if (x >= 0 && x < this.rows && y >= 0 && y < this.cols) { + return this.matrix[x][y]; + } + else { + throw new Error("component: index out of bounds"); + } + }; + // changes the specified component with value 'value'. + Matrix.prototype.changeComponent = function (x, y, value) { + 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. + Matrix.prototype.toString = function () { + var ans = ""; + 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 + Matrix.prototype.dimension = function () { + var ans = new Array(); + ans[0] = this.rows; + ans[1] = this.cols; + return ans; + }; + // matrix addition. returns the result. + Matrix.prototype.add = function (other) { + 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. + Matrix.prototype.equal = function (other) { + var ans = true; + var EPSILON = 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 + Matrix.prototype.scalar = function (c) { + 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; + }; + return Matrix; + }()); // end of class Matrix + LinearAlgebra.Matrix = Matrix; +})(LinearAlgebra || (LinearAlgebra = {})); // end of namespace LinearAlgebra diff --git a/linear-algebra-javascript/src/la_lib.ts b/linear-algebra-javascript/src/la_lib.ts new file mode 100644 index 000000000..3b389f3f0 --- /dev/null +++ b/linear-algebra-javascript/src/la_lib.ts @@ -0,0 +1,342 @@ +/* + 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 + + diff --git a/linear-algebra-javascript/test/test.js b/linear-algebra-javascript/test/test.js new file mode 100644 index 000000000..d69c1f88a --- /dev/null +++ b/linear-algebra-javascript/test/test.js @@ -0,0 +1,170 @@ +/* + author: Christian Bender + license: MIT-license + + This file contains the test-suite for the linear algebra library. + The tests use javascript test-framework mocha +*/ + +var assert = require('assert'); +var fs = require('fs'); + +// file is included here +eval(fs.readFileSync('src/la_lib.js') + ''); + +// Tests goes here + +// creating some vectors +describe('Create Vectors', function () { + describe('#toString()', function () { + it('should return a string representation', function () { + assert.equal((new LinearAlgebra.Vector(3, [1, 2, 3])).toString(), "(1,2,3)"); + }); + }); + describe("#unitBasisVector()", function () { + it("should return a unit basis vector", function () { + assert.equal(LinearAlgebra.unitBasisVector(3, 1).toString(), "(0,1,0)"); + }); + }); +}); + +// operations on it. +describe("Vector operations", function () { + describe("#add()", function () { + it("should return vector (2,4,6)", function () { + var x = new LinearAlgebra.Vector(3, [1, 2, 3]); + var y = new LinearAlgebra.Vector(3, [1, 2, 3]); + assert.equal((x.add(y)).toString(), "(2,4,6)"); + }); + }); + describe("#sub()", function () { + it("should return vector (0,0,0)", function () { + var x = new LinearAlgebra.Vector(3, [1, 2, 3]); + var y = new LinearAlgebra.Vector(3, [1, 2, 3]); + assert.equal((x.sub(y)).toString(), "(0,0,0)"); + }); + }); + describe("#dot()", function () { + it("should return the dot-product", function () { + var x = new LinearAlgebra.Vector(3, [1, 2, 3]); + var y = new LinearAlgebra.Vector(3, [5, 6, 7]); + assert.equal(x.dot(y), 38); + }); + }); + describe("#scalar()", function () { + it("should return the scalar product", function () { + var x = new LinearAlgebra.Vector(3, [1, 2, 3]); + assert.equal(x.scalar(2).toString(), "(2,4,6)"); + }); + }); + describe("#norm()", function () { + it("should return the normalizes vector", function () { + var x = new LinearAlgebra.Vector(4, [9, 0, 3, 1]); + var y = x.norm(); + assert.ok(Math.abs(y.component(0) - (9.0 / Math.sqrt(91))) <= 0.01); + }); + }); + describe("#eulideanLength()", function () { + it("should return the eulidean length of the vector", function () { + var x = new LinearAlgebra.Vector(3, [1, 2, 2]); + assert.ok(Math.abs(x.eulideanLength() - 3) <= 0.001); + }); + }); + describe("#size()", function () { + it("should return the size (not eulidean length!) of the vector", function () { + var x = LinearAlgebra.randomVectorInt(10, 1, 5); + assert.equal(x.size(), 10); + }); + }); + describe("#equal()", function () { + it("should compares two vectors", function () { + var x = new LinearAlgebra.Vector(3, [1, 2, 2]); + var y = new LinearAlgebra.Vector(3, [1, 2, 3]); + assert.ok(x.equal(x)); + assert.ok(!x.equal(y)); + }); + }); +}); + +describe("Methods on vectors", function () { + describe("#component()", function () { + it("should return the specified component", function () { + var x = new LinearAlgebra.Vector(3, [1, 2, 2]); + assert.equal(x.component(1), 2); + }); + }); + describe("#changeComponent()", function () { + it("should return the changed vector", function () { + var x = new LinearAlgebra.Vector(3, [1, 2, 2]); + x.changeComponent(1, 5); + assert.equal(x.toString(), "(1,5,2)"); + }); + }); + describe("#toString()", function () { + it("should return a string representation of the vector", function () { + var x = new LinearAlgebra.Vector(4, [9, 0, 3, 1]); + assert.equal(x.toString(), "(9,0,3,1)"); + }); + }); +}); + + +describe("class Matrix", function () { + describe("#component()", function () { + it("should return the specified component", function () { + var A = new LinearAlgebra.Matrix(2, 2); + assert.equal(A.component(0, 1), 0); + var B = new LinearAlgebra.Matrix(2, 2, [[1, 2], [3, 4]]); + assert.equal(B.component(1, 0), 3); + }); + }); + describe("#toString()", function () { + it("should return a string representation of the matrix", function () { + var A = new LinearAlgebra.Matrix(2, 2, [[1, 2], [3, 4]]); + assert.equal(A.toString(), "|1,2|\n|3,4|"); + }); + }); + describe("#dimension()", function () { + it("should return the dimension of the matrix as number array", function () { + var A = new LinearAlgebra.Matrix(3, 2, [[1, 2], [3, 4], [5, 6]]); + assert.equal(A.dimension()[0], 3); + assert.equal(A.dimension()[1], 2); + }); + }); + describe("#changeComponent()", function () { + it("should change the specified component of the matrix", function () { + var A = new LinearAlgebra.Matrix(3, 2, [[1, 2], [3, 4], [5, 6]]); + A.changeComponent(1, 0, 5); + assert.equal(A.component(1, 0), 5); + }); + }); + describe("#equal()", function () { + it("should compares the matrices", function () { + var A = new LinearAlgebra.Matrix(3, 2, [[1, 2], [3, 4], [5, 6]]); + var B = new LinearAlgebra.Matrix(3, 2, [[1, 2], [3, 4], [5, 6]]); + var C = new LinearAlgebra.Matrix(2, 2, [[1, 2], [3, 4]]); + var D = new LinearAlgebra.Matrix(2, 2, [[1, 2], [5, 4]]); + assert.ok(A.equal(B)); + assert.ok(!A.equal(C)); + assert.ok(!C.equal(D)); + }); + }); + describe("#add()", function () { + it("should return the result of the matrix addition", function () { + var A = new LinearAlgebra.Matrix(3, 2, [[1, 2], [3, 4], [5, 6]]); + var B = new LinearAlgebra.Matrix(3, 2, [[1, 2], [3, 4], [5, 6]]); + var C = A.add(B); + assert.equal(C.component(1, 0), 6); + assert.equal(C.component(1, 1), 8); + assert.equal(C.component(0, 0), 2); + }); + }); + describe("#scalar()", function () { + it("should return the result of the matrix-scalar multiplication", function () { + var A = new LinearAlgebra.Matrix(3, 2, [[1, 2], [3, 4], [5, 6]]); + var B = A.scalar(2); + var C = new LinearAlgebra.Matrix(3, 2, [[2, 4], [6, 8], [10, 12]]); + assert.ok(B.equal(C)); + }); + }) +}); \ No newline at end of file