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