rlab
Version:
Javascript scientific library like R
1,865 lines (1,629 loc) • 1.24 MB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var O = require("./field");
var acc = {
sum:{init:0,op:'+'},
product:{init:1,op:'*'},
min:{init:Number.MAX_VALUE,op:'min'},
max:{init:-Number.MAX_VALUE,op:'max'},
}
O.vfill=function(size, value) {
var v=[];
for (var i=0; i<size; i++)
v[i] = value;
return v;
}
O.vextend=function(a, size) {
var v = a.slice();
for (var i=a.length; i<size; i++) {
v.push(0);
}
return v;
}
O.vdot=function(x,y) {
var sum = 0;
for (var i=0; i<x.length; i++) {
sum = sum.add(x[i].mul(y[i]));
}
return sum;
}
O.vop=function(op,x,y) {
var c=[],result=(O.isUndefined(acc[op]))?undefined:acc[op].init;
if (O.isArray(x)) {
for (var i=0; i<x.length; i++) {
if (!O.isUndefined(result)) {
var xi = x[i];
if (O.isArray(x[i])) // x[i] is subArray
xi = O.op(op, x[i]);
else {
if (!O.isUndefined(y))
xi = y(x[i]); // y should be a function
}
result = O.op(acc[op].op, xi, result);
// if (op==='min') console.log("xi=%d result=%d", xi, result);
}
else {
var yi = O.isArray(y)?y[i]:y;
c[i] = O.op(op, x[i], yi);
}
}
} else {
throw Error('vop fail:op,x,y=', op, x, y);
}
if (x.length === c.length)
return c;
else
return result;
}
O.op = function(op,x,y) {
if (O.isField(x)) {
if (!O.isUndefined(acc[op])) {
switch (op) {
case 'max': return Math.max(x,y);
case 'min': return Math.min(x,y);
default:return x;
}
} else if (x instanceof O.FieldObj ||
(O.isNumber(x) && y instanceof O.FieldObj)) {
x = O.Complex.toComplex(x);
y = O.isNumber(y)?O.Complex.toComplex(y):y;
switch (op) {
case 'eval': var exp = y; return exp(x);
case 'neg':return x.neg();
case 'inv':return x.inv();
case 'bnot':return x.bnot();
case '+':return x.add(y);
case '-':return x.sub(y);
case '*':return x.mul(y);
case '/':return x.div(y);
case 'power':return x.power(y);
case 'sqrt':return x.sqrt();
case 'eq':return x.eq(y);
case 'neq':return x.neq(y);
case 'geq':return x.geq(y);
case 'leq':return x.leq(y);
case 'gt':return x.gt(y);
case 'lt':return x.lt(y);
}
} else if (O.isBool(x) || O.isNumber(x)) {
switch (op) {
case 'eval': var exp = y; return exp(x);
case 'not':return !x;
case 'neg':return -x;
case 'inv':return 1/x;
case 'bnot':return ~x;
case 'and':return x&&y;
case 'or':return x||y;
case 'xor':return x!==y;
case '+':return x+y;
case '-':return x-y;
case '*':return x*y;
case '/':return x/y;
case '%':return x%y;
case 'eq':return x===y;
case 'neq':return x!==y;
case 'geq':return x>=y;
case 'leq':return x<=y;
case 'gt':return x>y;
case 'lt':return x<y;
case '&':return x&y;
case '|':return x|y;
case 'bxor':return x^y;
case '<<':return x<<y;
case '>>':return x>>y;
case 'and':return x&&y;
case 'or':return x||y;
case 'xor':return x!==y;
case 'sqrt':
if (x>=0) return Math.sqrt(x);
else {
var c = new O.Complex(x,0);
return c.sqrt();
}
case 'power':
if (x>=0 || O.isInteger(y))
return Math.pow(x,y);
else
return new O.Complex(x,0).power(y);
case 'log':return Math.log(x);
case 'exp':return Math.exp(x);
case 'abs':return Math.abs(x);;
case 'sin':return Math.sin(x);
case 'cos':return Math.cos(x);
case 'tan':return Math.tan(x);
case 'asin':return Math.asin(x);
case 'acos':return Math.acos(x);
case 'atan':return Math.atan(x);
case 'sinh':return Math.sinh(x);
case 'cosh':return Math.cosh(x);
case 'tanh':return Math.tanh(x);
case 'ceil':return Math.ceil(x);
case 'floor':return Math.floor(x);
case 'round':return Math.round(x);
case 'log1p':return Math.log1p(x);
case 'log10':return Math.log10(x);
case 'log2':return Math.log2(x);
case 'random':return Math.random();
case 'sign':return Math.sign(x);
case 'abs':return Math.abs(x);
case 'cbrt':return Math.cbrt(x); // cubic root
}
}
} else if (O.isFunction(x)) {
if (O.isFunction(y)) {
switch (op) {
case 'neg':return O.fneg(x);
case 'inv':return O.finv(x);
case '+':return O.fadd(x,y);
case '-':return O.fsub(x,y);
case '*':return O.fmul(x,y);
case '/':return O.fdiv(x,y);
case 'compose':return O.fcompose(x,y);
}
} else {
switch (op) {
case 'eval':return x(y);
}
}
} else if (O.isArray(x)) {
return O.vop(op,x,y);
}
throw Error('op fail:op,x,y=', op, x, y);
}
O.sum=function(x) { return O.vop('sum', x) }
O.product=function(x) { return O.vop('product', x) }
O.max=function(x) { return O.vop('max', x) }
O.min=function(x) { return O.vop('min', x) }
O.eval=function(x,y) { return O.op('eval', x,y) }
O.norm=function(x) {
var norm2 = O.vop('sum', x, (x)=>x*x);
return Math.sqrt(norm2);
}
// +-*/%^
O.add=function(x,y) { return O.op('+',x,y) }
O.sub=function(x,y) { return O.op('-',x,y) }
O.mul=function(x,y) { return O.op('*',x,y) }
O.div=function(x,y) { return O.op('/',x,y) }
O.mod=function(x,y) { return O.op('%',x,y) }
O.power=function(x,y) { return O.op('power', x, y) }
O.neg=function(x) { return O.op('neg', x) }
O.inv=function(x) { return O.op('inv', x) }
// logical
O.not=function(x) { return O.op('not', x) }
O.and=function(x,y) { return O.op('&&', x, y) }
O.or=function(x,y) { return O.op('||', x, y) }
O.xor=function(x,y) { return O.op('xor', x, y) }
O.bnot=function(x) { return O.op('bnot', x) }
O.band=function(x,y) { return O.op('&', x, y) }
O.bor=function(x,y) { return O.op('|', x, y) }
O.bxor=function(x,y) { return O.op('bxor', x, y) }
O.lshift=function(x,y) { return O.op('<<', x, y) }
O.rshift=function(x,y) { return O.op('>>', x, y) }
// compare
O.eq=function(x,y) { return O.op('eq', x, y) }
O.neq=function(x,y) { return O.op('neq', x, y) }
O.geq=function(x,y) { return O.op('geq', x, y) }
O.leq=function(x,y) { return O.op('leq', x, y) }
O.gt=function(x,y) { return O.op('gt', x, y) }
O.lt=function(x,y) { return O.op('lt', x, y) }
// number function
O.sqrt=function(x) { return O.op('sqrt', x) }
O.log=function(x) { return O.op('log', x) }
O.exp=function(x) { return O.op('exp', x) }
O.abs=function(x) { return O.op('abs', x) }
O.sin=function(x) { return O.op('sin', x) }
O.cos=function(x) { return O.op('cos', x) }
O.tan=function(x) { return O.op('tan', x) }
O.asin=function(x) { return O.op('asin', x) }
O.acos=function(x) { return O.op('acos', x) }
O.atan=function(x) { return O.op('atan', x) }
O.atan2=function(x) { return O.op('atan2', x) }
O.ceil=function(x) { return O.op('ceil', x) }
O.floor=function(x) { return O.op('floor', x) }
O.round=function(x) { return O.op('round', x) }
O.parse = function(s) {
if (s.indexOf(';')>=0) {
var m = split(s, ";"), matrix;
for (var i=0; i<m.length; i++) {
matrix[i] = O.parse(m[i]);
}
return matrix;
} if (s.indexOf(',')>=0) {
var a = split(s, ","), array;
for (var i=0; i<a.length; i++) {
array[i] = O.parse(a[i]);
}
return array;
}
else if (s.indexOf('/')>=0)
return O.Ratio.parse(s);
else if (s.indexOf('i')>=0)
return O.Complex.parse(s);
else {
return parseFloat(s);
}
}
// =========== Polynomial Ring ==============
O.PolynomialRing=extend({}, O.Field);
class Polynomial extends O.FieldObj {
constructor(c) {
super(O.PolynomialRing);
this.c = c; // sum(ci x^i)
}
eval(x) {
var c = this.c, i=c.length-1, sum=c[i];
for (i--;i>=0; i--) {
sum = c[i].add(x.mul(sum));
}
return sum;
}
size() { return this.c.length }
toString() {
var s = [], c=this.c;
for (var i=c.length-1; i>=0; i--) {
s.push(c[i]+'x^'+i);
}
return s.join('+');
}
root() {
var p = this.normalize(); // 正規化
switch (this.size()) {
case 2:return p.c[0].neg();
case 3:return p.root2(p.c[1], p.c[0]);
case 4:return p.root3(p.c[2], p.c[1], p.c[0]);
default:throw Error('root() fail');
}
}
root2(b,c) { // x^2 + bx + c =0
var d = b.mul(b).sub(c.mul(4)).sqrt();
return [b.neg().add(d), b.neg().sub(d)];
}
root3(a,b,c) { // x^3+ax^2+bx+c=0
var q=((2*a*a*a/27)-(a*b/3)+c)/2;
var p=(b-a*a/3)/3;
var D=p*p*p+q*q;
var Dsqrt = D.sqrt(), _q=q.neg();
var u_p=_q.add(Dsqrt).power(1/3); // (-q+sqrt(D))^1/3
var u_m=_q.sub(Dsqrt).power(1/3); // (-q-sqrt(D))^1/3
console.log("q=%s p=%s D=%s u+=%s u-=%s", q, p, D, u_p, u_m);
var rho_p = (1/2).mul(O.parse('-1+3i'));
var rho_m = (1/2).mul(O.parse('-1-3i'));
console.log("rho_p=%s rho_m=%s", rho_p, rho_m);
var y1=u_p.add(u_m);
var y2=rho_p.add(u_p).add(rho_m.mul(u_m));
var y3=rho_p.sub(u_p).add(rho_p.mul(u_m));
return [y1, y2, y3];
}
normalize() {
var a = this.c[this.size()-1];
var nc = this.c.div(a);
return new Polynomial(nc);
}
}
O.Polynomial = Polynomial;
/*
function root3(a,b,c) { // x^3+ax^2+bx+c=0
var q=((2*a*a*a/27)-(a*b/3)+c/2);
var p=(b-a*a/3)/3;
var D=p*p*p+q*q;
var u_p=Math.sqrt(3, -q+Math.sqrt(D));
var u_m=Math.sqrt(3, -q-Math.sqrt(D));
var rho_p = 1/2*(-1+3i);
var rho_m = 1/2*(-1-3i);
var y1=u_p+u_m;
var y2=rho_p+u_p+ rho_m*u_m;
var y3=rho_p-u_p+ rho_p*u_m;
}
*/
O.PolynomialAddGroup={
e:new Polynomial([0]), // 到底應該設幾個?
op:function(x,y) {
var size = Math.max(x.size(), y.size());
var a=O.vextend(x.c,size), b=O.vextend(y.c,size);
var c=O.add(a,b);
return new Polynomial(c);
},
inv:function(x) {
var c = O.neg(x.c);
return new Polynomial(c);
},
}
extend(O.PolynomialAddGroup, O.Group);
O.PolynomialMulSemiGroup={
e:new Polynomial([1]),
op:function(x,y) {
var c=[];
for (var xi=0; xi<x.c.length; xi++) {
for (var yi=0; yi<y.c.length; yi++) {
var cxy = (typeof c[xi+yi]==='undefined')?0:c[xi+yi];
c[xi+yi] = cxy+x.c[xi]*y.c[yi];
}
}
return new Polynomial(c);
},
inv:function(x) { throw Error('PolynomialMulSemiGroup.inv not defined') },
}
extend(O.PolynomialMulSemiGroup, O.Group);
O.PolynomialRing.init(O.PolynomialAddGroup, O.PolynomialMulSemiGroup);
module.exports = O;
},{"./field":4}],2:[function(require,module,exports){
// http://blog.smartbear.com/testing/four-serious-math-libraries-for-javascript/
// Four Serious Math Libraries for JavaScript
var B = {};
B.slice = function(a) {
return Array.prototype.slice.call(a);
}
B.bind=function(o, member) {
if (typeof o[member]==='Function')
return o[member].bind(o);
else
return o[member];
}
B.ncall = function() {
var args = B.slice(arguments);
var n = args[0];
var o = args[1];
var fname = args[2];
var params = args.slice(3);
var a=[];
for (var i=0; i<n; i++)
a.push(o[fname].apply(o, params));
return a;
}
B.mapFunctions=function(host, obj, pairs) {
for (var h in pairs) {
var o = pairs[h];
if (typeof host[h] !=='undefined')
console.log('mapBind: error!', h, ' has been defined!');
host[h]=B.bind(obj, o);
}
}
B.copyFunctions=function(host, obj, names) {
for (var name of names) {
if (typeof host[name] !=='undefined')
console.log('namesBind: error!', name, ' has been defined!');
host[name]=B.bind(obj, name);
}
}
B.mix=function(self, members) {
for (var name in members) {
var member = members[name];
if (typeof self[name] === 'undefined') {
Object.defineProperty(self, name, {
enumerable: true,
writable: true,
value: member,
});
} else {
console.log("B.mix fail:", name, " already exists!");
}
}
}
B.arg1this = function(f,obj) { // 傳回一個已經綁定 f, obj 的函數
return function() {
var args = B.slice(arguments);
return f.apply(obj, [this].concat(args)); // 效果相當於 obj.f(this, args)
}
}
B.mixThis=function(proto, obj, fmembers) {
for (var fname of fmembers) {
var f = obj[fname];
if (typeof proto[fname] === 'undefined') {
Object.defineProperty(proto, fname, {
enumerable: false,
writable: true,
value: B.arg1this(f,obj), // proto.f(args) => obj.f(this, args) , 這行盡量不要動,除非想得很清楚了!
});
} else {
console.log("B.mixThis:", fname, " fail!");
}
}
}
B.mixThisMap=function(proto, obj, poMap) {
for (var pname in poMap) {
var oname = poMap[pname];
var f = obj[oname];
if (typeof proto[pname] === 'undefined') {
Object.defineProperty(proto, pname, {
enumerable: false,
writable: true,
value: B.arg1this(f,obj), // proto.f(args) = f(this, args) , 這行盡量不要動,除非想得很清楚了!
});
} else {
console.log('pname=', pname, 'proto[pname]=', proto[pname]);
console.log("B.mixThisMap:", oname, " fail!");
}
}
}
B.ctrim=function(s, set, side) {
side = side||"both";
for (var b=0; b<s.length; b++)
if (set.indexOf(s[b])<0) break;
for (var e=s.length-1; e>=0; e--)
if (set.indexOf(s[e])<0) break;
if (side === "right") b=0;
if (side === "left") e=s.length-1;
return s.substring(b, e+1);
}
B.lpad=function(s, width, ch) {
return s.length >= width ? s : new Array(width - s.length + 1).join(ch) + s;
}
B.def = function(x, value) {
return (typeof x !== 'undefined')?x:value;
}
B.precision=2;
B.nstr = function(n, precision=B.precision) {
if (n % 1 === 0) return n.toString();
return n.toFixed(precision);
}
B.astr = function(a, precision=B.precision) {
var s=[];
for (var i in a) {
s.push(a[i].str(precision));
}
return "["+s.join(', ')+"]";
}
B.sstr = function(s) { return s.toString(); }
B.ostr = function(o, precision=B.precision) {
var s = [];
for (var k in o)
s.push(k+":"+B.str(o[k], precision));
return "{"+s.join(", ")+"}";
}
B.str = function(o, precision=B.precision) {
if (typeof o ==='undefined')
return 'undefined';
else
return o.str(precision);
}
module.exports = B;
/*
B.calls = function() {
var args = B.slice(arguments);
var n = args[0];
var f = args[1];
var params = args.slice(2);
var a=[];
for (var i=0; i<n; i++)
a.push(f.apply(null, params));
return a;
}
*/
/*
B.slice = function(a) {
return Array.prototype.slice.call(a);
}
B.curry = function(f,o) {
return function() {
var args = Array.prototype.slice.call(arguments);
return f.apply(null, [o].concat(args));
}
}
B.mixThis=function(proto, fmap) {
for (var name in fmap) {
var f = fmap[name];
if (typeof proto[name] === 'undefined') {
Object.defineProperty(proto, name, {
enumerable: false,
writable: true,
value: B.arg1this(f), // proto.f(args) = f(this, args)
});
} else {
console.log("B.mixThis:", name, " fail!");
}
}
}
B.thisAsArg1 = function(f) {
return function() {
var args = B.slice(arguments);
return f.apply(null, [this].concat(args));
}
}
*/
/*
B.mixThis=function(proto, obj, fmembers) {
for (var fname of fmembers) {
// var f = B.bind(obj, fname);
var f = obj[fname];
if (typeof proto[fname] === 'undefined') {
Object.defineProperty(proto, fname, {
enumerable: false,
writable: true,
value: B.arg1this(f,obj), // proto.f(args) = f(this, args)
});
} else {
console.log("B.mixThis:", fname, " fail!");
}
}
}
*/
},{}],3:[function(require,module,exports){
module.exports = O = require("./matrix");
// =========== Calculus =================
O.dx = 0.01;
// 微分 differential calculus
O.fdiff = O.fdifferential = function(f, x, dx) {
dx = dx || O.dx;
var dy = f(x.add(dx)).sub(f(x.sub(dx)));
return dy.div(dx.mul(2));
}
// 積分 integral calculus
O.fint = O.fintegral = function(f, a, b, dx) {
dx = dx || O.dx;
var area = 0.0;
for (var x=a; x<b; x=x+dx) {
area = area + f(x).mul(dx);
}
return area;
}
// 偏微分 partial differential calculus
// f=[f1,f2,....] , x=[x1,x2,...] , dx=[dx1,dx2,....]
O.pdiff = O.pdifferential = function(f, x, i) {
f = O.fa(f);
var dx = O.vfill(x.length, 0);
dx[i] = O.dx;
// var df = f.apply(null, x.add(dx)).sub(f.apply(null, x.sub(dx)));
var df = f(x.add(dx)).sub(f(x.sub(dx)));
return df.div(dx.norm().mul(2));
}
// multidimensional integral calculus
// f=[f1,f2,....] , a=[a1,a2,...] , b=[b1,b2,....]
O.pint = O.pintegral = function(f, a, b) {
}
// 梯度 gradient : grad(f,x)=[pdiff(f,x,0), .., pdiff(f,x,n)]
O.fgrad = O.fgradient = function(f, x) {
var gf = [];
for (var i=0; i<x.length; i++) {
gf[i] = O.pdiff(f, x, i);
}
return gf;
}
// 散度 divergence : div(F,x) = sum(pdiff(F[i],x,i))
O.fdiv = O.fdivergence = function(F, x) {
var Fx = F(x);
var f=[], d=[];
for (var i=0; i<x.length; i++) {
f[i] = (xt)=>F(xt)[i];
d[i] = O.pdiff(f[i],x,i);
}
return d.sum();
}
// 旋度 curl : curl(F) = div(F)xF
O.fcurl = O.fcurlance = function(F, x) {
}
// 線積分: int F●dr = int F(r(t))●r'(t) dt
O.vint = O.vintegral = function(F, r, a, b, dt) {
dt = dt||O.dx;
var sum = 0;
for (var t=a; t<b; t+=dt) {
sum += F(r(t)).dot(r.diff(t));
}
return sum;
}
// 定理:int F●dr = int(sum(Qxi dxi))
// 向量保守場: F=grad(f) ==> int F●dr = f(B)-f(A)
// 定理: 向量保守場 F, pdiff(Qxi,xj) == pdiff(Qxj,xi) for any i, j
// ex: F=[x^2y, x^3] 中, grad(F)=[x^2, 3x^2] 兩者不相等,所以不是保守場
// 格林定理:保守場中 《線積分=微分後的區域積分》
// int P dx + Q dy = int int pdiff(Q,x) - pdiff(P, y) dx dy
// 散度定理:通量 = 散度的區域積分
// 2D : int F●n ds = int int div F dx dy
// 3D : int int F●n dS = int int int div F dV
// 史托克定理: F 在曲面 S 上的旋度總和 = F 沿著邊界曲線 C 的線積分
// int int_D curl(F)●n dS = int_C F●dr
},{"./matrix":8}],4:[function(require,module,exports){
// module : Field & Group Theory
var F = require("./set");
F.Integer=require("./integer");
var eq = F.eq;
// ========== Group =================
// 注意: 箭頭函數會自動將 this 變數綁定到其定義時所在的物件,因此以下很多地方不能用箭頭函數。
// 參考: https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Functions/Arrow_functions
F.Group={
invOp:function(x,y) {
return this.op(x,this.inv(y));
},
power:function(x,n) {
var p=this.e;
for (var i=0;i<n;i++) {
p=this.op(p,x);
}
return p;
},
leftCoset:function(g, H) {
var set = new F.Set();
for (var i in H)
set.add(this.op(g,H[i]));
return set;
},
rightCoset:function(H, g) {
var set = new F.Set();
for (var i in H)
set.add(this.op(g,H[i]));
return set;
},
// ref:https://en.wikipedia.org/wiki/Group_(mathematics)
// 封閉性:For all a, b in G, a • b, is also in G
closability:function(a,b) {
var ab = this.op(a,b);
var close=this.has(ab);
return this.has(this.op(a,b));
},
// 結合性:For all a, b and c in G, (a • b) • c = a • (b • c).
associativity:function(a,b,c) {
var op = this.op.bind(this);
return eq(op(op(a,b),c), op(a,op(b,c)))
},
// 單位元素:Identity element
identity:function(a) {
return eq(this.op(this.e,a),a)
},
// 反元素:Inverse element
inversability:function(a) {
return eq(this.op(a,this.inv(a)),this.e);
},
}
// PermutationGroup
F.PermutationGroup={
op:function(x,y) {
var z = [];
for (var i in x)
z[i] = y[x[i]];
return z;
},
inv:function(x) {
var nx = [];
for (var i in x) {
nx[x[i]] = i;
}
return nx;
},
}
extend(F.PermutationGroup, F.Group);
// Cyclic Group : a group that is generated by a single element (g)
F.CyclicGroup={
G:[],
// g:g,
op:function(x,y) {
},
inv:function(x) {
},
create(g) {
var t = e;
for (var i=0; !t.eq(e); i++) {
G[i]=t;
t=op(g,G[i]);
}
}
}
extend(F.CyclicGroup, F.Group);
// NormalSubGroup : 正規子群
F.NormalSubGroup={
op:function(x,y) {
},
inv:function(x) {
},
normality(g,n) {
return this.has(g.op(n).op(g.inv()));
},
}
extend(F.NormalSubGroup, F.Group);
// Quotent Group : aggregating similar elements of a larger group using an equivalence relation that preserves the group structure
F.QuotentGroup={
eq:function(x,y) {
},
op:function(x,y) {
},
inv:function(x) {
},
}
extend(F.QuotentGroup, F.Group);
// Normal SubGroup : gH = Hg
// https://en.wikipedia.org/wiki/Normal_subgroup
F.NormalSubGroup={
op:function(x,y) {
},
inv:function(x) {
},
}
extend(F.NormalSubGroup, F.Group);
// 群同構第一定理: 給定 GG和 G ′ 兩個群,和 f : G → G ′ 群同態。則 Ker f 是一個 G 的正規子群。
// 群同構第二定理:給定群 G 、其正規子群 N、其子群 H,則 N ∩ H 是 H 的正規子群,且我們有群同構如下: H / ( H ∩ N ) ≃ H N / N
// 群同構第三定理: 給定群 G, N 和 M,M 為 G 的正規子群,滿足 M 包含於 N ,則 N / M 是 G / M 的正規子群,且有如下的群同構: ( G / M ) / ( N / M ) ≃ G / N .
// ========== Field =================
F.Field={
sub:function(x,y) { return this.addGroup.invOp(x,y) },
div:function(x,y) { return this.mulGroup.invOp(x,y) },
// mod:function(x,y) { return x.sub(x.div(y).mul(y)) },
power:function(x,n) { return this.mulGroup.power(x,n) },
init:function(addGroup, mulGroup) {
this.addGroup = addGroup;
this.mulGroup = mulGroup;
this.zero = addGroup.e;
this.add = function(x,y) { return this.addGroup.op(x,y) }
this.neg = function(x) { return this.addGroup.inv(x) }
this.one = mulGroup.e;
this.mul = function(x,y) { return this.mulGroup.op(x,y) }
this.inv = function(x) { return this.mulGroup.inv(x) }
this.power= function(x,n) { return this.mulGroup.power(x,n) }
this.eq = function(x,y) { return F.eq(x,y); }
this.neq = function(x,y) { return !this.eq(x,y); }
this.isZero = function(x) {
return this.field.eq(this, F.proto(this).zero)
}
this.isOne = function(x) {
return this.field.eq(this, F.proto(this).one)
}
this.gcd = function(x,y) {
if (y.isZero()) return x;
return gcd(y, mod(x,y));
}
},
ldistribute:function(a,b,c) {
return this.mul(a, this.add(b,c)).eq(this.add(this.mul(a,b), this.mul(a,c)));
},
rdistribute:function(a,b,c) {
return this.ldistribute(b,c,a);
},
associativity:function(a,b,c) {
return this.mul(a,this.mul(b,c)).eq(this.mul(this.mul(a,b),c));
},
}
F.Ring = F.Field; // Ring (環) : 可能沒有乘法單位元素和反元素的 Field
F.Module = F.Field;// Module(模) : (R +) is Ring, (R × M → M)
F.Ideal = F.Field; // Ideal (理想): 子環,且 i·r ∈ I (左理想), r·i ∈ I (右理想)
// ref : https://en.wikipedia.org/wiki/Group_homomorphism
// https://en.wikipedia.org/wiki/Fundamental_theorem_on_homomorphisms
// 同態:h(a • b) = h(a) x h(b)
F.homomorphism=function(h, g1, g2) {
var a=g1.random(), b=g2.random();
return eq(h(group1.op(a,b)), group2.op(h(a), h(b)))
}
// ref : https://en.wikipedia.org/wiki/Isomorphism
// https://en.wikipedia.org/wiki/Isomorphism_theorem
// 同構:h(a • b) = h(a) • h(b)
F.isomorphism=function(h1, h2, g1, g2) {
var a1=g1.random(), b1=g2.random();
var a2=g1.random(), b2=g2.random();
return homorphism(h1,g1,g2)&&homorphism(h2,g2,g1);
}
// ========== Float Field =================
F.FloatAddGroup={
e:0,
op:function(x,y) { return x+y },
inv:function(x) { return -x},
}
extend(F.FloatAddGroup, F.Group, F.Set.Float);
F.FloatMulGroup={
e:1,
op:function(x,y) { return x*y },
inv:function(x) { return 1/x},
}
extend(F.FloatMulGroup, F.Group, F.Set.Float);
F.FloatField=extend({}, F.Field, F.Set.Float);
F.FloatField.init(F.FloatAddGroup, F.FloatMulGroup);
// ========== Finite Field =================
F.FiniteAddGroup={
e:0,
op:function(x,y) { return (x+y)%this.n },
inv:function(x) { return (this.n-x) }
}
extend(F.FiniteAddGroup, F.Group);
F.FiniteMulGroup={
e:1,
op:function(x,y) { return (x*y)%this.n },
inv:function(x) { return this.invMap[x] },
setOrder:function(n) {
this.n = n;
let invMap = new Map();
for (var x=1; x<n; x++) {
var y = this.op(x,x);
invMap.set(x,y);
}
this.invMap = invMap;
}
}
extend(F.FiniteMulGroup, F.Group);
F.FiniteField=extend({}, F.Field);
F.FiniteField.create=function(n) {
var finiteField = extend(F.Finite(n), F.FiniteField);
var addGroup = extend(F.Finite(n), {n:n}, F.FiniteAddGroup);
var mulGroup = extend(F.Finite(n), {n:n}, F.FiniteMulGroup);
finiteField.init(addGroup, mulGroup);
mulGroup.setOrder(n);
return finiteField;
}
class MathObj {
constructor() {}
str() { return this.toString() }
}
F.MathObj = MathObj;
// =========== Field Object ==============
class FieldObj extends MathObj {
constructor(field) {
super();
this.field = field;
var p = Object.getPrototypeOf(this);
p.zero = field.zero;
p.one = field.one;
}
add(y) { return this.field.add(this,y) }
mul(y) { return this.field.mul(this,y) }
neg() { return this.field.neg(this) }
inv() { return this.field.inv(this) }
div(y) { return this.field.div(this,y) }
sub(y) { return this.field.sub(this,y) }
power(n) { return this.field.power(this,n) }
isZero(x) { return this.field.isZero(this) }
isOne(x) { return this.field.isOne(this) }
eq(y) { return this.field.eq(this, y) }
neq(y) { return this.field.neq(this, y) }
mod(y) { return this.field.mod(this, y) }
gcd(y) { return this.field.gcd(this, y) }
}
F.FieldObj = FieldObj;
// =========== Complex Field ==============
F.ComplexField=extend({}, F.Field);
class Complex extends FieldObj {
constructor(a,b) {
super(F.ComplexField);
this.a = a; this.b = b;
}
conj() { return new Complex(this.a, -1*this.b); }
str() {
var op = (this.b<0)?'':'+';
return this.a.str()+op+this.b.str()+'i';
}
toString() { return this.str() }
toPolar() {
var a=this.a, b=this.b, r=Math.sqrt(a*a+b*b);
var theta = Math.acos(a/r);
return {r:r, theta:theta}
}
power(k) {
var p = this.toPolar();
return Complex.polarToComplex(Math.pow(p.r,k), k*p.theta);
}
sqrt() {
return this.power(1/2);
}
static toComplex(o) {
if (F.isFloat(o))
return new Complex(o, 0);
else if (o instanceof Complex)
return o;
console.log('o=', o);
throw Error('toComplex fail');
}
static polarToComplex(r,theta) {
var a=r*Math.cos(theta), b=r*Math.sin(theta);
return new Complex(a, b);
}
static parse(s) {
var m = s.match(/^([^\+]*)(\+(.*))?$/);
var a = parseFloat(m[1]);
var b = typeof m[3]==='undefined'?1:parseFloat(m[3]);
return new Complex(a, b)
}
}
F.Complex = Complex;
var C = (a,b)=>new Complex(a,b);
var enumComplex=[C(1,0),C(0,1),C(0,0),C(2,3),C(-5,4),C(-10,-7)];
F.ComplexSet=new F.Set(enumComplex);
F.ComplexSet.has = (a)=>a instanceof Complex;
F.ComplexAddGroup={
e:new Complex(0,0),
op:function(x,y) {
x = Complex.toComplex(x), y=Complex.toComplex(y);
return new Complex(x.a+y.a, x.b+y.b)
},
inv:function(x) {
x = Complex.toComplex(x);
return new Complex(-x.a, -x.b)
}
}
extend(F.ComplexAddGroup, F.Group, F.ComplexSet);
F.ComplexMulGroup={
e:new Complex(1,0),
op:function(x,y) {
x = Complex.toComplex(x), y=Complex.toComplex(y);
return new Complex(x.a*y.a-x.b*y.b, x.a*y.b+x.b*y.a);
},
inv:function(x) {
x = Complex.toComplex(x);
var a=x.a,b=x.b, r=(a*a+b*b);
return new Complex(a/r, -b/r);
}
}
extend(F.ComplexMulGroup, F.Group, F.ComplexSet);
extend(F.ComplexField, F.ComplexSet);
F.ComplexField.init(F.ComplexAddGroup, F.ComplexMulGroup);
// =========== Ratio Field ==============
F.RatioField=extend({}, F.Field);
class Ratio extends FieldObj {
constructor(a,b) {
super(F.RatioField);
this.a = a; this.b = b;
}
reduce() {
var a = this.a, b=this.b;
var c = F.Integer.gcd(a, b);
return new Ratio(a/c, b/c);
}
toString() { return this.a+'/'+this.b; }
static parse(s) {
var m = s.match(/^(\d+)(\/(\d+))?$/);
var a = parseInt(m[1]);
var b = typeof m[3]==='undefined'?1:parseInt(m[3]);
return new Ratio(a, b)
}
}
F.Ratio = Ratio;
F.RatioAddGroup={
e:new Ratio(0,1),
op:function(x,y) { return new Ratio(x.a*y.b+x.b*y.a, x.b*y.b) },
inv:function(x) { return new Ratio(-x.a, x.b); },
}
extend(F.RatioAddGroup, F.Group);
F.RatioMulGroup={
e:new Ratio(1,1),
op:function(x,y) { return new Ratio(x.a*y.a, x.b*y.b) },
inv:function(x) { return new Ratio(x.b, x.a) },
}
extend(F.RatioMulGroup, F.Group);
F.RatioField.init(F.RatioAddGroup, F.RatioMulGroup);
// =========== Function Operation ==============
F.fneg=function(fx) { return function(v) {
return -1*fx(v);
}}
F.finv=function(fx) { return function(v) {
return 1/fx(v);
}}
F.fadd=function(fx,fy) { return function(v) {
return fx(v).add(fy(v));
}}
F.fsub=function(fx,fy) { return function(v) {
return fx(v).sub(fy(v));
}}
F.fmul=function(fx,fy) { return function(v) {
return fx(v).mul(fy(v));
}}
F.fdiv=function(fx,fy) { return function(v) {
return fx(v).div(fy(v));
}}
F.fcompose=function(fx,fy) { return function(v) {
return fx(fy(v));
}}
F.feval=function(f,x) { return f(x) }
// f=(x,y)=>x*y+x*x;
// f0=fa(f); f0([x,y]);
F.fa=function(f) {
return function(x) {
return f.apply(null, x);
}
}
// =========== Function Field ==============
F.FunctionField=extend({}, F.Field);
F.FunctionAddGroup={
e:function(x) { return 0 },
op:function(x,y) { return F.fadd(x,y) },
inv:function(x) { return F.fneg(x) },
}
extend(F.FunctionAddGroup, F.Group);
F.FunctionMulGroup={
e:function(x) { return f(x) },
op:function(x,y) { return F.fsub(x,y) },
inv:function(x) { return F.finv(x) },
}
extend(F.FunctionMulGroup, F.Group);
F.FunctionField.init(F.FunctionAddGroup, F.FunctionMulGroup);
// Function
F.isField=function(x) {
return F.isBool(x) || F.isNumber(x) || x instanceof F.FieldObj;
}
module.exports = F;
},{"./integer":6,"./set":9}],5:[function(require,module,exports){
var G = require("./statistics");
// 各種 space : https://en.wikipedia.org/wiki/Space_(mathematics)#/media/File:Mathematical_implication_diagram_eng.jpg
G.Space={} // Space = HllbertSpace + BanachSpace + Manifold (流形)
G.HilbertSpace={} // HilbertSpace => InnerProductSpace => LocallyConvaxSpace => VectorSpace (LinearSpace)
G.InnerProductSpace={}
G.LocallyConvaxSpace={}
G.LinearSpace=G.VectorSpace={} // (Algebraic)
G.BanachSpace={} // BanachSpace => NormedVectorSpace => MetricSpace => TopologicalSpace
G.NormedVectorSpace={}
G.MetricSpace={}
G.TopologicalSpace={} // (Analytic)
G.Manifold={}
G.Rn = {} // (R,R,....)
G.steps = function(from, to, step) {
step=step || 1;
var a=[];
for (var t=from; t<=to; t+=step)
a.push(t);
return a;
}
G.curve=function(f, from=-10, to=10, step=0.1) {
var x=G.steps(from, to, step);
var y=x.map(f);
return { type:"curve", x:x, y:y };
}
G.hist=function(a, from, to, step=1) {
// console.log("from=%d to=%d step=%d", from, to, step);
from = from||a.min();
to = to||a.max();
var n = Math.ceil((to-from+G.EPSILON)/step);
var xc = G.steps(from+step/2.0, to, step);
// console.log("from=%d to=%d step=%d xc=%j", from, to, step, xc);
var bins = G.newV(n, 0);
for (var i in a) {
var slot=Math.floor((a[i]-from)/step);
if (slot>=0 && slot < n)
bins[slot]++;
}
return { type:'histogram', xc:xc, bins:bins, from:from, to:to, step:step};
}
/*
G.ihist=function(a) {
console.log("a.min()=%d a.max()=%d", a.min(), a.max());
return G.hist(a, a.min()-0.5, a.max()+0.5, 1);
}
*/
module.exports=G;
},{"./statistics":10}],6:[function(require,module,exports){
var I = {};
I.gcd = function(a, b) {
if (!b) return a;
return I.gcd(b, a % b);
}
I.lcm = function(a, b) {
return (a * b) / gcd(a, b);
}
I.isPrime=function(n) {
for (var i=2; i<=Math.sqrt(n); i++)
if (n%i===0) return false;
return n%1===0;
}
module.exports = I;
},{}],7:[function(require,module,exports){
// var M = require("./calculus");
var M = require("./geometry");
module.exports=M;
},{"./geometry":5}],8:[function(require,module,exports){
var N = require("numeric");
var M = require("./algebra");
// var M = N;
// Advance mathematics
M.ode=N.dopri; // dopri(x0,x1,y0,f,tol,maxit,event) #Ordinary Diff Eq
M.minimize=N.uncmin; // uncmin(f,x0,tol,gradient,maxit,callback,options) # Unconstrained optimization
M.sparse=N.ccsSparse; // Matrix => Sparse
M.sparse2full=N.ccsFull; // Sparse => Matrix
// M.complex=N.t;
// matrix
M.svd = N.svd;
M.det = N.det;
M.inv = N.inv;
M.lu = N.cLU;
M.luSolve = N.cLUsolve;
M.dot = N.dot;
M.rep = N.rep;
M.tr = N.transpose;
M.diag = N.diag;
M.mstr = M.strM = N.prettyPrint;
// M.sumM = N.sum;
M.rows=function(m) { return m.length; }
M.cols=function(m) { return m[0].length; }
M.row =function(m,i) { return m[i]; }
M.col =function(m,j) {
var cols = m.cols();
var c = M.vnew(cols);
for (var i=0;i<cols;i++) {
c[i] = m[i][j];
}
return c;
}
M.newV = function(n, value) {
return M.rep([n], value||0);
}
M.newM = function(rows, cols, value) {
return M.rep([rows, cols], value||0);
}
M.randomV = function(n, a, b) {
return N.random([n]).mul(b-a).add(a);
}
M.randomM = function(rows, cols, a, b) {
return N.random([rows, cols]).mul(b-a).add(a);
}
M.rowSum = function(m) {
var rows = M.rows(m);
var s=M.newV(rows, 0);
for (var i=0; i<rows; i++) {
s[i] = m[i].sum();
}
return s;
}
M.colSum = function(m) {
var mt = M.tr(m);
return M.rowSum(mt);
}
M.rowMean = function(m) {
return M.rowSum(m).div(m.cols());
}
M.colMean = function(m) {
return M.colSum(m).div(m.rows());
}
M.addMV = function(m,v) {
var result = [];
for(var i=0;i<m.length;i++) {
result.push(m[i].add(v));
}
return result;
}
M.mapM = function(m, f) {
var fm = M.clone(m);
var rows = M.rows(m), cols=M.cols(m);
for(i=0;i<rows;i++) {
for(j=0;j<cols;j++)
fm[i][j]=f(m[i][j]);
}
return fm;
}
M.mapMM = function(m1,m2,f) {
var fm = M.clone(m1);
var rows = m1.rows(), cols=m1.cols();
for(i=0;i<rows;i++) {
for(j=0;j<cols;j++)
fm[i][j]=f(m1[i][j],m2[i][j]);
}
return fm;
}
M.flatM=function(m) {
var a=[];
var ai = 0;
for (var i=0; i<m.length;i++)
for (var j=0; j<m[i].length; j++)
a[ai++] = m[i][j];
return a;
}
M.fillVM=function(v,rows,cols) {
var m = M.newM(rows,cols);
for (var r=0; r<rows; r++) {
for (var c=0; c<cols; c++) {
m[r][c] = v[r*cols+c];
}
}
return m;
}
M.fillMM=function(m,rows,cols) {
var v = M.flatM(m);
return M.fillVM(m,rows,cols);
}
M.eig=function(m) {
var E = N.eig(m);
return {lambda:E.lambda.x, E:E.E.x};
}
module.exports = M;
},{"./algebra":1,"numeric":16}],9:[function(require,module,exports){
var S = {}
var I = require("./integer");
S.PI = Math.PI;
S.E = Math.E;
extend = S.extend = Object.assign;
// ================= Rule =====================
var check = S.check = S.assert = function(cond, msg) {
if (cond)
console.log("O:"+msg);
else {
console.log("X:"+msg);
if (S.throwError) throw Error('check fail!');
}
}
be = S.be =function(msg,cond) { return check(cond, msg) }
S.proto=function(o) { return Object.getPrototypeOf(o) }
// relation
var eq=S.eq=function(a,b) {
return (typeof a === typeof b) && a.toString()===b.toString()
}
S.neq=function(a,b) { return !S.eq(a,b) }
S.leq=function(a,b) { return a<=b }
S.geq=function(a,b) { return a>=b }
S.lt =function(a,b) { return a<b }
S.gt =function(a,b) { return a>b }
// ========= type checking =================
S.yes=function(a) { return true }
S.no=function(a) {return false }
S.isBool=function(a) {
return typeof a === 'boolean' || a instanceof Boolean
}
S.isFunction=function(a) {
return typeof a==='function' || a instanceof Function
}
S.isString=function(a) {
return typeof a==='string' || a instanceof String
}
S.isObject=function(a) {
return typeof a==='object' || a instanceof Object
}
S.isArray=function(a) {
return a instanceof Array
}
S.isUndefined=function(a) {
return typeof a === 'undefined'
}
S.isSet=function(a) {
return a instanceof Set
}
S.isFloat=S.isNumber=function(a) {
return typeof a === 'number' || a instanceof Number
}
S.isInteger=function(a) { return S.isFloat(a) && a%1===0 }
S.isZero=function(a) { return a===0 }
S.isPositive=function(a) { return a>0 }
S.isNegative=function(a) { return a<0 }
S.isEven=function(a) { return (S.isInteger(a) && a%2===0) }
S.isOdd=function(a) { return (S.isInteger(a) && a%2===1) }
// ========== Random ==============
S.random=function(a,b) {
return a+Math.random()*(b-a);
}
S.randomInt=function(a,b) {
return Math.floor(S.random(a,b));
}
S.sample=function(a) {
return a[S.randomInt(0,a.length)];
}
// ========= Set ===================
Set.prototype.union = function(setB) {
var union = new Set(this);
for (var elem of setB) {
union.add(elem);
}
return union;
}
Set.prototype.intersection = function(setB) {
var intersection = new Set();
for (var elem of setB) {
if (this.has(elem)) {
intersection.add(elem);
}
}
return intersection;
}
Set.prototype.difference = function(setB) {
var difference = new Set(this);
for (var elem of setB) {
difference.delete(elem);
}
return difference;
}
Set.prototype.enumerate = function(n) {
var array=[], values = this.values();
for (var i=0; i<n; i++) {
array.push(values.next().value);
}
return array;
}
class EnumSet {
constructor(enumHead) {
this.set = new Set(enumHead);
this.enumHead = S.isUndefined(enumHead)?[]:enumHead;
}
add(e) { this.set.add(e) }
has(e) { return this.set.has(e) }
sample(n) {
if (S.isUndefined(n))
return S.sample(this.enumHead);
else {
var a=[];
for (var i=0; i<n; i++) a.push(this.sample());
return a;
}
}
enumerate() { return this.enumHead }
intersection(y) {
var x=this, xy=new EnumSet();
xy.has=function(e) { return x.has(e)&&y.has(e) }
return xy;
}
union(y) {
var x=this, xy=new EnumSet();
xy.has=function(e) { return x.has(e)||y.has(e) }
return xy;
}
difference(y) {
var x=this, xy=new EnumSet();
xy.has=function(e) { return x.has(e)&&!y.has(e) }
return xy;
}
symmetricDifference(y) {
var x=this;
return x.union(y).difference(x.intersection(y));
}
cartesianProduct(y) {
var x=this, xy=new EnumSet();
xy.has=function(e) { return x.has(e[0]) && y.has(e[1]) }
return xy;
}
}
S.Set = EnumSet
function steps(a,b,step) {
var array=[];
for (var i=a; i<=b; i+=step)
array.push(i);
return array;
}
var enumFloat = [-3.2,-1, 0, 1, 2.3, 4.7];
var enumInt = [-10,-5,-1,0,1,3,5,6];
var enumN0 = steps(0,10,1);
var enumN1 = steps(1,10,1);
var enumOdd = steps(1,15,2);
var enumEven = steps(2,15,2);
var enumPrime = [2,3,5,7,11,13,17,19,23,29,31,37];
var enumAll = ["hi", 5, Math.PI, EnumSet, S.isBool, enumPrime, new Set() ];
// 全體集合
S.All = new EnumSet(enumAll);
S.All.has = S.yes;
// 空集合
S.Empty = new EnumSet([]);
S.Empty.has = S.no;
// 浮點數集合
S.Float=new EnumSet(enumFloat);
S.Float.has=S.isFloat;
// 整數集合
S.Z=S.Integer=new EnumSet(enumInt);
S.Z.has=S.isInteger;
// 自然數集合 N0
S.N0=new EnumSet(enumN0);
S.N0.has=(e)=>S.isInteger(e)&&e>=0;
// 自然數集合 N1
S.N1=new EnumSet(enumN1);
S.N1.has=(e)=>S.isInteger(e)&&e>1;
// 偶數集合
S.Even=new EnumSet(enumEven);
S.Even.has=S.isEven;
// 奇數集合
S.Odd=new EnumSet(enumOdd);
S.Odd.has=S.isOdd;
// 質數集合
S.Prime=new EnumSet(enumPrime)
S.Prime.has=I.isPrime;
// 有限集合 0...n-1
S.Finite=(n)=>new EnumSet(steps(0,n-1,1));
// 羅素集合悖論
S.RussellSet=new EnumSet(enumAll);
S.RussellSet.has=function(e) { return !e.has(e) }
module.exports=S;
},{"./integer":6}],10:[function(require,module,exports){
var B = require('./base');
var J = require('jStat').jStat;
var S = require('./calculus');
var ncall = B.ncall;
// var T, R;
// ========== 離散分佈的 r, q 函數 ============
S.qcdf=function(cdf, q, N, p) {
for (var i=0; i<=N; i++) {
if (cdf(i, N, p) > q) return i;
}
return N;
}
S.rcdf=function(cdf, n, N, p) {
var a = [];
for (var i=0; i<n; i++) {
var q = Math.random();
a.push(cdf(q, N, p));
}
return a;
}
S.EPSILON=0.0000000001;
// 均等分布 : jStat.uniform( a, b )
S.dunif=(x,a=0,b=1)=>J.uniform.pdf(x,a,b);
S.punif=(q,a=0,b=1)=>J.uniform.cdf(q,a,b);
S.qunif=(p,a=0,b=1)=>J.uniform.inv(p,a,b);
S.runif=(n,a=0,b=1)=>ncall(n, J.uniform, 'sample', a, b);
// 常態分布 : jStat.normal( mean, sd )
S.dnorm=(x,mean=0,sd=1)=>J.normal.pdf(x,mean,sd);
S.pnorm=(q,mean=0,sd=1)=>J.normal.cdf(q,mean,sd);
S.qnorm=(p,mean=0,sd=1)=>J.normal.inv(p,mean,sd);
S.rnorm=(n,mean=0,sd=1)=>ncall(n, J.normal, 'sample', mean, sd);
// F 分布 : jStat.centralF( df1, df2 )
S.df=(x,df1,df2)=>J.centralF.pdf(x,df1,df2);
S.pf=(q,df1,df2)=>J.centralF.cdf(q,df1,df2);
S.qf=(p,df1,df2)=>J.centralF.inv(p,df1,df2);
S.rf=(n,df1,df2)=>ncall(n, J.centralF, 'sample', df1, df2);
// T 分布 : jStat.studentt( dof )
S.dt=(x,dof)=>J.studentt.pdf(x,dof);
S.pt=(q,dof)=>J.studentt.cdf(q,dof);
S.qt=(p,dof)=>J.studentt.inv(p,dof);
S.rt=(n,dof)=>ncall(n, J.studentt, 'sample', dof);
// Beta 分布 : jStat.beta( alpha, beta )
S.dbeta=(x,alpha,beta)=>J.beta.pdf(x,alpha,beta);
S.pbeta=(q,alpha,beta)=>J.beta.cdf(q,alpha,beta);
S.qbeta=(p,alpha,beta)=>J.beta.inv(p,alpha,beta);
S.rbeta=(n,alpha,beta)=>ncalls(n, J.beta, 'sample', alpha, beta);
// 柯西分布 : jStat.cauchy( local, scale )
S.dcauchy=(x,local,scale)=>J.cauchy.pdf(x,local,scale);
S.pcauchy=(q,local,scale)=>J.cauchy.cdf(q,local,scale);
S.qcauchy=(p,local,scale)=>J.cauchy.inv(q,local,scale);
S.rcauchy=(n,local,scale)=>ncall(n, J.cauchy, 'sample', local, scale);
// chisquare 分布 : jStat.chisquare( dof )
S.dchisq=(x,dof)=>J.chisquare.pdf(x,dof);
S.pchisq=(q,dof)=>J.chisquare.cdf(q,dof);
S.qchisq=(p,dof)=>J.chisquare.inv(p,dof);
S.rchisq=(n,dof)=>ncall(n, J.chisquare, 'sample', dof);
// 指數分布 : jStat.exponential( rate )
S.dexp=(x,rate)=>J.exponential.pdf(x,rate);
S.pexp=(q,rate)=>J.exponential.cdf(q,rate);
S.qexp=(p,rate)=>J.exponential.inv(p,rate);
S.rexp=(n,rate)=>ncall(n, J.exponential, 'sample', rate);
// Gamma 分布 : jStat.gamma( shape, scale )
S.dgamma=(x,shape,scale)=>J.gamma.pdf(x,shape,scale);
S.pgamma=(q,shape,scale)=>J.gamma.cdf(q,shape,scale);
S.qgamma=(p,shape,scale)=>J.gamma.inv(p,shape,scale);
S.rgamma=(n,shape,scale)=>ncall(n, J.gamma, 'sample', shape, scale);
// 反 Gamma 分布 : jStat.invgamma( shape, scale )
S.rinvgamma=(n,shape,scale)=>ncall(n, J.invgamma, 'sample', shape, scale);
S.dinvgamma=(x,shape,scale)=>J.invgamma.pdf(x,shape,scale);
S.pinvgamma=(q,shape,scale)=>J.invgamma.cdf(q,shape,scale);
S.qinvgamma=(p,shape,scale)=>J.invgamma.inv(p,shape,scale);
// 對數常態分布 : jStat.lognormal( mu, sigma )
S.dlognormal=(n, mu, sigma)=>J.lognormal.pdf(x,sigma);
S.plognormal=(n, mu, sigma)=>J.lognormal.cdf(q,sigma);
S.qlognormal=(n, mu, sigma)=>J.lognormal.inv(p,sigma);
S.rlognormal=(n, mu, sigma)=>ncall(n, J.dlognormal, 'sample', mu, sigma);
// Pareto 分布 : jStat.pareto( scale, shape )
S.dpareto=(n, scale, shape)=>J.pareto.pdf(x,scale,shape);
S.ppareto=(n, scale, shape)=>J.pareto.cdf(q,scale,shape);
S.qpareto=(n, scale, shape)=>J.pareto.inv(p,scale,shape);
S.rpareto=(n, scale, shape)=>ncall(n, J.pareto, 'sample', scale, shape);
// Weibull 分布 jStat.weibull(scale, shape)
S.dweibull=(n, scale, shape)=>J.weibull.pdf(x,scale,shape);
S.pweibull=(n, scale, shape)=>J.weibull.cdf(q,scale,shape);
S.qweibull=(n, scale, shape)=>J.weibull.inv(p,scale,shape);
S.rweibull=(n, scale, shape)=>ncall(n, J.weibull, 'sample', scale, shape);
// 三角分布 : jStat.triangular(a, b, c)
S.dtriangular=(n, a, b, c)=>J.triangular.pdf(x,a,b,c);
S.ptriangular=(n, a, b, c)=>J.triangular.cdf(q,a,b,c);
S.qtriangular=(n, a, b, c)=>J.triangular.inv(p,a,b,c);
S.rtriangular=(n, a, b, c)=>ncall(n, J.triangular, 'sample', a, b, c);
// 類似 Beta 分布,但計算更簡單 : jStat.kumaraswamy(alpha, beta)
S.dkumaraswamy=(n, alpha, beta)=>J.kumaraswamy.pdf(x,alpha,beta);
S.pkumaraswamy=(n, alpha, beta)=>J.kumaraswamy.cdf(q,alpha,beta);
S.qkumaraswamy=(n, alpha, beta)=>J.kumaraswamy.inv(p,alpha,beta);
S.rkumaraswamy=(n, alpha, beta)=>ncalls(n, J.kumaraswamy, 'sample', alpha, beta);
// ========== 離散分佈的 r, q 函數 ============
// 二項分布 : jStat.binomial(n, p0)
S.dbinom=(x, size, prob)=>J.binomial.pdf(x, size, prob);
S.pbinom=(q, size, prob)=>J.binomial.cdf(q, size, prob);
S.qbinom=(p, size, prob)=>S.qcdf(S.pbinom, p, size, prob);
S.rbinom=(n, size, prob)=>S.rcdf(S.qbinom, n, size, prob);
// 負二項分布 : jStat.negbin(r, p)
S.dnbinom=(x, size, prob)=>J.negbin.pdf(x, size, prob);
S.pnbinom=(q, size, prob)=>J.negbin.cdf(q, size, prob);
S.qnbinom=(p, size, prob)=>S.qcdf(S.pnbinom, p, size, prob);
S.rnbinom=(n, size, prob)=>S.rcdf(S.qnbinom, n, size, prob);
// 超幾何分布 : jStat.hypgeom(N, m, n)
S.dhyper=(x, m, n, k)=>J.hypgeom.pdf(k, m, n, k);
S.phyper=(q, m, n, k)=>J.hypgeom.cdf(q, m, n, k);
S.qhyper=(p, m, n, k)=>S.qcdf(S.phyper, p, m, n, k);
S.rhyper=(nn,m, n, k)=>S.rcdf(S.qhyper, nn, m, n, k);
// 布瓦松分布 : jStat.poisson(l)
S.dpois=(x, lambda)=>J.poisson.pdf(x, lambda);
S.ppois=(q, lambda)=>J.poisson.cdf(q, lambda);
S.qpois=(p, lambda)=>S.qcdf(S.ppois, p, lambda);
S.rpois=(n, lambda)=>S.rcdf(S.qpois, n, lambda);
// ====================== statistics =================================
// extend function
S.normalize=function(a) {
var sum = S.sum(a);
return a.map(function(x) { return x/sum});
}
// Vector Functionality
B.copyFunctions(S, J, "sumsqrt,sumsqerr,sumrow,mean,meansqerr,geomean,median,cumsum,cumprod,diff,mode,range,variance,stdev,meandev,meddev,skewness,kurtosis,coeffvar,quartiles,quantiles,percentile,percentileOfScore,histogram,covariance,corrcoeff,calcRdx,betafn,betacf,ibetainv,ibeta,gammafn,gammaln,gammap,lowRegGamma,gammapinv,factorialln,factorial,combination,combinationln,permutation,erf,erfc,erfcinv,randn,randg".split(","));
B.mapFunctions(S, J, {
C:'combination',// C(n,m)
choose:'combination',// C(n,m)
lchoose:'combinationln',// log C(n,m)
P:'permutation', // P(n,m)
sd:'stdev',
cov:'covariance',
cor:'corrcoeff',
});
// =============== 檢定 ==============================
B.mix(S, B);
var T = S;
T.test = function(o) { // name, D, x, mu, sd, y, alpha, op
Object.assign(o, {alpha:0.05, op:"="});
var alpha = o.alpha;
var pvalue, interval;
var D = o.D;
var q1 = D.o2q(o); // 單尾檢定的 pvalue
if (o.op === "=") {
if (q1>0.5) q1 = 1-q1; // (q1>0.5) 取右尾,否則取左尾。
pvalue= 2*q1; // 對稱情況:雙尾檢定的 p 值是單尾的兩倍。
interval = [D.q2p(alpha/2, o, "L"), D.q2p(1-alpha/2, o, "R")];
} else {
if (o.op === "<") { // 右尾檢定 H0: q < 1-alpha,
interval = [ D.q2p(alpha, o, "L"), Infinity ];
pvalue = 1-q1;
}
if (o.op === ">") { // 左尾檢定 H0: q > alpha
interval=[-Infinity, D.q2p(1-alpha, o, "R")];
pvalue = q1;
}
}
return {
name: o.name,
h: D.h(o),
alpha: alpha,
op: o.op,
pvalue: pvalue,
ci : interval,
df : D.df(o),
report: function() { S.report(this) }
};
}
T.report = function(o) {
console.log("=========== report ==========");
for (var k in o) {
if (typeof o[k] !== "function")
console.log(k+"\t: "+S.str(o[k]));
}
}
var t1 = { // 單樣本 T 檢定 t = (X-mu)/(S/sqrt(n))
h:function(o) { return "H0:mu"+o.op+o.mu; },
o2q:function(o) {
var x = o.x, n = x.length;
var t = (S.mean(x)-o.mu)/(S.sd(x)/Math.sqrt(n));
return S.pt(t, n-1);
},
// P(X-mu/(S/sqrt(n))<t) = q ; 信賴區間 P(T<q)
// P(mu > X-t*S/sqrt(n)) = q ; 這反而成了右尾檢定,所以左尾與右尾確實會反過來
q2p:function(q, o) {
var x = o.x, n = x.length;
return S.mean(x) + S.qt(q, n-1) * S.sd(x) / Math.sqrt(n);
},
df:function(o) { return o.x.length-1; }
}
var t2vareq = { // σ1=σ2, 合併 T 檢定 (雙樣本)
h:function(o) { return "H0:mu1"+o.op+"mu2" },
// S^2 = (n1-1)*S1^2+(n2-1)*S2^2)/(n1-1+n2-1)
sd:function(o) {
var x = o.x, n1 = x.length, y=o.y, n2=y.length;
var S1= S.sd(x), S2 = S.sd(y);
var S = Math.sqrt(((n1-1)*S1*S1+(n2-1)*S2*S2)/(n1-1+n2-1));
return S;
},
// T = ((X-Y)-(mu1-mu2))/(sqrt(1/n1+1/n2)*S)
o2q:function(o) {
var x = o.x, n1 = x.length, y=o.y, n2=y.length;
var S = this.sd(o);
var t = (S.mean(x)-S.mean(y)-o.mu)/(Math.sqrt(1/n1+1/n2)*S);
return S.pt(t, n1+n2-2);
},
// t=((X-Y)-mu)/(sqrt(1/n1+1/n2)*S), (X-Y)-t*sqrt(1/n1+1/n2)*S = mu
q2p:function(q, o) {
var x = o.x, n1 = x.length, y=o.y, n2=y.length;
var S = this.sd(o);
return S.mean(x)-S.mean(y)+ S.qt(q, n1+n2-2)*Math.sqrt(1/n1+1/n2)*S;
},
df:function(o) {
var x = o.x, n1 = x.length, y=o.y, n2=y.length;
return n1+n2-2;
}
}
var t2paired = { // 成對 T 檢定 T = (X-Y-mu)/(S/sqrt(n)) (雙樣本)
h:function(o) { return "H0:mu1"+o.op+"mu2" },
sd:function(o) { // S = sd(x-y)
var x = o.x, n = x.length, y=o.y;
var S= S.sd(S.sub(x,y));
return S;
},
o2q:function(o) {
var x = o.x, n = x.length, y=o.y;
var S = this.sd(o);
var t = (S.mean(S.sub(x,y))-o.mu)/(S/Math.sqrt(n));
return S.pt(t, n-1);
},
// mean(x-y)+t*S/sqrt(n)
q2p:function(q, o) {
var x = o.x, n = x.length, y=o.y;
var S = this.sd(o);