jam/js/ml/math.js

647 lines
15 KiB
JavaScript

/**
* Created by joonkukang on 2014. 1. 12..
*/
var m = module.exports;
m.randn = function() {
// generate random guassian distribution number. (mean : 0, standard deviation : 1)
var v1, v2, s;
do {
v1 = 2 * Math.random() - 1; // -1.0 ~ 1.0 까지의 값
v2 = 2 * Math.random() - 1; // -1.0 ~ 1.0 까지의 값
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
s = Math.sqrt( (-2 * Math.log(s)) / s );
return v1 * s;
}
m.shape = function(mat) {
var row = mat.length;
var col = mat[0].length;
return [row,col];
};
m.addVec = function(vec1, vec2) {
if(vec1.length === vec2.length) {
var result = [];
var i;
for(i=0;i<vec1.length;i++)
result.push(vec1[i]+vec2[i]);
return result;
} else {
throw new Error("Length Error : not same.")
}
}
m.minusVec = function(vec1,vec2) {
if(vec1.length === vec2.length) {
var result = [];
var i;
for(i=0;i<vec1.length;i++)
result.push(vec1[i]-vec2[i]);
return result;
} else {
throw new Error("Length Error : not same.")
}
};
m.addMatScalar = function(mat,scalar) {
var row = m.shape(mat)[0];
var col = m.shape(mat)[1];
var i , j,result = [];
for(i=0 ; i<row ; i++) {
var rowVec = [];
for(j=0 ; j<col ; j++) {
rowVec.push(mat[i][j] + scalar);
}
result.push(rowVec);
}
return result;
}
m.addMatVec = function(mat,vec) {
if(mat[0].length === vec.length) {
var result = [];
var i;
for(i=0;i<mat.length;i++)
result.push(m.addVec(mat[i],vec));
return result;
} else {
throw new Error("Length Error : not same.")
}
}
m.minusMatVec = function(mat,vec) {
if(mat[0].length === vec.length) {
var result = [];
var i;
for(i=0;i<mat.length;i++)
result.push(m.minusVec(mat[i],vec));
return result;
} else {
throw new Error("Length Error : not same.")
}
}
m.addMat = function (mat1, mat2) {
if ((mat1.length === mat2.length) && (mat1[0].length === mat2[0].length)) {
var result = new Array(mat1.length);
for (var i = 0; i < mat1.length; i++) {
result[i] = new Array(mat1[i].length);
for (var j = 0; j < mat1[i].length; j++) {
result[i][j] = mat1[i][j] + mat2[i][j];
}
}
return result;
} else {
throw new Error('Matrix mismatch.');
}
};
m.minusMat = function(mat1, mat2) {
if ((mat1.length === mat2.length) && (mat1[0].length === mat2[0].length)) {
var result = new Array(mat1.length);
for (var i = 0; i < mat1.length; i++) {
result[i] = new Array(mat1[i].length);
for (var j = 0; j < mat1[i].length; j++) {
result[i][j] = mat1[i][j] - mat2[i][j];
}
}
return result;
} else {
throw new Error('Matrix mismatch.');
}
}
m.transpose = function (mat) {
var result = new Array(mat[0].length);
for (var i = 0; i < mat[0].length; i++) {
result[i] = new Array(mat.length);
for (var j = 0; j < mat.length; j++) {
result[i][j] = mat[j][i];
}
}
return result;
};
m.dotVec = function (vec1, vec2) {
if (vec1.length === vec2.length) {
var result = 0;
for (var i = 0; i < vec1.length; i++) {
result += vec1[i] * vec2[i];
}
return result;
} else {
throw new Error("Vector mismatch");
}
};
m.outerVec = function (vec1,vec2) {
var mat1 = m.transpose([vec1]);
var mat2 = [vec2];
return m.mulMat(mat1,mat2);
};
m.mulVecScalar = function(vec,scalar) {
var i, result = [];
for(i=0;i<vec.length;i++)
result.push(vec[i]*scalar);
return result;
};
m.mulMatScalar = function(mat,scalar) {
var row = m.shape(mat)[0];
var col = m.shape(mat)[1];
var i , j,result = [];
for(i=0 ; i<row ; i++) {
var rowVec = [];
for(j=0 ; j<col ; j++) {
rowVec.push(mat[i][j] * scalar);
}
result.push(rowVec);
}
return result;
};
m.mulMatElementWise = function(mat1, mat2) {
if (mat1.length === mat2.length && mat1[0].length === mat2[0].length) {
var result = new Array(mat1.length);
for (var x = 0; x < mat1.length; x++) {
result[x] = new Array(mat1[0].length);
}
for (var i = 0; i < result.length; i++) {
for (var j = 0; j < result[i].length; j++) {
result[i][j] = mat1[i][j] * mat2[i][j]
}
}
return result;
} else {
throw new Error("Matrix shape error : not same");
}
};
m.mulMat = function (mat1, mat2) {
if (mat1[0].length === mat2.length) {
var result = new Array(mat1.length);
for (var x = 0; x < mat1.length; x++) {
result[x] = new Array(mat2[0].length);
}
var mat2_T = m.transpose(mat2);
for (var i = 0; i < result.length; i++) {
for (var j = 0; j < result[i].length; j++) {
result[i][j] = m.dotVec(mat1[i],mat2_T[j]);
}
}
return result;
} else {
throw new Error("Array mismatch");
}
};
m.sumVec = function(vec) {
var sum = 0;
var i = vec.length;
while (i--) {
sum += vec[i];
}
return sum;
};
m.sumMat = function(mat) {
var sum = 0;
var i = mat.length;
while (i--) {
for(var j=0;j<mat[0].length;j++)
sum += mat[i][j];
}
return sum;
};
m.sumMatAxis = function(mat,axis) {
// default axis 0;
// axis 0 : mean of col vector . axis 1 : mean of row vector
if(axis === 1) {
var row = m.shape(mat)[0];
var i ;
var result = [];
for(i=0 ; i<row; i++)
result.push(m.sumVec(mat[i]));
return result;
} else {
mat_T = m.transpose(mat);
return m.sumMatAxis(mat_T,1);
}
};
m.meanVec = function(vec) {
return 1. * m.sumVec(vec) / vec.length;
};
m.meanMat = function(mat) {
var row = mat.length;
var col = mat[0].length;
return 1. * m.sumMat(mat) / (row * col);
};
m.meanMatAxis = function(mat,axis) {
// default axis 0;
// axis 0 : mean of col vector . axis 1 : mean of row vector
if(axis === 1) {
var row = m.shape(mat)[0];
var i ;
var result = [];
for(i=0 ; i<row; i++)
result.push(m.meanVec(mat[i]));
return result;
} else {
mat_T = m.transpose(mat);
return m.meanMatAxis(mat_T,1);
}
};
m.squareVec = function(vec) {
var squareVec = [];
var i;
for(i=0;i<vec.length;i++) {
squareVec.push(vec[i]*vec[i]);
}
return squareVec;
};
m.squareMat = function(mat) {
var squareMat = [];
var i;
for(i=0;i<mat.length;i++) {
squareMat.push(m.squareVec(mat[i]));
}
return squareMat;
};
m.minVec = function(vec) {
var min = vec[0];
var i = vec.length;
while (i--) {
if (vec[i] < min)
min = vec[i];
}
return min;
};
m.maxVec = function(vec) {
var max = vec[0];
var i = vec.length;
while (i--) {
if (vec[i] > max)
max = vec[i];
}
return max;
}
m.minMat = function(mat) {
var min = mat[0][0];
var i = mat.length;
while (i--) {
for(var j=0;j<mat[0].length;j++) {
if(mat[i][j] < min)
min = mat[i][j];
}
}
return min;
};
m.maxMat = function(mat) {
var max = mat[0][0];
var i = mat.length;
while (i--) {
for(var j=0;j<mat[0].length;j++) {
if(mat[i][j] < max)
max = mat[i][j];
}
}
return max;
};
m.zeroVec = function(n) {
var vec = [];
while(vec.length < n)
vec.push(0);
return vec;
};
m.zeroMat = function(row,col) {
var mat = [];
while(mat.length < row)
mat.push(m.zeroVec(col));
return mat;
};
m.oneVec = function(n) {
var vec = [];
while(vec.length < n)
vec.push(1);
return vec;
};
m.oneMat = function(row,col) {
var mat = [];
while(mat.length < row)
mat.push(m.oneVec(col));
return mat;
};
m.randVec = function(n,lower,upper) {
lower = (typeof lower !== 'undefined') ? lower : 0;
upper = (typeof upper !== 'undefined') ? upper : 1;
var vec = [];
while(vec.length < n)
vec.push(lower + (upper-lower) * Math.random());
return vec;
};
m.randMat = function(row,col,lower,upper) {
lower = (typeof lower !== 'undefined') ? lower : 0;
upper = (typeof upper !== 'undefined') ? upper : 1;
var mat = [];
while(mat.length < row)
mat.push(m.randVec(col,lower,upper));
return mat;
};
m.randnVec = function(n,mean,sigma) {
var vec = [];
while(vec.length < n)
vec.push(mean+sigma* m.randn());
return vec;
};
m.randnMat = function(row,col,mean,sigma) {
var mat = [];
while(mat.length < row)
mat.push(m.randnVec(col,mean,sigma));
return mat;
};
m.identity = function (n) {
var result = new Array(n);
for (var i = 0; i < n ; i++) {
result[i] = new Array(n);
for (var j = 0; j < n; j++) {
result[i][j] = (i === j) ? 1 : 0;
}
}
return result;
};
m.sigmoid = function(x) {
var sigmoid = (1. / (1 + Math.exp(-x)))
if(sigmoid ==1) {
// console.warn("Something Wrong!! Sigmoid Function returns 1. Probably javascript float precision problem?\nSlightly Controlled value to 1 - 1e-14")
sigmoid = 0.99999999999999; // Javascript Float Precision Problem.. This is a limit of javascript.
} else if(sigmoid ==0) {
// console.warn("Something Wrong!! Sigmoid Function returns 0. Probably javascript float precision problem?\nSlightly Controlled value to 1e-14")
sigmoid = 1e-14;
}
return sigmoid; // sigmoid cannot be 0 or 1;;
};
m.dSigmoid = function(x){
a = m.sigmoid(x);
return a * (1. - a);
};
m.probToBinaryMat = function(mat) {
var row = m.shape(mat)[0];
var col = m.shape(mat)[1];
var i,j;
var result = [];
for(i=0;i<row;i++) {
var rowVec = [];
for(j=0;j<col;j++) {
if(Math.random() < mat[i][j])
rowVec.push(1);
else
rowVec.push(0);
}
result.push(rowVec);
}
return result;
};
m.activateVec = function(vec,activation) {
var i, result = [];
for(i=0;i<vec.length;i++)
result.push(activation(vec[i]));
return result;
};
m.activateMat = function(mat,activation) {
var row = m.shape(mat)[0];
var col = m.shape(mat)[1];
var i, j,result = [];
for(i=0;i<row;i++) {
var rowVec = [];
for(j=0;j<col;j++)
rowVec.push(activation(mat[i][j]));
result.push(rowVec);
}
return result;
};
m.activateTwoVec = function(vec1, vec2,activation) {
if (vec1.length === vec2.length) {
var result = new Array(vec1.length);
for (var i = 0; i < result.length; i++) {
result[i] = activation(vec1[i],vec2[i]);
}
return result;
} else {
throw new Error("Matrix shape error : not same");
}
};
m.activateTwoMat = function(mat1, mat2,activation) {
if (mat1.length === mat2.length && mat1[0].length === mat2[0].length) {
var result = new Array(mat1.length);
for (var x = 0; x < mat1.length; x++) {
result[x] = new Array(mat1[0].length);
}
for (var i = 0; i < result.length; i++) {
for (var j = 0; j < result[i].length; j++) {
result[i][j] = activation(mat1[i][j],mat2[i][j]);
}
}
return result;
} else {
throw new Error("Matrix shape error : not same");
}
};
m.fillVec = function(n,value) {
var vec = [];
while(vec.length < n)
vec.push(value);
return vec;
};
m.fillMat = function(row,col,value) {
var mat = [];
while(mat.length < row) {
var rowVec = [];
while(rowVec.length < col)
rowVec.push(value);
mat.push(rowVec);
}
return mat;
};
m.softmaxVec = function(vec) {
var max = m.maxVec(vec);
var preSoftmaxVec = m.activateVec(vec,function(x) {return Math.exp(x - max);})
return m.activateVec(preSoftmaxVec,function(x) {return x/ m.sumVec(preSoftmaxVec)})
};
m.softmaxMat = function(mat) {
var result=[], i;
for(i=0 ; i<mat.length ; i++)
result.push(m.softmaxVec(mat[i]));
return result;
};
m.randInt = function(min,max) {
var rand = Math.random() * (max - min + 0.9999) + min
return Math.floor(rand);
}
m.normalizeVec = function(vec) {
var i;
var newVec = [],tot = 0;
for(i=0; i<vec.length; i++)
tot += vec[i];
for(i=0; i<vec.length;i++)
newVec.push(1.*vec[i]/tot);
return newVec;
};
m.euclidean = function(x1,x2) {
var i;
var distance = 0;
for(i=0 ; i<x1.length; i++) {
var dx = x1[i] - x2[i];
distance += dx * dx;
}
return Math.sqrt(distance);
};
m.pearson = function(x, y)
{
var xy = [];
var x2 = [];
var y2 = [];
for(var i=0; i<x.length; i++)
{
xy.push(x[i] * y[i]);
x2.push(x[i] * x[i]);
y2.push(y[i] * y[i]);
}
var sum_x = 0;
var sum_y = 0;
var sum_xy = 0;
var sum_x2 = 0;
var sum_y2 = 0;
for(var i=0; i<x.length; i++)
{
sum_x += x[i];
sum_y += y[i];
sum_xy += xy[i];
sum_x2 += x2[i];
sum_y2 += y2[i];
}
var step1 = (x.length * sum_xy) - (sum_x * sum_y);
var step2 = (x.length * sum_x2) - (sum_x * sum_x);
var step3 = (x.length * sum_y2) - (sum_y * sum_y);
var step4 = Math.sqrt(step2 * step3);
var answer = step1 / step4;
return answer;
};
m.getNormVec = function(vec) {
var i;
var sqsum = 0;
for(i=0; i<vec.length; i++)
sqsum += vec[i] * vec[i];
return Math.sqrt(sqsum);
}
m.gaussian = function(x, sigma) {
sigma = sigma || 10.0;
return Math.exp(-1.*x*x/(2*sigma*sigma));
}
m.meanVecs = function(vecs) {
var sum = m.zeroVec(vecs[0].length);
var i;
for(i=0; i<vecs.length; i++)
sum = m.addVec(sum,vecs[i]);
return m.activateVec(sum,function(x) {return 1.*x/vecs.length;});
};
m.covarianceVecs = function(vecs) {
var mat = m.zeroMat(vecs[0].length,vecs[0].length);
var meanVec = m.meanVecs(vecs);
var i;
for(i=0; i<vecs.length; i++) {
var a = m.minusVec(vecs[i],meanVec);
mat = m.addMat(mat, m.mulMat(m.transpose([a]),[a]));
}
return m.activateMat(mat,function(x) { return 1.*x/(vecs.length-1);});
};
m.shuffle = function(arr){
var o = [];
for(var i=0;i<arr.length;i++)
o.push(arr[i]); // deep copy
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
m.range = function(start, end, step) {
var ret = [];
if(typeof step === "undefined")
step = 1;
if(typeof end === "undefined") {
end = start;
start = 0;
}
for(var i=start;i<end;i+=step)
ret.push(i);
return ret;
};
// For CRBM
/*
m.phi = function(mat,vec,low,high) {
var i;
var result = [];
for(i=0;i<mat.length;i++) {
result.push(m.activateTwoVec(mat[i],vec,function(x,y){return low+(high-low)* m.sigmoid(x*y);}))
}
return result;
}
*/