LALOLib / ML.js: scientific computing and machine learning
in web pages made easy

LALOLib (Linear ALgebra Online Library) is a library entirely written in Javascript to enable and ease mathematical computing within web pages. It is developed as a part of the MLweb project and constitutes the core of LALOLab (an online scientific computing environment). It also provides the basic building blocks for ML.js, a javascript library for machine learning.

LALOLib includes functions for

all easily loaded with a simple line of HTML:
	<script src="http://mlweb.loria.fr/lalolib.js"></script>
or
	<script src="http://mlweb.loria.fr/ml.js"></script>
for ML.js.

Alternatively, you can use a local copy of the library (download lalolib or ml.js) and modify the path accordingly.

The following shows how to use the library. The list of available functions can also be quickly accessed in LALOLab, on the right of the screen, and a few machine learning oriented tutorials are also available.

  1. The direct (synchronous) method
  2. The safer (asynchronous) method: Computing in a background Lab
  3. Sending data to and retrieving data from a background Lab
  4. Parallel computing with multiple Labs
  5. Closing a Lab
  6. The direct method for scripts
  7. Importing LALOLab scripts
  8. Importing Javascript/LALOLib code
  9. Implementation details and data types
  10. Using the machine learning functions (ML.js)
  11. Writing efficient code with LALOLib
  12. Extending LALOLib/LALOLab
  13. Available functions / API reference

The direct (synchronous) method

LALOLib functions can be used in a straightforward manner to implement computations in the current scope.



In this example we used the laloprint() function to print a vector. Here are the various ways in which it can be used:

// Print the vector or matrix X to the standard LALOLib output (an HTML div with id="LALOLibOutput")
laloprint( X );			

// Print X to the HTML element with id=htmlId 
laloprint( X, htmlId ); 

// Append X to the HTML element with id=htmlId (
laloprint( X, htmlId, true ); 

// Return an HTML formated String for X
str = laloprint(X, true);

The safer (asynchronous) method: Computing in a background Lab

The direct method is unsafe in the sense that it makes the browser freeze while waiting for the result.
If the computations take too long, the alternative is to do them in the background. This is implemented by opening a Lab with

	var lab = new Lalolab() ;   // open a standard Lab
or with
	var lab = new MLlab() ;    // open a Lab with machine learning capabilities
depending on the desired capabilities. Then, commands can then be sent the the lab with do( script, callback ) or exec( command_string, callback ). If an action needs to be taken upon the completion of the command, a callback function is provided.

Note: when using a local copy of lalolib.js (or ml.js), this requires a local copy of lalolibworker.js (or mlworker.js) in the same directory. In addition, the relative path to these files from the html page must be supplied as var lab = new Lalolab("labname", false, path_to_lalolib ) ; or var lab = new MLlab("labname", path_to_mljs ) ;.



The difference between do( script, callback ) and exec( command_string, callback ) is that do parses the string argument before executing it, whereas exec directly executes it. Thus,

	lab.do( "x = (2*A + C*D) \ b" )
is equivalent to
	lab.exec("x = solve( add( mul(2,A), mul(C,D) ), b)");

Sending data to and retrieving data from a background Lab

Any Lab running in the background works with an independent scope, i.e., it cannot access variables in the current scope, nor can you access its variables directly.
Example 3 shows how to send data to a Lab with the function

load( variable_in_current_scope, variable_name_in_the_lab, callback)
and how to recover data from a Lab with a call to
getObject( variable_name_in_the_lab, callback )

Note that this method can be combined with the direct method for instance to generate random data in the current scope with randn() before sending it to the lab.



Parallel computing with multiple Labs

Multiple Labs can be created. Each Lab works with its own private scope and runs in a different thread (a web worker in javascript language).



Closing a Lab

In order to free the memory or to force a Lab to stop computing, a Lab can be closed with

	lab.close(); 

The direct method for scripts

The direct method can also be used with LALOLab scripts without having to memorize LALOLib functions. To execute a script in the current global scope, use lalo( script ), where script is a string referring to global variables in the page.


Importing LALOLab scripts

Scripts written with LALOLab instructions can be imported in a Lab with the import( script, callback ) function. However, the script must comply with the same-origin policy (typically, it must be located on the same server).

File "test.lalo":
	function sumsquares ( x ) {
		return (sum(x.*x))
	}

Importing Javascript/LALOLib code

Scripts written in pure Javascript (possibly calling LALOLib functions) can be imported in a Lab with the importjs( JSscript, callback ) function. However, the script must comply with the same-origin policy (typically, it must be located on the same server).

File "test.js":
	function sumsquaresjs (x) {
		var ss = 0;
		for ( var i = 0; i < x.length; i++)
			ss += x[i] * x[i];
		return ss;
	}

Implementation details and data types

The type of a variable x is recovered with
type(x)	 // returns the type of x as a string

Basic types

The following basic types are found in javascript:
"undefined"
"number" 		// all numbers are 64-bit floats (double)
"boolean"
"string"
"function"		// functions are stored in variables
"object"
The basic type of a variable x can be recovered with
typeof(x)
which returns the uninformative "object" for all the types below. type(x) returns the correct type (but is typically slower) as
"vector"
"matrix"
"spvector"
"spmatrix"
"Array"		// standard javascript Array
Note that "vector" is also returned for Arrays containing only numbers. Arrays can be used in general for lists of variable length with easy insertion and removal of entries.

Vectors

Vectors are implemented as standard Float64Array objects with a fixed size stored in the property length:

x = zeros(5);    // this is equivalent to x = new Float64Array(5);
dim = x.length;  // returns dim = 5
The entries can be accessed directly with square brackets and indexes in the range 0...x.length-1 as
x[0] = first component of the vector x
x[1] = second component of the vector x
...
x[x.length-1] = last component of the vector x

A vector can be copied with

x2 = vectorCopy( x );
while x2 = x makes x2 point to the same location in memory as x (in a LALOLab script, x2 = x actually copies x into x2).

Creating a Vector from an Array: the vector copy can also be used to convert a standard javascript Array of numbers to a vector with

x = vectorCopy( [1, 2, 3, -4.2] );   // returns a Float64Array (i.e. a vector) initialized with the given values
y = array2vec( [1, 2, 3, -4.2] );   // returns the same vector (this is equivalent)
However, most functions working on vectors also work with Arrays of numbers.

Matrices

Matrices are implemented as Matrix objects created with
A = new Matrix(m,n);    // this is equivalent to A = zeros(m,n);
and having the following properties:
A.type      : object type = "matrix" (constant)
A.m         : number of rows (constant)
A.n         : number of columns (constant)
A.length    : number of rows (constant) (= A.m)
A.size      : size as an Array = [A.m, A.n] (constant)
A.val       : vector of values
The matrix entries are stored rowwise in a single vector A.val, i.e., the entry at the ith row and jth column is
A.val[i*A.n + j]   // = A[i,j] in LALOLab
for i in the range 0...A.m-1 and j in the range 0...A.n-1.

Creating a Matrix from a 2D Array: given a 2D Array, a matrix is obtained with the function mat as

a2DArray = [ [ 1, 2, 3], [4, 5, 6] ];  // an Array of as many Arrays as rows in the matrix
aMatrix = array2mat(a2DArray);         // a Matrix with 2 rows and 3 columns

Sparse vectors and matrices

Sparse vectors and matrices are created with

a = sparse( b );
A = sparse( B );
The dense versions can be recovered with
b = full( a );
B = full( A );

Sparse vectors are implemented as spVectors objects having the following properties:

a.type      : object type = "spvector" (constant)
a.length    : size of the vector (constant)
a.size      : size as an Array = [a.length, 1] (constant)
a.val       : vector of values
a.ind       : vector of indexes
a.nnz       : number of nonzeros
The vector entries are stored such that ai = a.val[k] with i = a.ind[k].

Sparse matrices are implemented as spMatrix objects having the following properties:

A.type      : object type = "spmatrix" (constant)
A.m         : number of rows (constant)
A.n         : number of columns (constant)
A.length    : number of rows (constant) (= A.m)
A.rowmajor  : true/false for row/column compressed format
A.size      : size as an Array = [A.m, A.n] (constant)
A.val       : vector of values
A.cols      : list of column starting indexes 
A.rows      : list of row indexes
A.nnz       : number of nonzeros
The matrix entries are stored by default (with A.rowmajor = true) in a row-sparse format with
A.rows[i] = starting index of row i in A.val and A.cols
A.cols[k] = column of the value A.val[k]	
or (with A.rowmajor = false) in a column-sparse format with
A.cols[j] = starting index of column j in A.val and A.rows
A.rows[k] = row of the value A.val[k]	

Other types

Complex objects like classifiers or regression models have a type string in the format "Class:Subclass", for instance:
"Distribution:Gaussian"		// an object created by 'new Distribution(Gaussian,...)'
"Classifier:SVM"		// an object created by 'new Classifier(SVM, ... )'
"Regression:LASSO"		// an object created by 'new Regression(LASSO, ... )'

Writing efficient code with LALOLib

Follow these guidelines to avoid common pitfalls and write more efficient code with LALOLib.

Extending LALOLib/LALOLab

LALOLib and LALOLab can be easily extended with new toolboxes, as detailed here.

Using the machine learning functions (ML.js)

ML.js extends LALOLib with machine learning functions. Many examples can be found in the API reference below and the online help of LALOLab. You can also look at a few online demos and tutorials.

For supervised learning, predictive models are created with a new statement. For instance,

model = new Classifier(SVM, params); 
creates a new support vector machine (SVM) classifier with an optional argument (params) to set hyperparameters. Then, given an N-by-d matrix X of N observations in dimension d (N data instances described by d features each) and the corresponding vector of labels Y, the model can be trained with
model.train(X, Y);
To see the result, the model.info() function returns a formatted HTML text String listing all model parameters. After training, a model can be used to make predictions with
prediction = model.predict(Xtest);
where Xtest can be either a matrix with multiple data instances or a single data vector.

Most machine learning models come with a self-tuning function, which automatically determines (or more precisely tries to determine) the best hyperparameters for training. This function can be used instead of the train() function as

model.tune(X, Y); 

Available functions / API reference

Below is the list of functions provided by LALOLib. The help shows both the script-like LALOLab syntax and the corresponding javascript calls. Examples are mostly written for LALOLab and should be executed by a lab.do() statement in a javascript context.

Select a topic on the left to see the help.

Linear algebra