rlab
Version:
Javascript scientific library like R
279 lines (230 loc) • 7.46 kB
JavaScript
var R, A, V, N, F;
module.exports = R = A = V = N = F = require("./matrix");
// var A = R.Algebra, V = R.Vector, N = R.Number; //, p = N.parse;
// var F = R.F = R.Function = {}
var extend = R.extend;
// =========== Calculus =================
F.dx = 0.01;
// 微分 differential calculus
F.d = F.diff = F.differential = function(f, x, dx) {
dx = dx || F.dx;
var dy = f(x.add(dx)).sub(f(x.sub(dx)));
return dy.div(dx.mul(2));
}
// 積分 integral calculus
F.i = F.integral = function(f, a, b, dx) {
dx = dx || F.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,....]
F.pdiff = F.pdifferential = function(f, x, i) {
f = F.fa(f);
var dx = V.fill(x.length, 0);
dx[i] = F.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,....]
F.pintegral = function(f, a, b) {
}
// 梯度 gradient : grad(f,x)=[pdiff(f,x,0), .., pdiff(f,x,n)]
F.grad = F.gradient = function(f, x) {
var gf = [];
for (var i=0; i<x.length; i++) {
gf[i] = F.pdiff(f, x, i);
}
return gf;
}
// 散度 divergence : div(F,x) = sum(pdiff(F[i],x,i))
F.divergence = 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] = F.pdiff(f[i],x,i);
}
return d.sum();
}
// 旋度 curl : curl(F) = div(F)xF
F.curl = F.curlance = function(F, x) {
}
// 線積分: int F●dr = int F(r(t))●r'(t) dt
F.vintegral = function(F, r, a, b, dt) {
dt = dt||F.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
// =========== Function Operation ==============
F.neg=function(fx) { return function(v) {
return -1*fx(v);
}}
F.inv=function(fx) { return function(v) {
return 1/fx(v);
}}
F.add=function(fx,fy) { return function(v) {
return fx(v).add(fy(v));
}}
F.sub=function(fx,fy) { return function(v) {
return fx(v).sub(fy(v));
}}
F.mul=function(fx,fy) { return function(v) {
return fx(v).mul(fy(v));
}}
F.div=function(fx,fy) { return function(v) {
return fx(v).div(fy(v));
}}
F.compose=function(fx,fy) { return function(v) {
return fx(fy(v));
}}
F.eval=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({}, A.Field);
F.FunctionAddGroup={
e:function(x) { return 0 },
op:function(x,y) { return F.add(x,y) },
inv:function(x) { return F.neg(x) },
}
extend(F.FunctionAddGroup, F.AbelGroup);
F.FunctionMulGroup={
e:function(x) { return f(x) },
op:function(x,y) { return F.sub(x,y) },
inv:function(x) { return F.inv(x) },
}
extend(F.FunctionMulGroup, F.AbelGroup);
F.FunctionField.init(F.FunctionAddGroup, F.FunctionMulGroup);
// =========== Polynomial Ring ==============
A.PolynomialRing=extend({}, A.Field);
class Polynomial extends A.FieldObj {
constructor(c) {
super(A.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(); // 正規化
var c = p.c.toComplex();
console.log("c=%s", c);
switch (this.size()) {
case 2:return p.c[0].neg();
case 3:return p.root2(c[1], c[0]);
case 4:return p.root3(c[2], c[1], c[0]);
default:throw Error('root() fail');
}
}
root2(b,c) { // x^2 + bx + c =0
var d = b.mul(b).sub(c.mul(N.parse('4+0i'))).sqrt();
return [b.neg().add(d), b.neg().sub(d)];
}
root3(a,b,c) { // x^3+ax^2+bx+c=0
var q=a.power(3).mul(2/27).sub(a.mul(b).div(3).add(c)).div(2); // q=((2*a*a*a/27)-(a*b/3)+c)/2;
var p=b.sub(a.power(2).div(3)).div(3); // p=(b-a*a/3)/3;
var D=p.power(3).add(q.power(2)); // D=p*p*p+q*q;
var Dsqrt = D.sqrt(), _q=q.neg();
console.log("Dsqrt=%s _q=%s", Dsqrt, _q);
var u_p=_q.add(Dsqrt).power(1/3); // u+ = (-q+sqrt(D))^1/3
var u_m=_q.sub(Dsqrt).power(1/3); // u- = (-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 = N.parse('-1+3i').div(2); // rho+ = (-1+3i)/2
var rho_m = N.parse('-1-3i').div(2); // rho- = (-1-3i)/2
console.log("rho_p=%s rho_m=%s", rho_p, rho_m);
var y1=u_p.add(u_m); // y1 = (u+) + (u-)
var y2=rho_p.add(u_p).add(rho_m.mul(u_m)); // y2=(rho+)+(u+)+(rho-)*(u+)
var y3=rho_p.sub(u_p).add(rho_p.mul(u_m)); // y2=(rho+)+(u+)+(rho+)*(u-)
return [y1, y2, y3];
/*
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();
console.log("Dsqrt=%s _q=%s", Dsqrt, _q);
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(N.parse('-1+3i'));
var rho_m = (1/2).mul(N.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);
}
}
R.Polynomial = A.Polynomial = Polynomial;
A.PolynomialAddGroup={
e:new Polynomial([0]), // 到底應該設幾個?
op:function(x,y) {
var size = Math.max(x.size(), y.size());
var a=V.extend(x.c,size), b=V.extend(y.c,size);
var c=a.add(b);
return new Polynomial(c);
},
inv:function(x) {
var c = x.c.neg();
return new Polynomial(c);
},
}
extend(A.PolynomialAddGroup, A.Group);
A.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(A.PolynomialMulSemiGroup, A.Group);
A.PolynomialRing.init(A.PolynomialAddGroup, A.PolynomialMulSemiGroup);