aboutsummaryrefslogtreecommitdiffstats
path: root/web/nms.gathering.org/speedometer/d3-master/test/math
diff options
context:
space:
mode:
authorKristian Lyngstol <kristian@bohemians.org>2015-04-02 19:24:45 +0200
committerKristian Lyngstol <kristian@bohemians.org>2015-04-02 19:24:45 +0200
commit0d8bba263dc195147d6fdb09662e7926f0a58b3e (patch)
tree4c570b4376c323e585120e7695b8715be7aa8881 /web/nms.gathering.org/speedometer/d3-master/test/math
parente4354b47bd8891c5b1ee591fdf74b3ca67eee461 (diff)
Bump lots of changes
Diffstat (limited to 'web/nms.gathering.org/speedometer/d3-master/test/math')
-rw-r--r--web/nms.gathering.org/speedometer/d3-master/test/math/random-test.js132
-rw-r--r--web/nms.gathering.org/speedometer/d3-master/test/math/transform-null-matrix-test.html26
-rw-r--r--web/nms.gathering.org/speedometer/d3-master/test/math/transform-null-test.html26
-rw-r--r--web/nms.gathering.org/speedometer/d3-master/test/math/transform-rotate-origin-test.html40
-rw-r--r--web/nms.gathering.org/speedometer/d3-master/test/math/transform-rotate-test.html138
-rw-r--r--web/nms.gathering.org/speedometer/d3-master/test/math/transform-test.html88
6 files changed, 450 insertions, 0 deletions
diff --git a/web/nms.gathering.org/speedometer/d3-master/test/math/random-test.js b/web/nms.gathering.org/speedometer/d3-master/test/math/random-test.js
new file mode 100644
index 0000000..1e00ec9
--- /dev/null
+++ b/web/nms.gathering.org/speedometer/d3-master/test/math/random-test.js
@@ -0,0 +1,132 @@
+var vows = require("vows"),
+ load = require("../load"),
+ assert = require("../assert"),
+ seedrandom = require("seedrandom");
+
+var suite = vows.describe("d3.random");
+
+var _random;
+
+// Testing a random number generator is a bit more complicated than testing
+// deterministic code, so we use different techniques.
+//
+// If the RNG is correct, each test in this suite will pass with probability
+// at least P. The tests have been designed so that P ≥ 98%. Specific values
+// of P are given above each case. We use the seedrandom module to get around
+// this non-deterministic aspect -- so it is safe to assume that if the tests
+// fail, then d3's RNG is broken.
+//
+// See also: http://www.johndcook.com/Beautiful_Testing_ch10.pdf
+
+suite.addBatch({
+ "random": {
+ topic: load("math/random").sandbox({Math: Math}).expression("d3.random"),
+ "(using seedrandom)": {
+ topic: function(random) {
+ _random = Math.random;
+ Math.seedrandom("a random seed.");
+ return random;
+ },
+ "normal": {
+ "topic": function(random) { return random.normal(-43289, 38.8); },
+ "has normal distribution": KSTest(normalCDF(-43289, 38.8))
+ },
+ "logNormal": {
+ "topic": function(random) { return random.logNormal(10, 2.5); },
+ "has log-normal distribution": KSTest(logNormalCDF(10, 2.5))
+ },
+ "irwinHall": {
+ "topic": function(random) { return random.irwinHall(10); },
+ "has Irwin-Hall distribution": KSTest(irwinHallCDF(10))
+ },
+ teardown: function() {
+ Math.random = _random;
+ }
+ }
+ }
+});
+
+/**
+ * A macro that that takes a RNG and performs a Kolmogorov-Smirnov test:
+ * asserts that the values generated by the RNG could be generated by the
+ * distribution with cumulative distribution function `cdf'. Each test runs in
+ * O(n log n) * O(cdf).
+ *
+ * Passes with P≈98%.
+ *
+ * @param cdf function(x) { returns CDF of the distribution evaluated at x }
+ * @param n number of sample points. Higher n = better evaluation, slower test.
+ * @return a function that asserts the rng produces values fitting the distribution
+ */
+function KSTest(cdf, n) {
+ return function(rng) {
+ var n = 1000;
+ var values = [];
+ for (var i = 0; i < n; i++) {
+ values.push(rng());
+ }
+ values.sort(function(a, b) { return a - b; });
+
+ K_positive = -Infinity; // Identity of max() function
+ for (var i = 0; i < n; i++) {
+ var edf_i = i / n; // Empirical distribution function evaluated at x=values[i]
+ K_positive = Math.max(K_positive, edf_i - cdf(values[i]));
+ }
+ K_positive *= Math.sqrt(n);
+
+ // Derivation of this interval is difficult.
+ // @see K-S test in Knuth's AoCP vol.2
+ assert.inDelta(K_positive, 0.723255, 0.794145);
+ };
+}
+
+// Logistic approximation to normal CDF around N(mean, stddev).
+function normalCDF(mean, stddev) {
+ return function(x) {
+ return 1 / (1 + Math.exp(-0.07056 * Math.pow((x-mean)/stddev, 3) - 1.5976 * (x-mean)/stddev));
+ };
+}
+
+// See http://en.wikipedia.org/wiki/Log-normal_distribution#Similar_distributions
+function logNormalCDF(mean, stddev) {
+ var exponent = Math.PI / (stddev * Math.sqrt(3));
+ var numerator = Math.exp(mean);
+ return function(x) {
+ return 1 / (Math.pow(numerator / x, exponent) + 1);
+ };
+}
+
+function irwinHallCDF(n) {
+ var normalisingFactor = factorial(n);
+
+ // Precompute binom(n, k), k=0..n for efficiency. (this array gets stored
+ // inside the closure, so it is only computed once)
+ var binoms = [];
+ for (var k = 0; k <= n; k++) {
+ binoms.push(binom(n, k));
+ }
+
+ // See CDF at http://en.wikipedia.org/wiki/Irwin–Hall_distribution
+ return function(x) {
+ var t = 0;
+ for (var k = 0; k < x; k++) {
+ t += Math.pow(-1, k % 2) * binoms[k] * Math.pow(x - k, n);
+ }
+ return t / normalisingFactor;
+ };
+}
+
+function factorial(n) {
+ var t = 1;
+ for (var i = 2; i <= n; i++) {
+ t *= i;
+ }
+ return t;
+}
+
+function binom(n, k) {
+ if (k < 0 || k > n) return undefined; // only defined for 0 <= k <= n
+ return factorial(n) / (factorial(k) * factorial(n - k));
+}
+
+suite.export(module);
diff --git a/web/nms.gathering.org/speedometer/d3-master/test/math/transform-null-matrix-test.html b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-null-matrix-test.html
new file mode 100644
index 0000000..7a5eec3
--- /dev/null
+++ b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-null-matrix-test.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<body>
+<script src="../../d3.js"></script>
+<script>
+
+var svg = d3.select("body").append("svg")
+ .attr("width", 960)
+ .attr("height", 500);
+
+var g = svg.append("g")
+ .attr("transform", "translate(100,100)")
+ .append("g")
+ .attr("transform", "matrix(1 0 0 1 0 0)rotate(0)");
+
+var rect = g.append("rect")
+ .attr("x", -25)
+ .attr("y", -50)
+ .attr("width", 50)
+ .attr("height", 100);
+
+g.transition()
+ .duration(3000)
+ .attrTween("transform", d3.tween("matrix(1 0 0 1 100 100)rotate(360)", d3.interpolateString));
+
+</script>
diff --git a/web/nms.gathering.org/speedometer/d3-master/test/math/transform-null-test.html b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-null-test.html
new file mode 100644
index 0000000..6211680
--- /dev/null
+++ b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-null-test.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<body>
+<script src="../../d3.js"></script>
+<script>
+
+var svg = d3.select("body").append("svg")
+ .attr("width", 960)
+ .attr("height", 500);
+
+var g = svg.append("g")
+ .attr("transform", "translate(100,100)")
+ .append("g")
+ .attr("transform", "translate(0,0)rotate(0)");
+
+var rect = g.append("rect")
+ .attr("x", -25)
+ .attr("y", -50)
+ .attr("width", 50)
+ .attr("height", 100);
+
+g.transition()
+ .duration(3000)
+ .attrTween("transform", d3.tween("translate(100,100)rotate(360)", d3.interpolateString));
+
+</script>
diff --git a/web/nms.gathering.org/speedometer/d3-master/test/math/transform-rotate-origin-test.html b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-rotate-origin-test.html
new file mode 100644
index 0000000..5a006f5
--- /dev/null
+++ b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-rotate-origin-test.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<body>
+<script src="../../d3.js"></script>
+<script>
+
+var width = 960,
+ height = 500;
+
+var cross = d3.svg.symbol()
+ .type("cross")
+ .size(10000);
+
+var svg = d3.select("body").append("svg")
+ .attr("width", width)
+ .attr("height", height)
+ .append("g")
+ .attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")");
+
+svg.append("path")
+ .style("fill", "steelblue")
+ .attr("d", cross);
+
+svg.append("path")
+ .style("fill", "darkgreen")
+ .attr("d", cross)
+ .attr("transform", "rotate(45 200,200)");
+
+svg.append("path")
+ .style("fill", "white")
+ .style("fill-opacity", .2)
+ .style("stroke", "steelblue")
+ .style("stroke-width", "4px")
+ .attr("d", cross)
+ .transition()
+ .duration(1000)
+ .style("stroke", "darkgreen")
+ .attr("transform", "rotate(45 200,200)");
+
+</script>
diff --git a/web/nms.gathering.org/speedometer/d3-master/test/math/transform-rotate-test.html b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-rotate-test.html
new file mode 100644
index 0000000..49fb571
--- /dev/null
+++ b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-rotate-test.html
@@ -0,0 +1,138 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+
+table {
+ width: 960px;
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+
+th, td {
+ padding: 4px;
+}
+
+th {
+ text-align: left;
+}
+
+td {
+ border: solid 1px #ccc;
+ text-align: right;
+}
+
+td.fail {
+ background: lightcoral;
+}
+
+td.success {
+ background: lightgreen;
+}
+
+</style>
+<table>
+ <thead>
+ <th>start</th>
+ <th>end</th>
+ <th colspan=5>actual intermediate values</th>
+ <th>exp.</th>
+ <th>act.</th>
+ </thead>
+ <tbody>
+ </tbody>
+</table>
+<script src="../../d3.js"></script>
+<script>
+
+var format = d3.format(",.2f");
+
+var tests = [
+ {start: 170, end: 225, expected: [ 170.00, -176.25, -162.50, -148.75, -135.00]},
+ {start: 225, end: 170, expected: [-135.00, -148.75, -162.50, -176.25, 170.00]},
+ {start: -170, end: -225, expected: [-170.00, 176.25, 162.50, 148.75, 135.00]},
+ {start: -225, end: -170, expected: [ 135.00, 148.75, 162.50, 176.25, -170.00]},
+ {start: -170, end: 170, expected: [-170.00, -175.00, 180.00, 175.00, 170.00]},
+ {start: -170, end: 0, expected: [-170.00, -127.50, -85.00, -42.50, 0.00]},
+ {start: 170, end: 0, expected: [ 170.00, 127.50, 85.00, 42.50, 0.00]},
+ {start: -180, end: 90, expected: [ 180.00, 157.50, 135.00, 112.50, 90.00]},
+ {start: 180, end: 90, expected: [ 180.00, 157.50, 135.00, 112.50, 90.00]},
+ {start: -180, end: -90, expected: [-180.00, -157.50, -135.00, -112.50, -90.00]},
+ {start: 180, end: -90, expected: [ 180.00, -157.50, -135.00, -112.50, -90.00]},
+ {start: 780, end: -90, expected: [ 60.00, 22.50, -15.00, -52.50, -90.00]}
+];
+
+var tr = d3.select("tbody").selectAll("tr")
+ .data(tests)
+ .enter().append("tr");
+
+tr.append("td")
+ .text(function(d) { return format(d.start); });
+
+tr.append("td")
+ .text(function(d) { return format(d.end); });
+
+tr.selectAll(".actual")
+ .data(function(d) {
+ var interpolate = d3.interpolateTransform("rotate(" + d.start + ")", "rotate(" + d.end + ")");
+ return d.expected.map(function(expected, i) {
+ return {
+ expected: expected,
+ actual: d3.transform(interpolate(i / 4)).rotate
+ };
+ });
+ })
+ .enter().append("td")
+ .text(function(d, i) { return format(d.actual); })
+ .attr("class", function(d) { return Math.abs(d.actual - d.expected) < .01 ? "success" : "fail"; });
+
+var ga = tr.append("td").attr("width", 40).append("svg")
+ .attr("width", 40)
+ .attr("height", 20)
+ .append("g")
+ .attr("transform", "translate(20,10)")
+ .append("g")
+ .each(animateExpected);
+
+ga.append("path")
+ .attr("d", d3.svg.symbol().type("cross").size(120));
+
+ga.append("circle")
+ .attr("cx", 8)
+ .attr("r", 4);
+
+var gb = tr.append("td").attr("width", 40).append("svg")
+ .attr("width", 40)
+ .attr("height", 20)
+ .append("g")
+ .attr("transform", "translate(20,10)")
+ .append("g")
+ .each(animateActual);
+
+gb.append("path")
+ .attr("d", d3.svg.symbol().type("cross").size(120));
+
+gb.append("circle")
+ .attr("cx", 8)
+ .attr("r", 4);
+
+function animateExpected(d) {
+ d3.select(this).transition()
+ .duration(2500)
+ .attrTween("transform", function(d) {
+ var a = d.start % 360, b = d.end % 360;
+ if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
+ return d3.interpolateString("rotate(" + a + ")", "rotate(" + b + ")");
+ })
+ .each("end", animateExpected);
+}
+
+function animateActual(d) {
+ d3.select(this)
+ .attr("transform", "rotate(" + d.start + ")")
+ .transition()
+ .duration(2500)
+ .attr("transform", "rotate(" + d.end + ")")
+ .each("end", animateActual);
+}
+
+</script>
diff --git a/web/nms.gathering.org/speedometer/d3-master/test/math/transform-test.html b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-test.html
new file mode 100644
index 0000000..7e313d7
--- /dev/null
+++ b/web/nms.gathering.org/speedometer/d3-master/test/math/transform-test.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Transform Test</title>
+<style>
+
+th,
+td {
+ border: solid #ccc 1px;
+}
+
+</style>
+<body>
+<script src="../../d3.js"></script>
+<script>
+
+var outcome = d3.select("body").append("p");
+
+var g = d3.select("body").append("svg")
+ .attr("width", 10)
+ .attr("height", 10)
+ .append("g");
+
+var results = d3.select("body").append("table")
+ .style("display", "none");
+
+results.append("tr").selectAll("th")
+ .data(["Expected", "Actual", "Expected matrix", "Actual matrix"])
+ .enter().append("th")
+ .text(function(d) { return d; });
+
+var el = g[0][0],
+ v,
+ m,
+ a,
+ b,
+ failures = 0;
+
+for (var tx = -10; tx <= 10; tx += 5) {
+ for (var ty = -10; ty <= 10; ty += 5) {
+ for (var r = -180; r <= 180; r += 15) {
+ for (var skx = -45; skx <= 45; skx += 45) {
+ for (var sx = -2; sx <= 2; sx++) {
+ for (var sy = -2; sy <= 2; sy++) {
+ v = "translate(" + tx + "," + ty + ")rotate(" + r + ")skewX(" + skx + ")scale(" + sx + "," + sy + ")";
+ g.attr("transform", v);
+ a = matrix(el);
+ g.attr("transform", d3.transform(v));
+ b = matrix(el);
+ if (!deepEqual(a, b, 1e-6)) {
+ failures++;
+ results
+ .style("display", null)
+ .append("tr").selectAll("td")
+ .data([v, d3.transform(v), a, b])
+ .enter().append("td")
+ .text(function(d) { return d; });
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+outcome.text(failures ? failures + " failures" : "Success!");
+
+function matrix(el) {
+ var t = el.transform.baseVal.consolidate();
+ if (t) {
+ var m = t.matrix;
+ return [m.a, m.b, m.c, m.d, m.e, m.f];
+ }
+ return null;
+}
+
+function deepEqual(actual, expected, epsilon) {
+ epsilon = epsilon || 0;
+ if (actual === expected) return true;
+ if (actual == null || expected == null) return false;
+ if (actual.length !== expected.length) return false;
+
+ for (var i = 0; i < actual.length; i++) {
+ if (Math.abs(actual[i] - expected[i]) > epsilon) return false;
+ }
+ return true;
+}
+
+</script>