An introduction to stdlib

Why another library?

npm is the most popular package manager of any programming language.

stdlib

Downsides

  • package discovery
  • packages of varying quality
  • no consistent interfaces

 

jQuery

underscore

 

lodash

ramda

 

ES6

Beyond the Front-End
The Endless Frontier

  • Server programming (Node.js)
  • Databases (e.g., mongoDB client)
  • Desktop applications (electron)
  • Internet of Things (IoT) (Cylon.js, iot.js, JerryScript, Johnny-Five)
enlarge

The built-in JavaScript libraries are limited

stdlib in a nutshell

  • utilities you would expect from a standard library
  • collection of robust, high performance libraries for mathematics, statistics, data processing, streams, and more
  • as of April 2018, stdlib contains more than 2,000 functions
  • integrated REPL

Overview of stdlib

Special Functions

stdlib

Probability Distributions

stdlib

Seedable Pseudorandom Number Generators (PRNGs)


var r = normal( 2.0, 5.0 );
// draw from N(2,5) distribution

r = normal( 2.0, -2.0 );
// returns NaN

var rand = normal.factory({ 'seed': 12345 });

r = rand( 1.0, 2.0 );
// returns ~0.175

rand = normal.factory( 1.0, 2.0, { 'seed': 12345 });

r = rand();
// returns ~0.175
				

Utilities

stdlib

Assertions

stdlib

Datasets

stdlib

Plotting

stdlib

BLAS

stdlib

https://github.com/stdlib-js/stdlib

Current version:
0.34

Get stdlib

Option 1

Install via npm

Bundle via Webpack or browserify

Option 2

Distributable files for use in browser environments

Applications

Development of an e-learning platform for teaching data science built on stdlib

stdlib
stdlib

"See things not as they are, but as they might be"

Felix Adler

MATLAB (1984)

Mathematica (1988)

Python (1991)

R (1993)

Julia (2012)

 

stdlib

Job Postings on indeed.com

stdlib

Stack Overflow
Developer Survey 2018

stdlib
stdlib

stdlib provides building blocks for the future

ndarrays

  • multi-dimensional arrays are used in all of scientific computing
  • natively, JavaScript does not have such a data type

Common approach: Array-of-Arrays


var arr = [
  [ 1, 2, 3 ],
  [ 4, 5, 6 ],
  [ 7, 8, 9 ]
];
var x = arr[ 2 ][ 0 ];
				

Performance Issues

  • many object references
  • element access
  • ...

Solution:
Strided Arrays

3 by 3 Matrix
(ndarray shape: [3,3])

2 7 0
5 4 5
9 1 3

Underlying data buffer

  • C-style (row-major):
    2 7 0 5 4 5 9 1 3
  • Fortran-style (column major):
    2 5 9 7 4 1 0 5 3
  • single contiguous block of memory

ndarrays

  • used by most scientific computing libraries, including Numpy
  • prior art in JS: ndarray package by Mikola Lysenko
  • stdlib ndarrays
    • are the most comprehensive implementation supporting both C- and Fortran-style layouts
    • include native implementations for greater performance in server environments

Using ndarrays


// Create a new ndarray:
var arr = ndarray({
  'buffer': [ 2, 7, 0, 5, 4, 5, 9, 1, 3 ], // underlying data
  'order': 'row-major', // C-style layout
  'shape': [ 3, 3 ], // 3 rows, 3 colums
  'strides': [ 3, 1 ] // separation of elements in each dimension
})
var x = arr.get( 2, 0 );
				

Element Access


arr.get( 2, 0 ) => buffer[ strides[0]*2 + strides[1]*1 + offset ] => 9
				

Example: Transposing a matrix

X

2 7 0
5 4 5
9 1 3

Xᵀ

2 5 9
7 4 1
0 5 3
  • Create view without copying data by using strides [ 1, 3 ] instead of
    [ 3, 1 ]
arr.get( 2, 0 ) => buffer[ 6 ] => 9
arr.get( 2, 0 ) => buffer[ 2 ] => 0
2 7 0 5 4 5 9 1 3

Next Steps

  • Generic versions of stdlib functions that work on ndarrays
  • C-implementations for optimal performance
  • Utility functions for working with ndarrays
  • Linear Algebra

Design Principles

Decomposability

  • each package can consumed and understood independently of the project
  • every package maintains resource locality

Backward Compatibility

  • support of Node.js versions starting v0.10.x.
  • when bundled via Webpack or browserify, code will also run in legacy browsers

stdlib packages are fully documented, tested, and benchmarked

package
  • Examples
  • Benchmarks
  • Tests
  • Package and REPL documentation
Each package will be independently released on npm once v1.0 is reached

Testing

Unit Tests via tape


// TESTS //

tape( 'main export is a function', function test( t ) {
  t.ok( true, __filename );
  t.equal( typeof abs, 'function', 'main export is a function' );
  t.end();
});

tape( 'the function computes the absolute value of a number', function test( t ) {
  t.equal( abs( -2.0 ), 2.0, 'negative number' );
  t.equal( abs( 3.0 ), 3.0, 'positive number' );
  t.equal( abs( 0.0 ), 0.0, 'zero' );
  t.equal( abs( -PI ), PI, 'pi' );
  t.end();
});
				

Stats

  • Code Coverage: ~94%
  • Continuous Integration Services:
    • Travis CI (Linux builds)
    • AppVeyor (Windows builds)
    • CircleCI

Benchmarking

Custom micro-benchmarking framework


bench( 'Math.sin', function benchmark( b ) {
  var x;
  var i;
  b.tic();
  for ( i = 0; i < b.iterations; i++ ) {
    x = Math.sin( Math.random() );
    if ( x !== x ) {
      b.fail( 'should not return NaN' );
    }
  }
  b.toc();
  if ( x !== x ) {
    b.fail( 'should not return NaN' );
  }
  b.pass( 'success!' );
  b.end();
});
					

Structure of a benchmark


function benchmark( b ) {
	var x;
	var i;

	// [1] Start timing:
	b.tic();

	// [2] Loop containing code to time...
	for ( i = 0; i < b.iterations; i++ ) {
		// [3] Code to time...

		// [4] A conditional verifying results to prevent certain compiler optimizations:
		if ( x !== x ) {
			b.fail( 'something went wrong!' );
		}
	}
	// [5] Stop timing:
	b.toc();

	// [6] Another conditional verifying results to prevent certain compiler optimizations:
	if ( x !== x ) {
		b.fail( 'something went wrong!' );
	}
	// [7] End the benchmark:
	b.end();
}
				

Output

Results are output in accordance with the Test Anything Protocol (TAP) version 13.


    ok 3 benchmark success!
    # hypot
      ---
      iterations: 1000000
      elapsed: 0.13120811
      rate: 7621480.105155086
      ...
    ok 4 benchmark success!
    # hypot
      ---
      iterations: 1000000
      elapsed: 0.129308984
      rate: 7733414.717727579
      ...
    ok 5 benchmark success!
    # hypot
      ---
      iterations: 1000000
      elapsed: 0.12404053
      rate: 8061881.064197323
      ...
    ok 6 benchmark success!
    #
    1..6
    # total 6
    # pass  6
    #
    # ok
				
  • iterations: number of iterations
  • elapsed: total elapsed time beginning with b.tic() ending with b.toc() (in seconds)
  • rate: number of operations per second

Benchmarks for JS, Julia, Python, R, and C

stdlib


TAP version 13
# @stdlib/random/base/randn
  ---
  iterations: 1000000
  elapsed: 0.098133603
  rate: 10190189.389051577
  ...
ok 1 benchmark finished
# @stdlib/random/base/randn
  ---
  iterations: 1000000
  elapsed: 0.098849843
  rate: 10116353.95313678
  ...
ok 2 benchmark finished
# @stdlib/random/base/randn
  ---
  iterations: 1000000
  elapsed: 0.099407804
  rate: 10059572.38528275
  ...
ok 3 benchmark finished
#
1..3
# total 3
# pass  3
#
# ok
					

R


TAP version 13
# r::randn
  ---
  iterations: 1000000
  elapsed: 1.786431643
  rate: 559775.127091163
  ...
ok 1 benchmark finished
# r::randn
  ---
  iterations: 1000000
  elapsed: 1.746798779
  rate: 572475.783714754
  ...
ok 2 benchmark finished
# r::randn
  ---
  iterations: 1000000
  elapsed: 1.773366445
  rate: 563899.245313622
  ...
ok 3 benchmark finished
#
1..3
# total 3
# pass  3
#
# ok
				

Documentation

Web Interface

How to contribute

Thank you!

stdlib

https://www.stdlib.io
https://github.com/stdlib-js/stdlib
https://www.patreon.com/athan

Questions?

Appendix

JavaScript Math Built-Ins

  • acos
  • asin
  • atan
  • atan2
  • cos
  • sin
  • tan
  • acosh
  • asinh
  • atanh
  • cosh
  • sinh
  • tanh
  • abs
  • exp
  • log (ln)
  • pow
  • sqrt
  • sign
  • cbrt
  • expm1
  • log10
  • log1p
  • log2
  • ceil
  • floor
  • round
  • fround
  • trunc
  • max
  • min
  • random
  • hypot
  • clz32
  • imul

Issues with JavaScript Math built-ins

  • No standard algorithms
  • No minimum precision
  • Portability
  • No common codebase
  • Slow pace of innovation
  • Bugs

Math.pow


var x = Math.pow( 10, 308 );
// returns:  1.0000000000000006e+308
// expected: 1.0e+308
				

The End