version bump 0.2.1: cleanup
This commit is contained in:
parent
8bc7f35eaf
commit
3b7543e631
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
node_modules
|
||||
test_files/out.*
|
||||
misc/coverage.html
|
||||
|
58
Makefile
58
Makefile
@ -2,38 +2,66 @@ LIB=vdc
|
||||
REQS=
|
||||
ADDONS=
|
||||
AUXTARGETS=
|
||||
HTMLLINT=index.html
|
||||
|
||||
ULIB=$(shell echo $(LIB) | tr a-z A-Z)
|
||||
DEPS=
|
||||
TARGET=$(LIB).js
|
||||
FLOWTARGET=$(LIB).flow.js
|
||||
|
||||
## Main Targets
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGET) $(AUXTARGETS)
|
||||
all: $(TARGET) $(AUXTARGETS) ## Build library and auxiliary scripts
|
||||
|
||||
$(TARGET) $(AUXTARGETS): %.js : %.flow.js
|
||||
node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^\s*\/\*:[^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*:[^*]*\*\//gm,""))' > $@
|
||||
node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^[ \t]*\/\*[:#][^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*[:#][^*]*\*\//gm,""))' > $@
|
||||
|
||||
.PHONY: clean
|
||||
clean: clean-baseline
|
||||
clean: clean-baseline ## Remove targets and build artifacts
|
||||
rm -f $(TARGET)
|
||||
|
||||
## Testing
|
||||
|
||||
.PHONY: test mocha
|
||||
test mocha: test.js $(TARGET)
|
||||
test mocha: test.js $(TARGET) baseline ## Run test suite
|
||||
mocha -R spec -t 20000
|
||||
|
||||
.PHONY: baseline
|
||||
baseline: ## Build test baselines
|
||||
@bash ./misc/make_baseline.sh
|
||||
|
||||
.PHONY: clean-baseline
|
||||
clean-baseline: ## Remove test baselines
|
||||
rm -f test_files/*.*
|
||||
|
||||
## Code Checking
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(TARGET) $(AUXTARGETS)
|
||||
jshint --show-non-errors $(TARGET) $(AUXTARGETS)
|
||||
jshint --show-non-errors package.json
|
||||
jscs $(TARGET) $(AUXTARGETS)
|
||||
lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks
|
||||
@jshint --show-non-errors $(TARGET) $(AUXTARGETS)
|
||||
@jshint --show-non-errors package.json
|
||||
@jshint --show-non-errors --extract=always $(HTMLLINT)
|
||||
@jscs $(TARGET) $(AUXTARGETS)
|
||||
|
||||
.PHONY: flow
|
||||
flow: lint
|
||||
flow check --all --show-all-errors
|
||||
flow: lint ## Run flow checker
|
||||
@flow check --all --show-all-errors
|
||||
|
||||
.PHONY: baseline clean-baseline
|
||||
baseline:
|
||||
./misc/make_baseline.sh
|
||||
.PHONY: cov
|
||||
cov: misc/coverage.html ## Run coverage test
|
||||
|
||||
clean-baseline:
|
||||
rm -f test_files/*.*
|
||||
misc/coverage.html: $(TARGET) test.js
|
||||
mocha --require blanket -R html-cov -t 20000 > $@
|
||||
|
||||
.PHONY: coveralls
|
||||
coveralls: ## Coverage Test + Send to coveralls.io
|
||||
mocha --require blanket --reporter mocha-lcov-reporter -t 20000 | node ./node_modules/coveralls/bin/coveralls.js
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST) | bash misc/help.sh
|
||||
|
||||
#* To show a spinner, append "-spin" to any target e.g. cov-spin
|
||||
%-spin:
|
||||
@make $* & bash misc/spin.sh $$!
|
||||
|
37
README.md
37
README.md
@ -4,13 +4,21 @@ Pure JS implementation of van der Corput low-discrepancy sequences.
|
||||
|
||||
## Installation
|
||||
|
||||
Available on [npm vdc](http://npm.im/vdc):
|
||||
With [npm](http://npm.im/vdc):
|
||||
|
||||
```
|
||||
```bash
|
||||
$ npm install vdc
|
||||
```
|
||||
|
||||
## Usage
|
||||
In the browser:
|
||||
|
||||
```html
|
||||
<script src="vdc.js"></script>
|
||||
```
|
||||
|
||||
The browser exposes a variable `VDC`
|
||||
|
||||
## Usage
|
||||
|
||||
The exported function `VDC` accepts a `opts` object with the following fields:
|
||||
|
||||
@ -19,15 +27,15 @@ The exported function `VDC` accepts a `opts` object with the following fields:
|
||||
|
||||
Calling without arguments will default to the aforementioned values.
|
||||
|
||||
The object returned by `VDC` exposes a `next()` method to get the next element.
|
||||
The object returned by `VDC` exposes a `next()` method to get the next element.
|
||||
|
||||
The field `last` holds the most recently generated value (accessing the field
|
||||
does not trigger a recalculation)
|
||||
|
||||
## Sample Session
|
||||
For example:
|
||||
|
||||
```
|
||||
var VDC = require('vdc')
|
||||
```js
|
||||
//var VDC = require('vdc') // uncomment this line if in node
|
||||
|
||||
var opts = {'n':0, 'b':2};
|
||||
var generator = VDC(opts);
|
||||
@ -49,6 +57,21 @@ The expected output is
|
||||
0.5625 (9/16)
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
`make test` will run the nodejs-based test.
|
||||
|
||||
`make baseline` will generate the test baselines using Mathematica by explicitly
|
||||
extracting and reversing the digits. The implementation is based off a tutorial
|
||||
<http://reference.wolfram.com/mathematica/CUDALink/tutorial/Applications.html>
|
||||
|
||||
```mathematica
|
||||
VanDerCorput[base_][len_] := Table[
|
||||
With[{digits = Reverse@IntegerDigits[n, base]},
|
||||
Sum[2^(-ii)*digits[[ii]], {ii, Length[digits]}]
|
||||
], {n, len}]
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
`0` is the first value. Some sources (notably Wikipedia) start the sequence at
|
||||
|
231
index.html
Normal file
231
index.html
Normal file
@ -0,0 +1,231 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- vdc.js (C) 2013-present SheetJS http://sheetjs.com -->
|
||||
<!-- vim: set ts=2: -->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>VDC Live Demo</title>
|
||||
</head>
|
||||
<body>
|
||||
<b>VDC Live Demo</b><br />
|
||||
<a href="https://github.com/SheetJS/js-vdc">Source Code</a><br />
|
||||
<a href="https://github.com/SheetJS/js-vdc/issues">Issues? Something look weird? Click here and report an issue</a><br />
|
||||
<br />
|
||||
<div>
|
||||
Using the van der Corput sequences for bases 2,3 we can generate a sequence of
|
||||
quasirandom points in the unit square. The sequence is said to be
|
||||
<a href="https://en.wikipedia.org/wiki/Low-discrepancy_sequence">low-discrepancy</a>
|
||||
(basically the points are somewhat more uniformly spread across the square; you
|
||||
would expect a truly random sequence of points to have some concentrated lumps
|
||||
and small areas with no points).
|
||||
<br /><br />
|
||||
quasi-Monte Carlo methods generally have better error properties compared to the
|
||||
standard random and pseudo-random MC methods. As a demonstration, we will
|
||||
estimate π by sampling points in the unit square. The left side shows the
|
||||
VDC estimate using bases 2 (x) and 3 (y). The right side shows the random
|
||||
estimate by repeatedly calling Math.random.
|
||||
<br /><br />
|
||||
The graphs show the results of sampling many points and estimating PI. Below
|
||||
the graphs, the PI value shows the calculated estimate, "err %" shows the
|
||||
relative error (smaller is better) and "ln err" shows the natural log of the
|
||||
error (smaller is better).
|
||||
<br /><br />
|
||||
VDC sequences can be "seeded" by setting the starting index for the calculation.
|
||||
In this demo a random integer is chosen using Math.random.
|
||||
<br /><br />
|
||||
The values and graphs are calculated in your browser window. If the graphs do
|
||||
not appear or the values are not calculated, please report the issue!
|
||||
</div>
|
||||
<br />
|
||||
<div width=620>
|
||||
<div style="float:left">
|
||||
<b><center id="ltext">VDC (2,3) Sampling </center></b>
|
||||
<br />
|
||||
<canvas id="canvas1" width=300 height=300></canvas>
|
||||
<br />
|
||||
<b><center id="lout">Estimate of PI: </center></b>
|
||||
</div>
|
||||
<div style="float:right">
|
||||
<b><center id="rtext">Math.random Sampling </center></b>
|
||||
<br />
|
||||
<canvas id="canvas2" width=300 height=300></canvas>
|
||||
<br />
|
||||
<b><center id="rout">Estimate of PI: </center></b>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
<script src="http://d3js.org/d3.v2.js"></script>
|
||||
<script src="vdc.js"></script>
|
||||
<script src="https://cdn.rawgit.com/SheetJS/printj/master/printj.js"></script>
|
||||
<script>
|
||||
/*jshint browser:true */
|
||||
var PTS = 10000;
|
||||
var seed = (Math.random()*100000)|0;
|
||||
document.getElementById("ltext").innerHTML += PTS + " points; seed " + seed;
|
||||
document.getElementById("rtext").innerHTML += PTS + " points";
|
||||
var canvas1, canvas2;
|
||||
|
||||
// from http://bl.ocks.org/syntagmatic/3341641 (WTFPL)
|
||||
var renderQueue = (function(func) {
|
||||
var _queue = [], // data to be rendered
|
||||
_rate = 1000, // number of calls per frame
|
||||
_invalidate = function() {}, // invalidate last render queue
|
||||
_clear = function() {}; // clearing function
|
||||
|
||||
var rq = function(data) {
|
||||
if (data) rq.data(data);
|
||||
_invalidate();
|
||||
_clear();
|
||||
rq.render();
|
||||
};
|
||||
|
||||
rq.render = function() {
|
||||
var valid = true;
|
||||
_invalidate = rq.invalidate = function() {
|
||||
valid = false;
|
||||
};
|
||||
|
||||
function doFrame() {
|
||||
if (!valid) return true;
|
||||
var chunk = _queue.splice(0,_rate);
|
||||
chunk.map(func);
|
||||
timer_frame(doFrame);
|
||||
}
|
||||
|
||||
doFrame();
|
||||
};
|
||||
|
||||
rq.data = function(data) {
|
||||
_invalidate();
|
||||
_queue = data.slice(0); // creates a copy of the data
|
||||
return rq;
|
||||
};
|
||||
|
||||
rq.add = function(data) {
|
||||
_queue = _queue.concat(data);
|
||||
};
|
||||
|
||||
rq.rate = function(value) {
|
||||
if (!arguments.length) return _rate;
|
||||
_rate = value;
|
||||
return rq;
|
||||
};
|
||||
|
||||
rq.remaining = function() {
|
||||
return _queue.length;
|
||||
};
|
||||
|
||||
// clear the canvas
|
||||
rq.clear = function(func) {
|
||||
if (!arguments.length) {
|
||||
_clear();
|
||||
return rq;
|
||||
}
|
||||
_clear = func;
|
||||
return rq;
|
||||
};
|
||||
|
||||
rq.invalidate = _invalidate;
|
||||
|
||||
var timer_frame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { setTimeout(callback, 17); };
|
||||
|
||||
return rq;
|
||||
});
|
||||
|
||||
// ---
|
||||
var color = d3.scale.linear()
|
||||
.domain([0, 0.5, 1])
|
||||
.range(["#ef2212", "#e7c767", "#2799df"])
|
||||
.interpolate(d3.interpolateHcl);
|
||||
|
||||
var VDC2 = VDC({b:2,n:seed});
|
||||
var VDC3 = VDC({b:3,n:seed});
|
||||
var VDC5 = VDC({b:5,n:seed});
|
||||
|
||||
var in1 = 0, in2 = 0, out1 = 0, out2 = 0;
|
||||
|
||||
function update1() {
|
||||
var mypi = (in1 / (in1 + out1))*4, err = Math.abs(mypi - Math.PI)/Math.PI, lnerr = Math.log(err);
|
||||
document.getElementById("lout").innerHTML = PRINTJ.sprintf("PI = %f <br />err%% = %f<br />ln err = %f", mypi, err, lnerr);
|
||||
}
|
||||
function update2() {
|
||||
var mypi = (in2 / (in2 + out2))*4, err = Math.abs(mypi - Math.PI)/Math.PI, lnerr = Math.log(err);
|
||||
document.getElementById("rout").innerHTML = PRINTJ.sprintf("PI = %f <br />err%% = %f<br />ln err = %f", mypi, err, lnerr);
|
||||
}
|
||||
|
||||
function generate1(n) {
|
||||
return d3.range(n).map(function(i) {
|
||||
var x = VDC2.next(), y = VDC3.next();
|
||||
if(x*x + y*y <= 1) in1++; else out1++;
|
||||
if((in1 + out1) % 100 === 0) update1();
|
||||
return [ canvas1.width*x, canvas1.height*y, color(VDC5.next()) ];
|
||||
});
|
||||
}
|
||||
|
||||
function generate2(n) {
|
||||
return d3.range(n).map(function(i) {
|
||||
var x = Math.random(), y = Math.random();
|
||||
if(x*x + y*y <= 1) in2++; else out2++;
|
||||
if((in2 + out2) % 100 === 0) update2();
|
||||
return [ canvas2.width*x, canvas2.height*y, color(Math.random()) ];
|
||||
});
|
||||
}
|
||||
|
||||
function make_dot(ctx) {
|
||||
return function(pos) {
|
||||
ctx.fillStyle = pos[2];
|
||||
ctx.beginPath();
|
||||
ctx.fillRect(pos[0]-1,pos[1]-1,2,2);
|
||||
ctx.stroke();
|
||||
ctx.fill();
|
||||
};
|
||||
}
|
||||
|
||||
function make_clear_canvas(ctx, canvas) {
|
||||
return function() { ctx.clearRect(0,0,canvas.width,canvas.height); make_boundary(canvas, ctx); };
|
||||
}
|
||||
|
||||
function make_boundary(canvas, ctx) {
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, canvas.height, canvas.width, 0, 2*Math.PI);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
canvas1 = document.getElementById("canvas1");
|
||||
var ctx1 = canvas1.getContext("2d");
|
||||
ctx1.globalCompositeOperation = "destination-over";
|
||||
|
||||
canvas2 = document.getElementById("canvas2");
|
||||
var ctx2 = canvas2.getContext("2d");
|
||||
ctx2.globalCompositeOperation = "destination-over";
|
||||
|
||||
make_boundary(canvas1, ctx1);
|
||||
make_boundary(canvas2, ctx2);
|
||||
|
||||
var dot1 = make_dot(ctx1);
|
||||
var dot2 = make_dot(ctx2);
|
||||
|
||||
var clear_canvas1 = make_clear_canvas(ctx1, canvas1);
|
||||
var clear_canvas2 = make_clear_canvas(ctx2, canvas2);
|
||||
|
||||
|
||||
var render1 = renderQueue(dot1).clear(clear_canvas1);
|
||||
var render2 = renderQueue(dot2).clear(clear_canvas2);
|
||||
|
||||
render1(generate1(PTS));
|
||||
render2(generate2(PTS));
|
||||
};
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-36810333-1']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
</script>
|
||||
</html>
|
42
misc/help.sh
Executable file
42
misc/help.sh
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
# make_help.sh -- process listing of targets and special items in Makefile
|
||||
# Copyright (C) 2016-present SheetJS
|
||||
#
|
||||
# usage in makefile: pipe the output of the following command:
|
||||
# @grep -hE '(^[a-zA-Z_-][ a-zA-Z_-]*:.*?|^#[#*])' $(MAKEFILE_LIST)
|
||||
#
|
||||
# lines starting with "## " are treated as subtitles
|
||||
# lines starting with "#* " are treated as plaintext comments
|
||||
# multiple targets with "## " after the ":" are rendered as separate targets
|
||||
# if the presumed default target is labeled, it will be assigned a unique color
|
||||
|
||||
awk '
|
||||
BEGIN{recipes=0;}
|
||||
!/#[#*] .*$/ {next;}
|
||||
{multi=0; isrecipe=0;}
|
||||
/^[^#]*:/ {isrecipe=1; ++recipes;}
|
||||
/^[^ :]* .*:/ {multi=1}
|
||||
multi==0 && isrecipe>0 { if(recipes > 1) print; else print $0, "[default]"; next}
|
||||
isrecipe == 0 {print; next}
|
||||
multi>0 {
|
||||
k=split($0, msg, "##"); m=split($0, a, ":"); n=split(a[1], b, " ");
|
||||
for(i=1; i<=n; ++i) print b[i] ":", "##" msg[2], (recipes==1 && i==1 ? "[default]" : "")
|
||||
}
|
||||
END {}
|
||||
' | if [[ -t 1 ]]; then
|
||||
awk '
|
||||
BEGIN {FS = ":.*?## "}
|
||||
{color=36}
|
||||
/\[default\]/ {color=35}
|
||||
NF==1 && /^##/ {color=34}
|
||||
NF==1 && /^#\*/ {color=20; $1 = substr($1, 4)}
|
||||
{printf "\033[" color "m%-20s\033[0m %s\n", $1, $2;}
|
||||
END{}' -
|
||||
else
|
||||
awk '
|
||||
BEGIN {FS = ":.*?## "}
|
||||
/^#\* / {$1 = substr($1, 4)}
|
||||
{printf "%-20s %s\n", $1, $2;}
|
||||
END{}' -
|
||||
fi
|
||||
|
14
misc/spin.sh
Executable file
14
misc/spin.sh
Executable file
@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# spin.sh -- show a spinner (for coverage test)
|
||||
# Copyright (C) 2014-present SheetJS
|
||||
|
||||
wpid=$1
|
||||
delay=1
|
||||
str="|/-\\"
|
||||
while [ $(ps -a|awk '$1=='$wpid' {print $1}') ]; do
|
||||
t=${str#?}
|
||||
printf " [%c]" "$str"
|
||||
str=$t${str%"$t"}
|
||||
sleep $delay
|
||||
printf "\b\b\b\b"
|
||||
done
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vdc",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.1",
|
||||
"author": "SheetJS",
|
||||
"description": "van der Corput low-discrepancy sequences",
|
||||
"keywords": [ "math", "random", "qrng", "lds" ],
|
||||
@ -19,6 +19,11 @@
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"config": {
|
||||
"blanket": {
|
||||
"pattern": "vdc.js"
|
||||
}
|
||||
},
|
||||
"bugs": { "url": "https://github.com/SheetJS/js-vdc/issues" },
|
||||
"license": "Apache-2.0",
|
||||
"engines": { "node": ">=0.8" }
|
||||
|
Loading…
Reference in New Issue
Block a user