訊息
|
我創建的 MathNode.js 專案
- 專案壓縮檔:mathnode_v3.zip
- GitHub: https://github.com/ccckmit/mathnode
純 JavaScript 的科學計算函式庫
- 矩陣函式庫 — http://www.numericjs.com/ (超讚!)
- 統計函式庫 — http://www.jstat.org/ (超讚!)
- 依賴 jQuery, jQuery UI, flot (讚!)
- flot 是繪圖函式庫
- jquery.flot.image.js 可以讓 flot 所繪的圖輸出成為一個 image
- 應該加上 numericjs 就可以形成完整的 JavaScript 科學計算架構了。
- Git Hub 裏有更完整的專案
- 顯然連線性代數的函式庫都有了,這樣連 numericjs 都可以不用了。
- 但事實上,2012/8/3 時,筆者建置 jstat 並未成功。
numericjs
其中的 WorkShop 其實是用 flot 包裝後的函式庫,如下所示。
<script>
"use strict";
var _indexOf;
if(typeof Array.indexOf === "undefined") {
_indexOf = function(t,obj){
for(var i=0; i<t.length; i++){
if(t[i]==obj){
return i;
}
}
return -1;
}
} else _indexOf = function(t,obj) { return t.indexOf(obj); }
var _retarded = false;
if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)){ _retarded = true; }
if(_retarded) {
_queue = [];
_onmessage = function(ev) { _queue.push(ev); }
_loaded = 0;
window.Worker = function(f) {
var worker = this;
worker.queue = [];
worker.onmessage = function(ev) {};
worker.postMessage = function(ev) { _onmessage({data: ev}); };
var scr = document.createElement('script');
scr.src = f;
scr.type = 'text/javascript';
scr.onreadystatechange = function () {
var k;
if (scr.readyState == 'loaded' || scr.readyState == 'complete') {
for(k=0;k<_queue.length;k++) { _onmessage(_queue[k]); }
}
}
document.getElementsByTagName('head')[0].appendChild(scr);
workerPostMessage = function(ev) { worker.onmessage({data: ev}); }
}
importScripts = function(z) {
var scr = document.createElement('script');
scr.src = z;
scr.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(scr);
};
}
var workshop = (function () {
function resize(input) {
if(input.scrollHeight > input.clientHeight) {
input.style.height = (input.scrollHeight+10)+"px";
}
}
function elementPos(e){
var x = 0, y = 0, dx = e.offsetWidth, dy = e.offsetHeight;
while(e !== null){
x += e.offsetLeft;
y += e.offsetTop;
e = e.offsetParent;
}
return {x:x, y:y, dx:dx, dy:dy};
}
function checkpos(e) {
var foo = elementPos(e);
var y = window.pageYOffset, dy = window.innerHeight;
if(foo.y < y+10 || foo.y+foo.dy > y+dy-10) {
window.scrollTo(window.pageXOffset,Math.max(0,Math.round(foo.y-0.5*dy)));
}
}
function myfocus(e) {
checkpos(e);
e.focus();
}
var savedata;
var cache = [];
var count = 0;
var clear = [];
var divcount = 0;
var divorder = [0];
var w = new Worker('myworker.js');
var plotcount = 0;
function plotit(plotid,x) {
var k;
try {
if(typeof x.s === "object") $('#'+plotid).css(x.s);
$.plot($("#"+plotid), x.p, x.o);
} catch(e) {
var _foo = e.toString();
if(typeof e.stack !== "undefined" && typeof e.stack.toString !== "undefined") {
_foo += "\n\n"+e.stack.toString();
}
_foo = _foo.replace(/&/g,'&').replace(/>/g,'>').replace(/</g,'<').replace(/"/g,'"');
$('#'+plotid).after(_foo);
$('#'+plotid).remove();
}
}
var savereq = false;
function saveit() {
if(!savereq) {
savereq = true;
setTimeout(function () {
savereq = false;
localStorage.savedata = JSON.stringify(savedata);
},1000);
}
}
function outputChanged(k,o) {
var i = _indexOf(divorder,k);
savedata.outputs[i].push(o);
saveit();
}
w.onmessage = function(ev) {
var x = JSON.parse(ev.data);
var y = $('#out_'+x.k.toString())[0];
if(clear[x.k]) { y.innerHTML = ''; savedata.outputs[_indexOf(divorder,x.k)] = []; }
if(typeof x.p !== "undefined") {
var plotid = "plot_"+plotcount.toString();
plotcount++;
y.innerHTML += '<div class="plot" id="'+plotid+'"></div>';
(function () {
setTimeout(function () {
plotit(plotid,x);
setTimeout(function () {
outputChanged(x.k,x);
},0);
},0);
}());
clear[x.k] = false;
return;
}
else {
y.innerHTML += x.o;
(function () {
setTimeout(function() {
outputChanged(x.k,x.o); },0)
}());
clear[x.k] = false;
}
}
function mkdiv(i) {
divcount++;
var foo = _indexOf(divorder,i);
divorder.splice(foo+1,0,divcount);
savedata.inputs.splice(foo+1,0,'');
savedata.outputs.splice(foo+1,0,[]);
$('#output_'+i.toString()).after(
'<div class="inner" id = "input_'+divcount.toString()+'">'+
'<div class="caret">IN></div>'+
'<div class="input"><textarea rows=1 id = "text_'+divcount.toString()+'" class="input" onkeydown="workshop.mykeydown(event,'+divcount.toString()+');"></textarea></div>'+
'<div class="button"><a href="#" onclick="workshop.rmdiv('+divcount.toString()+')" class="button">✖</a></div>'+
'</div>'+
'<div class="inner" id = "output_'+divcount.toString()+'">'+
'<div class="out">OUT></div>'+
'<div id = "out_'+divcount.toString()+'" class="output"></div>'+
'<div class="button2"><a href="#" onclick="workshop.mkdiv('+divcount.toString()+');" class="button">↩</a></div>'+
'</div>'
);
}
function rmdiv(i) {
var foo = _indexOf(divorder,i);
divorder.splice(foo,1);
$('#input_'+i.toString()).remove();
$('#output_'+i.toString()).remove();
savedata.inputs.splice(foo,1);
savedata.outputs.splice(foo,1);
}
function go(k) {
var input = $('#text_'+k.toString())[0];
var n = _indexOf(divorder,k);
var foo = divorder[n+1];
if(typeof foo === "number") {
myfocus($('#text_'+foo.toString())[0]);
} else {
mkdiv(k);
foo = divorder[n+1];
}
input.className = "runned";
cache[k] = input.value;
myfocus($('#text_'+foo.toString())[0]);
clear[k] = true;
$('#out_'+k.toString())[0].innerHTML = "<img src=\"resources/wait16.gif\">";
var runit = function() { w.postMessage(JSON.stringify({k:k,n:n,e:input.value})); }
setTimeout(runit,0);
}
function inputChanged(k){
var i = _indexOf(divorder,k);
var input = $('#text_'+k.toString())[0];
if(input.value === cache[k]) input.className = "runned";
else { input.className = "input"; cache[k] = null; }
savedata.inputs[i] = input.value;
saveit();
}
var _foo;
var rc = 0;
function restore2(foo) {
if(foo) _foo = foo;
rc++;
if(rc<2) return;
foo = _foo;
savedata = { inputs: [], outputs: [], scripts: foo.scripts };
var baz = 'Version: <tt>'+foo.scripts[0]+'</tt>';
if(_indexOf(foo.scripts,workshop.updateVersion)<0) {
baz = baz + ' (Update to <tt><a href="javascript: workshop.update();">'+workshop.updateVersion+'</a></tt>)';
}
$('#divupdate')[0].innerHTML = baz;
if(foo.inputs.length === 0) { mkdiv(0); return; }
var input,output,i,j,f0;
for(i=1;i<foo.inputs.length;i++) {
mkdiv(i-1);
input = $('#text_'+i.toString())[0];
input.value = foo.inputs[i];
f0 = (function(in0) { return function() { resize(in0); }; }(input));
setTimeout(f0,0);
output = $('#out_'+i.toString())[0];
if(typeof foo.outputs[i] === "undefined") { continue; }
for(j=0;j<foo.outputs[i].length;j++) {
if(typeof foo.outputs[i][j] === "string") {
output.innerHTML += foo.outputs[i][j];
} else {
(function(i,j) {
var plotid = "plot_"+plotcount.toString();
plotcount++;
output.innerHTML += '<div class="plot" id="'+plotid+'"></div>';
setTimeout(function () {
plotit(plotid,{k:i, o:foo.outputs[i][j].o, p:foo.outputs[i][j].p});
},0);
}(i,j));
}
}
}
savedata = foo;
workshop.savedata = savedata;
}
function restore(savedata) {
w.postMessage(JSON.stringify({imports:savedata.scripts}));
restore2(savedata);
}
function preload(savedata) {
var k;
var client;
for(k=0;k<savedata.scripts.length;k++) {
client = new XMLHttpRequest();
client.open("GET", savedata.scripts[k]);
client.send();
}
}
function mykeydown(e,i) {
var input = $('#text_'+i.toString())[0];
checkpos(input);
resize(input);
setTimeout(function () { resize(input); },0);
var e = window.event?window.event:e;
if(e.keyCode === 13 && e.shiftKey === false) {
setTimeout(function () { inputChanged(i); go(i); },0);
if(window.event) e.returnValue = false;
else e.preventDefault();
} else {
setTimeout(function () { inputChanged(i); },0)
};
}
function reset() {
localStorage.clear();
window.location.replace('workshop.php');
}
function update() {
savedata.scripts = [workshop.updateVersion];
localStorage.savedata = JSON.stringify(savedata);
window.location.replace('workshop.php');
}
function submit() {
var f = document.myform;
var foo = JSON.stringify(savedata);
var digest = Crypto.SHA256(foo, { asBytes: true });
var s = document.myform.savedata;
s.value = foo;
digest = Crypto.util.bytesToHex(digest);
f.action = "workshop.php?link="+digest;
f.submit();
}
return {
print:print,
mkdiv:mkdiv,
rmdiv:rmdiv,
mykeydown:mykeydown,
w:w,
savedata:savedata,
restore:restore,
restore2:restore2,
reset:reset,
resize:resize,
submit:submit,
update:update,
preload:preload
}
}());
</script>
<script>
workshop._restore = ((typeof localStorage.savedata === "string")?
(JSON.parse(localStorage.savedata)):
{inputs: [], outputs: [],
scripts: ["lib/numeric-1.1.8.js"] });
workshop.version = "1.1.8";
workshop.updateVersion = "lib/numeric-1.1.8.js";
workshop.preload(workshop._restore);
</script>
<script>
workshop.restore(workshop._restore);
</script>
jStat
D:\ccc101\JavaScript\jstat-jstat-6d68253>make insall
make: *** No rule to make target `insall'. Stop.
D:\ccc101\JavaScript\jstat-jstat-6d68253>make install
'Downloading necessary libraries for build'
npm http GET https://registry.npmjs.org/uglify-js/1.2.3
npm http GET https://registry.npmjs.org/vows
npm http 200 https://registry.npmjs.org/uglify-js/1.2.3
npm http GET https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.3.tgz
npm http 200 https://registry.npmjs.org/vows
npm http GET https://registry.npmjs.org/vows/-/vows-0.6.3.tgz
npm http 200 https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.3.tgz
npm http 200 https://registry.npmjs.org/vows/-/vows-0.6.3.tgz
npm http GET https://registry.npmjs.org/eyes
npm http 200 https://registry.npmjs.org/eyes
npm http GET https://registry.npmjs.org/eyes/-/eyes-0.1.7.tgz
npm http 200 https://registry.npmjs.org/eyes/-/eyes-0.1.7.tgz
uglify-js@1.2.3 node_modules\uglify-js
vows@0.6.3 node_modules\vows
└── eyes@0.1.7
D:\ccc101\JavaScript\jstat-jstat-6d68253>make test
'Cleaning up build files'
'Building jStat'
命令語法不正確。
make: *** [jstat.js] Error 1
D:\ccc101\JavaScript\jstat-jstat-6d68253>
而且專案的 README 中也寫到:
*NOTE:* The code in this repository does not currently match that found on www.jstat.org. We are in the process of merging two similar projects and will update the website once the merge is complete.
因此還得等到專案成熟,所以我想可以先用 numericjs 作矩陣運算,jstat 僅作統計之用。
這個專案的 doctool.js 顯然是用 node.js 作的,而且用了 markd (Markdown) 的文件描述語法。
var fs = require("fs"),
path = require("path"),
markdown = require("./lib/markdown"),
argv = process.argv,
argc = argv.length,
template = fs.readFileSync(argv[2], "utf8");
純 JavaScript 的科學計算函式庫
- http://www.numericjs.com/ (超讚!)
- http://sylvester.jcoglan.com/docs.html (好!)
- http://code.google.com/p/webgl-mjs/
numericjs
- http://www.numericjs.com/
- Linear algebra
- Complex numbers
- Splines
- ODE solver
- Unconstrained optimization
- PDE and sparse linear algebra
sylvester (矩陣運算)
var M1 = $M([
[1,7,3],
[9,4,0],
[2,7,1]
]);
var M2 = $M([
[6,2,8],
[9,1,3],
[0,7,6]
]);
var M = M1.x(M2);
// M is the matrix
// 69 30 47
// 90 22 84
// 75 18 43
node-gsl — 統計運算
範例:
var gsl = require('gsl'),
seed = 50,
deviation = 0.5;
console.log( gsl.random.gaussian(deviation) );
console.log( gsl.random.gaussian(seed, deviation) );
var iterator = new gsl.Random(seed);
console.log( iterator.gaussian(deviation) );
console.log( iterator.gaussian(deviation) );
- gsl.Random([seed])
- Construct a new iterator, seel below for available random methods.
- gsl.random.get([seed])
- gsl.Random.get()
- Returns a random integer. The minimum and maximum values depend on the algorithm used, but all integers in the range [min,max] are equally likely. The values of min and max can determined using the auxiliary functions random.min() and random.max().
- gsl.random.min()
- gsl.Random.min()
- Returns the smallest value that random.get() can return.
- gsl.random.max()
- gsl.Random.max()
- Returns the largest value that random.get() can return.
- gsl.random.uniform([seed])
- gsl.Random.uniform()
- Returns a double precision floating point number uniformly distributed in the range [0,1). The range includes 0.0 but excludes 1.0.
- gsl.random.gaussian([seed], deviation)
- gsl.Random.gaussian(deviation)
- Returns a Gaussian random float with mean zero given a standart deviation as a float.
- gsl.random.gaussianZiggurat([seed], deviation)
- gsl.Random.gaussianZiggurat(deviation)
- Same as random.gaussian but using the alternative Marsaglia-Tsang ziggurat method.
- gsl.random.gaussianRatioMethod([seed], deviation)
- gsl.Random.gaussianRatioMethod(deviation)
- Same as random.gaussian but using the alternative Kinderman-Monahan-Leva ratio method.
- gsl.random.poisson([seed], mean)
- gsl.Random.poisson(mean)
- Returns a random integer from the Poisson distribution given a provided mean as a float.
參考文獻
- https://github.com/wdavidw/node-gsl
- http://nodejsmodules.org/tags/mathematics
- gsl — GNU Scientific Library for NodeJS.
- science — Scientific and statistical computing in JavaScript.
- lmj-maths — a library of mathematics routines
- gtest — g-test algorithm to compute statistical significance
- gamma — the gamma function (Γ) Try it out
- chi-squared — characteristic functions for chi-squared distributions
Facebook
|
Post preview:
Close preview