I recently needed to generate multivariate normal values in a web browser. Since I was unable to find a simple implementation, I wrote the following JavaScript code. This code is not the fastest, and it also makes use of the Math.random() method which I can’t vouch for, but it seems to do a decent job. The first two functions are needed to generate normal values via the Box-Muller method. This implementation uses the basic trig functions of the JavaScript Math object. The third function performs a Cholesky decomposition, which is need to decompose a correlation matrix. Finally, the last function combines these functions to generate iid normals and then transform them to correlated normals.

// generates a pair of iid standard normals using Box-Muller
function boxMuller() {
  var x = new Array(2);
  var u1 = Math.random();
  var u2 = Math.random();
 
  var R = Math.sqrt(-2*Math.log(u1));
  var theta = 2*Math.PI*u2;
 
  x[0] = R*Math.cos(theta);
  x[1] = R*Math.sin(theta);
  return(x);
}
 
 
// generates a vector of iid standard normals
// n is the number of normals to generate
function rnorm(n) {
  var x = new Array(n);
  var y = new Array(2);
  var k = n % 2;
 
  // if n is even
  if(k==0){
    for(var i=0; i<(n/2); i++){
      y = boxMuller();
      x[i*2]     = y[0];
      x[i*2 + 1] = y[1];
    }
  }
 
  // if n is odd
  if(k==1){
    for(var i=0; i<Math.round((n-1)/2); i++){
      y = boxMuller();
      x[i*2]     = y[0];
      x[i*2 + 1] = y[1];
    }
    y = boxMuller();
    x[n-1] = y[0];
  }  
  return(x);
}
 
// returns a cholesky decomposed matrix
// A is the square matrix to decompose
function cholesky(A) {
  var n = A.length;
  // create square matrix L
  var L = new Array(n)
  for(var i=0; i<n; i++){
    L[i] = new Array(n)
    for(var j=0; j<n; j++){
      L[i][j] = 0;
    }
  }
 
  for(var i=0; i<n; i++){
    for(var j=0; j<=i; j++){
      var ss = 0;
      for(var k=0; k<j; k++){
        ss = ss + L[i][k] * L[j][k];
      }
      if(i==j){
        L[i][i] = Math.sqrt(A[i][i] - ss);
      } else{
        L[i][j] = (A[i][j] - ss) / L[j][j];
      }
    }
  }
  return(L);  
}
 
// generates multivariate normals
// n is the number of multivariate normals to generate
// mu is an array of means
// sig is an array of standard deviations
// rho is a 2 dim correlation array
function rmultinorm(n, mu, sig, rho){
  var N = mu.length;
  var A = cholesky(rho);
 
  // create x which will be the return values
  var x = new Array(n)
  for(var i=0; i<n; i++){
    x[i] = new Array(N);
    for(var j=0; j<N; j++){
      x[i][j] = 0;
    }
  }
 
  for(var k=0; k<n; k++){
    // generate standard normals
    var z = rnorm(N);
 
   // tranform to correlated standard normals
    for(var i=0; i<N; i++){
      var ss = 0;
      for(var j=0; j<N; j++){
        ss = ss + z[j]*A[i][j];
      }
      x[k][i] = ss*sig[i] + mu[i];
    }
  }
  return(x);
}

One Response to “Multivariate normal generator in JavaScript”

  1. My spouse and i go through a bunch of posting on the subject matter yet could definitely not have the solutions We were seeking intended for.

Leave a Reply