Coder Social home page Coder Social logo

mateogianolio / vectorious Goto Github PK

View Code? Open in Web Editor NEW
911.0 18.0 45.0 12.52 MB

Linear algebra in TypeScript.

Home Page: https://docs.vectorious.org/vectorious/6.1.12

License: MIT License

JavaScript 2.76% TypeScript 97.24%
blas javascript matrix vector linear-algebra high-performance-computing machine-learning linear-algebra-library typescript

vectorious's Introduction

Vectorious Logo

A linear algebra library, written in TypeScript and accelerated with C++ bindings to BLAS and LAPACK.

Installation

Follow the installation instructions in nlapack and nblas to get maximum performance.

# with C++ bindings
$ npm install vectorious

# or, if you don't want C++ bindings
$ npm install vectorious --no-optional

There are three output bundles exposed in this package.

CommonJS

A node.js bundle, can be found in dist/index.js and imported with the require() syntax:

const v = require('vectorious');

Browser

A browser bundle, can be found in dist/index.browser.js and imported with the <script> tag:

<script src="dist/index.browser.js" />

It exposes a global variable named v in the window object and can be accessed like this:

<script>
  const x = v.array([1, 2, 3]);
</script>

ES module

Added in version 6.1.0, vectorious exposes an ES module bundle at dist/index.mjs which can be imported using the import syntax:

import { array } from 'vectorious';

const x = array([1, 2, 3]);

Usage

Unless stated otherwise, all operations are in-place, meaning that the result of the operation overwrites data in the current (or in the static case leftmost) array. To avoid this, an explicit copy call is needed before the operation (copy(x) or x.copy()).

import { array, random, range } from 'vectorious';

// Create a random 2x2 matrix
const x = random(2, 2);
/*
array([
  [
    0.26472008228302,
    0.4102575480937958
  ],
  [
    0.4068726599216461,
    0.4589384198188782
  ]
], dtype=float64)
*/

// Create a one-dimensional vector with values from
// 0 through 8 and reshape it into a 3x3 matrix
const y = range(0, 9).reshape(3, 3);
/*
array([
  [ 0, 1, 2 ],
  [ 3, 4, 5 ],
  [ 6, 7, 8 ]
], dtype=float64)
*/

// Add the second row of x to the first row of x
y.slice(0, 1).add(y.slice(1, 2));
/*
array([
  [ 3, 5, 7 ],
  [ 3, 4, 5 ],
  [ 6, 7, 8 ]
], dtype=float64)
*/

// Swap the first and second rows of x
y.swap(0, 1);
/*
array([
  [ 3, 4, 5 ],
  [ 3, 5, 7 ],
  [ 6, 7, 8 ]
], dtype=float64)
*/

// Create a 2x2x1 tensor
const z = array([
  [[1], [2]],
  [[3], [4]],
]);
/*
array([
  [ [ 1 ], [ 2 ] ],
  [ [ 3 ], [ 4 ] ]
], dtype=float64)
*/

Documentation

Examples

Basic

Machine learning

Testing

All functions are accompanied with a .spec.ts file.

The Jest testing framework is used for testing and the whole test suite can be run using a single command:

$ npm test

Benchmarks

All functions are accompanied with a .bench.ts file.

Run all benchmarks with:

$ npm run benchmark

Or for a single function with:

$ npx ts-node src/core/abs.bench.ts

vectorious's People

Contributors

akdor1154 avatar bartvanandel avatar beraliv avatar christianbender avatar dependabot[bot] avatar greenkeeper[bot] avatar lucidrains avatar majiang avatar mateogianolio avatar metabench avatar mjschock avatar monkeywithacupcake avatar pvnr0082t avatar rotu avatar waylonflinn avatar xuefeng-zhu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vectorious's Issues

Tests

@mateogianolio do you have experience with unit testing, maybe the automatic kind that's integrated into github? I'm not experienced in doing that(yet), perhaps it should be a part of this project?

Expose the nBLAS API

I think it could be useful to export the nBLAS API as e.g. vectorious.blas, which could then be used as follows:

var v = require('vectorious');

var a = new v.Matrix([[1, 2, 3]]),
    size = a.shape[0] * a.shape[1];

v.blas.dasum(size, a.data, 1);
// 6

var b = new v.Matrix([[3], [2], [1]]);

v.blas.dswap(size, a.data, 1, b.data, 1);
// a and b data is swapped

v.blas.ddot(size, a.data, 1, b.data, 1);
// 10

Checking static methods in test

Can we please have some tests for the static methods? Such as the static version of add, and the new API for range?

Also we should stop testing the range instance method soon as it will no longer be part of the documented API (I think we reached agreement on that issue).

Benchmarks

Both to help direct development, and to show the performance of the code to users, there should be benchmarks.

These benchmarks need to be runnable from node.js. We will need to keep track of:

the hardware it's running on
the OS
the node/iojs version
the software vector implementation we are testing
the resulting time taken

Is there an existing benchmark module we should be using? Otherwise I'll write some code that will take these measurements and log them.

Tests failing in opt-js brankch

I just copied over the tests, but I get a lot of test fails...

C:\Users\James\Documents\GitHub\vectorious>mocha


  Vector
    .add()
      V should return empty vector if adding two empty vectors
      1) should throw error if sizes do not match
      V should work as expected
    .subtract()
      V should return empty vector if subtracting two empty vectors
      2) should throw error if sizes do not match
      V should work as expected
    .scale()
      V should work as expected
    .normalize()
      3) should work as expected
    .project()
      4) should throw error if sizes do not match
      5) should work as expected
    .zeros()
      V should throw error if argument < 0
      V should return empty vector if argument === 0
      V should work as expected
    .ones()
      V should throw error if argument < 0
      V should return empty vector if argument === 0
      V should work as expected
    .range()
      6) should throw error if wrong number or arguments supplied
      7) should throw error if step > start - end
      8) should work as expected
    .dot()
      9) should throw error if sizes do not match
      V should work as expected
    .magnitude()
      10) should return 0 if empty vector
      V should work as expected
    .angle()
      V should work as expected
    .equals()
      V should work as expected
    .get()
      11) should throw error if index out of bounds
      V should work as expected
    .min()
      V should work as expected
    .max()
      V should work as expected
    .set()
      12) should throw error if index out of bounds
      V should work as expected
    .combine()
      V should return current vector if combined with empty vector
      V should work as expected
    .push()
      V should work as expected
    .map()
      V should work as expected
    .each()
      V should work as expected
    .toString()
      V should work as expected
    .toArray()
      V should work as expected


  26 passing (31ms)
  12 failing

  1) Vector .add() should throw error if sizes do not match:
     Error: the string "Error: sizes do not match!" was thrown, throw an Er
      at Runner.fail (C:\Users\James\AppData\Roaming\npm\node_modules\mocha
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at done (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  2) Vector .subtract() should throw error if sizes do not match:
     Error: the string "Error: sizes do not match!" was thrown, throw an Er
      at Runner.fail (C:\Users\James\AppData\Roaming\npm\node_modules\mocha
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at done (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  3) Vector .normalize() should work as expected:
     AssertionError: { values: [ 0.7071067811865475, 0.7071067811865475 ],
  length: 2 } deepEqual { values: [ 0.5, 0.5 ], length: 2 }
      at Context.<anonymous> (C:\Users\James\Documents\GitHub\vectorious\te
      at callFn (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  4) Vector .project() should throw error if sizes do not match:
     Error: the string "Error: sizes do not match!" was thrown, throw an Er
      at Runner.fail (C:\Users\James\AppData\Roaming\npm\node_modules\mocha
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at done (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  5) Vector .project() should work as expected:
     AssertionError: { values: [ 0.24, -0.32 ], length: 2 } deepEqual { val
      at Context.<anonymous> (C:\Users\James\Documents\GitHub\vectorious\te
      at callFn (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  6) Vector .range() should throw error if wrong number or arguments suppli
     Error: the string "Error: invalid range!" was thrown, throw an Error :
      at Runner.fail (C:\Users\James\AppData\Roaming\npm\node_modules\mocha
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at done (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  7) Vector .range() should throw error if step > start - end:
     Error: the string "Error: invalid range!" was thrown, throw an Error :
      at Runner.fail (C:\Users\James\AppData\Roaming\npm\node_modules\mocha
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at done (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  8) Vector .range() should work as expected:
     AssertionError: { values: [ 0, 1, 2, 3, 4 ], length: 5 } deepEqual { v
      at Context.<anonymous> (C:\Users\James\Documents\GitHub\vectorious\te
      at callFn (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  9) Vector .dot() should throw error if sizes do not match:
     Error: the string "Error: sizes do not match!" was thrown, throw an Er
      at Runner.fail (C:\Users\James\AppData\Roaming\npm\node_modules\mocha
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at done (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  10) Vector .magnitude() should return 0 if empty vector:
     TypeError: Reduce of empty array with no initial value
      at Array.reduce (native)
      at Vector.magnitude (C:\Users\James\Documents\GitHub\vectorious\vecto
      at Context.<anonymous> (C:\Users\James\Documents\GitHub\vectorious\te
      at callFn (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  11) Vector .get() should throw error if index out of bounds:
     AssertionError: Missing expected exception (Error)..
      at Function._throws (assert.js:306:5)
      at Function.assert.throws (assert.js:323:11)
      at Context.<anonymous> (C:\Users\James\Documents\GitHub\vectorious\te
      at callFn (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

  12) Vector .set() should throw error if index out of bounds:
     AssertionError: Missing expected exception (Error)..
      at Function._throws (assert.js:306:5)
      at Function.assert.throws (assert.js:323:11)
      at Context.<anonymous> (C:\Users\James\Documents\GitHub\vectorious\te
      at callFn (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\
      at Test.Runnable.run (C:\Users\James\AppData\Roaming\npm\node_modules
      at Runner.runTest (C:\Users\James\AppData\Roaming\npm\node_modules\mo
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\runner.j
      at next (C:\Users\James\AppData\Roaming\npm\node_modules\mocha\lib\ru
      at Immediate._onImmediate (C:\Users\James\AppData\Roaming\npm\node_mo
      at processImmediate [as _immediateCallback] (timers.js:357:17)

Are the tests working for you on the opt-js branch? I don't think all these errors should be thrown, I'm not sure what's going on here.

Browser version doesn't make Vector class available

I do not know if this is desired behavior, but when using vectorious in the browser (via the vectorious-4.1.4.js file made available in the Releases, only the Matrix class is made available in the global namespace.
This seems to be the behavior when using vectorious as a node module.
Vector objects are still functional, when using the Matrix.toVector() function, but it would be more convenient to have the ability to use Vector instead.

API Extension Proposal - More Static Methods

I think it's worth having static methods for add and various other functions that take two vectors as arguments. This would enable the user to have more flexibility in how they use the library.

This is like what you had changed the API to in master, but I'm not suggesting removing the existing API that works from Vector.prototype. Having these as static methods in their different forms would be useful. I was not against having those methods as static, just against removing the non-static versions. Now I've moved onto some other things I think it would be a useful addition rather than a bad substitution, given users' expectations.

It would also help with compression of code, but it's a somewhat longwinded explanation, but it's that UglifyJS can compress the names of local variables but not property names. The functions would be writeable as local variables, so would uglify-js to smaller code.

It also probably fits in with ideas of functional programming.

Because JavaScript lacks operator overloading, people are left with imperfect answers. I think it's better to provide two of them that would both be useful.

Massive API changes in master

I've noticed that Vector.prototype.add no longer does what it used to do, or what is documented.

Currently, it does not add two vectors together, producing a resultant vector, documented as

// (Vector, Vector) => (Vector)
Vector.prototype.add = function(vector)

It just does not do that with the new implementation. It adds b to a.

This is taken from the old code:

Vector.prototype.add = function(vector) {
    if(this.length !== vector.length)
      throw 'Error: sizes do not match!';

    return Vector.construct(this.values.map(function(value, index) {
      return value + vector.values[index];
    }));
  };

It constructs a new vector.

Bug 1: Vector equals

I've called this Bug 1

It does not work as it's supposed to, I've given it vectors that are not equal, but it said they were equal. I've made a fast version that works as far as I can tell.

This is something that it would be nice to have a test suite to find, but I found this just by coding an example. The examples are of some use in testing but eventually we should have automated tests.

Documentation: Order of Vector and Matrix

I think we should introduce the Vector before the Matrix. Matrix uses Vector, not the other way round, so introducing Vector makes sense to better help users get an understanding of Vectorious.

Also, would you please add a 'documentation' label? I think I can't do it as a committer but you can do it as the project owner.

Complex numbers

Vector/Matrix enhancement proposal. Complex data in C:

typedef struct {
  double re;
  double im;
} complex16;

typedef struct {
  float re;
  float im;
} complex8;

// example cblas functions
extern "C" int cblas_icamax (
  const int n,
  const complex8 *x,
  const int inc_x
);

extern "C" int cblas_izamax (
  const int n,
  const complex16 *x,
  const int inc_x
);

How would one reinterpret a javascript object as a C struct?

API addition: Matrix.magic()

Creates a magic square matrix, like magic() in MATLAB.

Matrix.magic(3) should result in the following matrix:

[
    [8, 1, 6],
    [3, 5, 7],
    [4, 9, 2]
]

Sparse vector/matrix routines

Could be useful to introduce sparse matrices by adding a stride option to Matrix.prototype and performing operations with this in mind.

Pulling changes from opt-js to master?

@mateogianolio, I've noticed you have rewritten some code in Vector. I'd rewritten parts of it and pushed it to opt-js. I'm not sure if you looked at the code I wrote and then wrote it yourself in a style you prefer, or did not see the code.

I also thought we would be working on the optimized branch, testing it, and then pushing it over to master when a bunch of things were seen to be ready. I still think that is the best way to proceed, and if in the meantime you are making changes to master (and possibly npm) I don't see the problem with that. I think there have been some duplicated efforts recently though, but if we both enjoy coding then maybe that's not a problem either.

Do you have specific ideas about the style of the code, or will it be decided by what works best in benchmarks or tests?

Random

Matrix.random(m, n) and Vector.random(n) could be a useful addition.

Added travis build status

Just added Travis CI for this repository. That means that every time we git push it will run testing (mocha) and update the readme with build passing/failing.

Prepare master for merge

Here is a short post on how to rewind the master branch:

$ git reset --hard 0e4df12
$ git push --force origin master

Rewinding to 0e4df12 will enable automatic merging with opt-js.

Normal distribution

Adding the ability of generating a matrix or vector according to a normal distribution seems like a great addition to the library.

API Change Suggestion: Vector range

The readme says 'Create a vector containing the range from start to end in steps of step (optional).' This looks more like it should be a static method of Vector, rather than a method of a Vector instance. To do that it would be assigned to Vector rather than Vector.prototype

Looking at the code, range pushes values onto an existing Vector instance. That behaviour is not defined in the API, but for the moment it's being used in my first vector.range example. I got unexpected results where I tried to add the range 100 to 105, using .range(100, 105), but it only pushed the numbers 100 to 103 onto the vector.

We should clarify what range is supposed to do, then get it to do that, possibly using a static method.

Matrix lines 10-28 (constructor)... what do they do?

I already see it's using [].slice.call(arguments, 0) which I plan on changing.

With the other parts, it would help to have an explanation of what it should be doing, then I'll think about how to best express that in JavaScript. The answer to the question about the Vector constructor was very helpful

There will be a lot of speed increases in Matrix.

Matrix.augment bug adding NaN values to matrix

I'm pushing a fix right now, just thought it should be mentioned in an issue because it wasn't caught by the test suite.

Error (lines 528-534 in matrix.js):

for (i = 0; i < r1; i++)
  for (j = 0; j < c1; j++)
    data[i * (c1 + c2) + j] = d1[i * r1 + j];

for (i = 0; i < r1; i++)
  for (j = 0; j < c2; j++)
    data[i * (c1 + c2) + j + c1] = d2[i * r1 + j];

Fix:

for (i = 0; i < r1; i++)
  for (j = 0; j < c1; j++)
    data[i * (c1 + c2) + j] = d1[i * c1 + j];

for (i = 0; i < r2; i++)
  for (j = 0; j < c2; j++)
    data[i * (c1 + c2) + j + c1] = d2[i * c2 + j];

Getting rid of memcpy dependency

The memcpy dependency requires node version <=0.12 and should be replaced to be able to make the package work with the newest (and future) node versions.

API addition: Matrix.inverse()

Matrix inverses are essential to linear algebra and I'm suggesting we add it to the API. A (somewhat vague) description of the algorithm can be found here.

Versioning

For the purpose of structure and consistency, we should decide how to version releases. Up until now, I have just incremented the version number when changing something: 1.0.0 => 1.0.1 => ... => 1.0.9 => 1.1.0.

I'm suggesting version 2.0.0 as the point where we've converted everything to typed arrays and successfully implemented C/C++ bindings to the extent that we can call it a stable library suitable for use in production environments.

How about working together on some optimizations?

I thought I should mention these things to see what direction you want to take the project in. I've done some work already that's a bit similar (not published yet) that simulates a table of numbers, and uses a typed array as the storage. Maybe you should use typed arrays here? What do you think? It would lose some flexibility because the typed array needs to be initialised with a fixed size, but operations are faster after that.

Then there is the possibility of writing C/C++ addon code. A few functions could be written in (mainly) C, using C++ bindings to node, and some operations would be a fair bit faster.

There would also then be the possibility of using SIMD to get higher speeds still, with intrinsics in the C++ code. I'd need to look into cross-platform compatibility for that, and find ways to only use particular SIMD instructions when they are available.

Which of these are directions you would be interested in taking vectorious?

More changes to static methods: Vector zeros, Vector ones

These methods also look best as static methods because they have no effect on the instance which they are currently being called from.

This change should appear in 2.0.0.

I'm writing to confirm this, I think you'll be OK with it, but do you think I should just go ahead and make this kind of change or bring it up as an issue first?

Policy on API changes

How should we handle changes that could break an app that relies on an API being as it is?

I'm thinking with regards to possibly removing Vector.prototype.range and having it as the static method Vector.range.

Could it be worth deprecating Vector.prototype.range with the goal of eventually removing it?

Further Progress - Versions 3 and 4

Version 2.1.0 of node's Nan (https://github.com/nodejs/nan) has introduced Nan::TypedArrayContents (https://github.com/nodejs/nan/blob/master/doc/v8_misc.md#nantypedarraycontents), which provides stability and a seemingly convenient interface to access Typed Arrays from within C++ addons.

From the look of things, much optimization has been done in versions 2.x.x. Though the version 3 milestone says 'fully optimized' I don't think we would be sure of reaching that because it would take a while longer to prove everything is at maximum optimization. Perhaps it means 'fully optimized' within the scope of how much optimization we will do to the JavaScript code.

I am keen on using Typed Arrays and accessing them from C++ code to speed up some operations. It will also require care to ensure that the project keeps the right structure and compatibility, as it becomes more complicated by introducing compiled C++ code.

API addition: Matrix.determinant()

Matrix determinants are essential to linear algebra (for example calculating areas, volumes, etc) and I'm suggesting we add it to the API as well.

Matrix row/column addition

Proposal:

Adds a multiple of one row to another inside a matrix.

// (Matrix, Number, Number, Number) => (Matrix)
Matrix.rowAdd = function (matrix, i, j, scalar)

// (this, Number, Number, Number) => (this)
Matrix.prototype.rowAdd = function (i, j, scalar)

Example:

var m = new Matrix([[1, 2], [3, 4]]);
m.rowAdd(0, 1, 10);
// [[31, 42], [3, 4]]

Same for columns.

Inspiration for C/C++ optimizations

Eigen, a C++ template library for linear algebra: matrices, vectors, numerical solvers, and related algorithms.

Currently used by e.g. Google's TensorFlow and the ATLAS experiment at the LHC at CERN.

Optimization suggestion: Don't make as many function calls

I am seeing a lot of code like this.values.map(function(. Using more procedural code would probably speed it up. A for loop does not need to call a function on each iteration. Benchmarking would tell if this actually does make for an improvement in the speed, but I think it's an avenue worth perusing.

Though we could (probably) use an equivalent of map in C or C++, it's easier to port functions that correspond almost directly with simple, idiomatic C code.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.