Merge branch 'master' into es6
This commit is contained in:
commit
e6a1f1fafa
13 changed files with 1567 additions and 1156 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1,4 +1,6 @@
|
|||
.DS_Store
|
||||
.vscode
|
||||
node_modules
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
tests/coverage
|
||||
|
|
16
.travis.yml
16
.travis.yml
|
@ -5,12 +5,13 @@ env:
|
|||
node_js:
|
||||
- "7"
|
||||
addons:
|
||||
firefox: latest
|
||||
- firefox: latest
|
||||
before_script:
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
before_deploy:
|
||||
- mkdir -p deploy
|
||||
- ./build.py -l lib -d deploy
|
||||
script:
|
||||
- yarn run build
|
||||
after_success:
|
||||
- yarn run docs
|
||||
notifications:
|
||||
slack:
|
||||
secure: Kwe1KBh4SMzgXaj6GQg3ZmopRYcDR3Vnd4C/gyiEOJsXzKRlU5dA7WwM/mbyOe9+ZvWDyp+g2CoQYYyvLR0SHEy1m0gn6M8fBzgSZQlWxOxAJxkwVsyxUNwAy2FylMpS+ugpw/fBMSbnSFqfZSa/tGB3KhBc0yA7V9wVS0hnwBfICqKKlFdLPcp+Us4zpXRUmcL1e0BVwm2klJi0CoKlOmTa4lI3tUa/YiuuMpgk89/PioMEr6/PP+5OfWV624djw2gznoualvcwdfZniC/oxkdTUbcu4nbTf+bFk5uwwW+XBpUhm9rMUoftngYCrWdtYHS6qenyzmflO5bgCDg5W8onv3qgMcDTEHDjlO8JMoEQLC2o27Hsyukrh2Iu0Hn2k4S10ZIDWLUZXf8ERKdU7v8o5xaiCrP7NO8fJlyGbWwYxwpFi9dpacb8qWuWw53k8+ld9orl2Zu5t1Y1QJCvT0DP0iGYSxbbICfex7im0fgh3A+MHTfhxxiGQtFJRUxqO5wGCIsT4dJJkYwRJ1HoCPyLT1x1WT8iy4lr8ivRhanEwQ5g2OmuRKz522yCrm2DPaRR/LDhqK9xghJqqh4RNx9Be5xNaxSxKs4Hcya4ZXrGaU9tzGTehRkNQksKUHq9PpdY85Mbk84wEq7zKLhtLPTn17DQePFm2DbdX4392o4=
|
||||
|
@ -23,9 +24,10 @@ deploy:
|
|||
on:
|
||||
tags: true
|
||||
- provider: pages
|
||||
github_token:
|
||||
secure: HszUovTqcRxuXTmH3/rStEe1ZeZbrZweQah8Bq0POs89P3/GjyEat11WbH9S7tfIT1yVcF736TmsDNRtl34Rmr71P7rczwFlX1yJOIamH4jT9vG8ocpZH4Orc6XA2s7UclD1HwJwStM1k2J4CV34eTTlX36ngjYrp09HertXAQWSK6TZk9RK6ql2HlNzchImz2EY1aQnfqkrFByOtM4o/SJJryJJBJUMD69gWrYu6cv51w/jMEoUtzvV6Nr2o9YOuo97B0scJmbxgfx67FaCQwEOxKtr8xT5nttJ2q6EeaAiErAieG8/o8yRsJRFrHyVm42v9PEfoe8O8Y4g/1VrtbjY3vH8LPpCotMxhshjUCBaLDc8TCC/osik6dxhv/fqjbdPwrGRW2qzsmXIZug7+YCEW+qUFRPwwX+Cr0ENnaPFMSDFxANeLF7KfF7oaVnr8JTlZnu9G+Uliqe6RNCoWfQtpTRM759cDLQp4b5eBQF2G61x2XOdRqcNZepRaRVnsaCo0lNPW9o5HCQnJnMbEB9Gdowt18PwgVucIdIPJeAPodMs40s7sUOP5Xik58b4YBG9lsgLBcfCgTy+n8JPS2LJsclG82pBACtSV+ucc6rVeD+5fbSUxn4ItaK4e0MonCv4Jnp7zGn6hErcpexBmXSdYQSrdsemKDTGHibOF6U=
|
||||
local_dir: deploy
|
||||
keep-history: true
|
||||
skip_cleanup: true
|
||||
github_token:
|
||||
secure: PvCrB9ckDfWedl1rdo/3mUvCy/Vg4ksZR2mj4KT3AdEyukbpMiVVDkocMFohuIq+mnRdeyhpvM2KluLHhQrEhWjvqVobiZ9/c0gWWxZHV8doDdqNUPm693MpGojMOxHT4qRih6x9KyjanmWAwy/Bc972dpD5vtaTx1gKOzRUjUI=
|
||||
on:
|
||||
branch: master
|
||||
local_dir: docs/
|
||||
|
|
31
Gruntfile.js
31
Gruntfile.js
|
@ -1,31 +0,0 @@
|
|||
module.exports = function (grunt) {
|
||||
let pkg = grunt.file.readJSON('package.json')
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: pkg,
|
||||
|
||||
karma: {
|
||||
unit: {
|
||||
configFile: 'karma.conf.js'
|
||||
}
|
||||
},
|
||||
coveralls: {
|
||||
options: {
|
||||
coverageDir: 'tests/coverage/',
|
||||
force: true
|
||||
}
|
||||
},
|
||||
standard: {
|
||||
options: pkg.standard,
|
||||
lib: {
|
||||
src: ['lib/**/*.js']
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
grunt.loadNpmTasks('grunt-karma')
|
||||
grunt.loadNpmTasks('grunt-karma-coveralls')
|
||||
grunt.loadNpmTasks('grunt-standard')
|
||||
|
||||
grunt.registerTask('test', ['standard', 'karma', 'coveralls'])
|
||||
}
|
55
README.md
55
README.md
|
@ -18,19 +18,24 @@ Octo.js bundles core functions and generic boilerplate code commonly used in mos
|
|||
|
||||
Octo's future aims to be a stable, well-tested and well-documented standard library for fuzzing in a JavaScript environment.
|
||||
|
||||
## Note
|
||||
The ES6 branch is under active development while we are incorporating it with our existing fuzzers.
|
||||
## Table of Contents
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [Playbook](#playbook)
|
||||
- [Usage in Node](#usage-in-node)
|
||||
- [Usage in Browser](#usage-in-browser)
|
||||
- [Develop](#develop)
|
||||
- [Testing](#testing)
|
||||
- [API Documentation](#api-documentation)
|
||||
|
||||
|
||||
## Playbook
|
||||
### Playbook
|
||||
|
||||
https://runkit.com/posidron/octo-js-playbook
|
||||
|
||||
|
||||
## Node
|
||||
### Usage in Node
|
||||
|
||||
```
|
||||
npm i @mozillasecurity/octo
|
||||
yarn add @mozillasecurity/octo
|
||||
```
|
||||
|
||||
```
|
||||
|
@ -38,33 +43,35 @@ const {random} = require('@mozillasecurity/octo')
|
|||
random.init()
|
||||
```
|
||||
|
||||
|
||||
## Browser
|
||||
|
||||
We have not yet merged ES6 to master, hence the browser version which was released on master is not up-to-date.
|
||||
Use the `dist/octo.js` version of this branch by running the following command.
|
||||
### Usage in Browser
|
||||
|
||||
```
|
||||
npm run build
|
||||
yarn build
|
||||
```
|
||||
|
||||
|
||||
## Development
|
||||
### Develop
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build
|
||||
npm run watch
|
||||
npm run test:lint
|
||||
yarn install
|
||||
yarn lint
|
||||
yarn test
|
||||
yarn build
|
||||
```
|
||||
|
||||
## Testing
|
||||
### Testing
|
||||
|
||||
Tests live in the `tests/` subdirectory, and are written for [QUnit](https://qunitjs.com/).
|
||||
To run tests locally, open `tests/index.html` in a browser.
|
||||
The automated tests are run in Firefox or Chrome using [Karma](https://karma-runner.github.io/).
|
||||
To run the automated tests:
|
||||
Octo.js uses Jest for testing. Each directory should contain a `__tests__` folder containing the tests.
|
||||
|
||||
```bash
|
||||
npm test
|
||||
yarn test
|
||||
```
|
||||
|
||||
### API Documentation
|
||||
|
||||
* https://
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
yarn docs
|
||||
```
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
module.exports = function (config) {
|
||||
let configuration = {
|
||||
basePath: './tests',
|
||||
|
||||
frameworks: ['qunit'],
|
||||
|
||||
files: [
|
||||
'../lib/utils/init.js',
|
||||
'../lib/utils/*.js',
|
||||
'../lib/logging/*.js',
|
||||
'../lib/make/init.js',
|
||||
'../lib/make/*.js',
|
||||
'../lib/random/*.js',
|
||||
'**/*.js'
|
||||
],
|
||||
|
||||
exclude: [
|
||||
],
|
||||
|
||||
preprocessors: {
|
||||
'../lib/**/*.js': ['coverage']
|
||||
},
|
||||
|
||||
reporters: ['progress', 'coverage'],
|
||||
|
||||
port: 9876,
|
||||
|
||||
colors: true,
|
||||
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
autoWatch: true,
|
||||
|
||||
browsers: ['Chrome', 'Firefox'],
|
||||
|
||||
singleRun: true,
|
||||
|
||||
browserNoActivityTimeout: 30000,
|
||||
|
||||
customLaunchers: {
|
||||
Chrome_travis_ci: {
|
||||
base: 'Chrome',
|
||||
flags: ['--no-sandbox']
|
||||
}
|
||||
},
|
||||
|
||||
coverageReporter: {
|
||||
reporters: [
|
||||
{ type: 'lcov', dir: 'coverage/' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.TRAVIS) {
|
||||
configuration.browsers = ['Chrome_travis_ci', 'Firefox']
|
||||
}
|
||||
|
||||
config.set(configuration)
|
||||
}
|
92
lib/random/__tests__/mersennetwister.test.js
Normal file
92
lib/random/__tests__/mersennetwister.test.js
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* eslint-env jest */
|
||||
const MersenneTwister = require('../mersennetwister')
|
||||
|
||||
describe('MersenneTwister', () => {
|
||||
test('uniform distribution', () => {
|
||||
const N = Math.pow(2, 18)
|
||||
const TRIES = 10
|
||||
const XSQ = 293.25 // quantile of chi-square dist. k=255, p=.05
|
||||
|
||||
let mt = new MersenneTwister()
|
||||
mt.seed(Math.random() * 0x100000000)
|
||||
|
||||
const _test = () => {
|
||||
let tries = []
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let data = new Uint32Array(N)
|
||||
let sh
|
||||
for (let i = 0; i < data.length; ++i) {
|
||||
data[i] = mt.int32()
|
||||
}
|
||||
for (sh = 0; sh <= 24; ++sh) {
|
||||
let bins = new Uint32Array(256)
|
||||
for (let b of data) {
|
||||
++bins[(b >>> sh) & 0xff]
|
||||
}
|
||||
let xsq = bins.reduce((a, v) => {
|
||||
let e = N / bins.length
|
||||
return a + Math.pow(v - e, 2) / e
|
||||
}, 0)
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 255)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
|
||||
return true
|
||||
}
|
||||
tries.push(xsq)
|
||||
}
|
||||
if (sh === 25) {
|
||||
return
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
expect(_test()).toBe(true)
|
||||
})
|
||||
|
||||
test('float distribution', () => {
|
||||
const N = Math.pow(2, 18)
|
||||
const TRIES = 3
|
||||
const XSQ = 564.7 // quantile of chi-square dist. k=511, p=.05
|
||||
|
||||
let mt = new MersenneTwister()
|
||||
mt.seed(Math.random() * 0x100000000)
|
||||
|
||||
const _test = () => {
|
||||
let tries = []
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(512)
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = (mt.real2() * bins.length) >>> 0
|
||||
if (tmp >= bins.length) {
|
||||
throw new Error('random.float() >= 1.0')
|
||||
}
|
||||
++bins[tmp]
|
||||
}
|
||||
let xsq = bins.reduce((a, v) => {
|
||||
let e = N / bins.length
|
||||
return a + Math.pow(v - e, 2) / e
|
||||
}, 0)
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 511)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
console.log(`Expected x^2 to be < ${XSQ}, got ${xsq} on attempt #${attempt + 1}`)
|
||||
return true
|
||||
}
|
||||
tries.push(xsq)
|
||||
}
|
||||
// assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": " + tries)
|
||||
return false
|
||||
}
|
||||
expect(_test()).toBe(true)
|
||||
})
|
||||
})
|
1374
lib/random/__tests__/random.test.js
Normal file
1374
lib/random/__tests__/random.test.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const MersenneTwister = require('./mersennetwister')
|
||||
const {logger} = require('../logging')
|
||||
const logger = require('../logging')
|
||||
|
||||
class random {
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
const random = require('../random')
|
||||
const utils = require('../utils')
|
||||
const {logger} = require('../logging')
|
||||
const logger = require('../logging')
|
||||
|
||||
var o = null // eslint-disable-line no-unused-vars
|
||||
|
||||
|
|
67
package.json
67
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@mozillasecurity/octo",
|
||||
"version": "1.0.14",
|
||||
"description": "",
|
||||
"version": "1.0.15",
|
||||
"description": "A unified shared library which aids in building fuzzers for browsers or as complement for an existing fuzzing framework.",
|
||||
"keywords": [
|
||||
"fuzzing",
|
||||
"browser",
|
||||
|
@ -9,7 +9,7 @@
|
|||
"node",
|
||||
"library"
|
||||
],
|
||||
"homepage": "https://github.com/mozillasecurity/octo/tree/es6",
|
||||
"homepage": "https://github.com/mozillasecurity/octo",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mozillasecurity/octo.git"
|
||||
|
@ -21,18 +21,20 @@
|
|||
"author": "Christoph Diehl <cdiehl@mozilla.com>",
|
||||
"license": "MPL-2.0",
|
||||
"scripts": {
|
||||
"test": "grunt test --verbose",
|
||||
"test:lint": "cross-env NODE_ENV=test standard --verbose",
|
||||
"test:lint:fix": "cross-env NODE_ENV=test standard --fix --verbose",
|
||||
"test": "jest --silent",
|
||||
"coverage": "cross-env NODE_ENV=test jest --silent --coverage --collectCoverageFrom=lib/**/*.js",
|
||||
"coveralls": "yarn coverage && cat ./coverage/lcov.info | coveralls",
|
||||
"lint": "cross-env NODE_ENV=test standard --verbose",
|
||||
"lint:fix": "cross-env NODE_ENV=test standard --fix --verbose",
|
||||
"docs": "esdoc",
|
||||
"build": "webpack -p",
|
||||
"watch": "webpack --watch",
|
||||
"precommit": "npm run test:lint",
|
||||
"postinstall": "npm run build",
|
||||
"precommit": "yarn lint",
|
||||
"postinstall": "yarn build",
|
||||
"release": "np"
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"tests/**",
|
||||
"dist/"
|
||||
],
|
||||
"envs": {
|
||||
|
@ -41,26 +43,43 @@
|
|||
"es6": true
|
||||
}
|
||||
},
|
||||
"jest": {
|
||||
"verbose": true
|
||||
},
|
||||
"esdoc": {
|
||||
"source": "./lib",
|
||||
"destination": "./docs",
|
||||
"plugins": [
|
||||
{
|
||||
"name": "esdoc-standard-plugin",
|
||||
"option": {
|
||||
"lint": {
|
||||
"enable": true
|
||||
},
|
||||
"coverage": {
|
||||
"enable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "esdoc-node"
|
||||
}
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^3.0.2",
|
||||
"cross-env": "^5.1.4",
|
||||
"grunt": "*",
|
||||
"grunt-karma": "*",
|
||||
"grunt-karma-coveralls": "*",
|
||||
"grunt-standard": "*",
|
||||
"esdoc": "^1.1.0",
|
||||
"esdoc-node": "^1.0.3",
|
||||
"esdoc-standard-plugin": "^1.0.0",
|
||||
"husky": "^0.14.3",
|
||||
"karma": "*",
|
||||
"karma-chrome-launcher": "*",
|
||||
"karma-coverage": "*",
|
||||
"karma-firefox-launcher": "^1.1.0",
|
||||
"karma-qunit": "^2.0.1",
|
||||
"jest": "^23.5.0",
|
||||
"np": "^3.0.4",
|
||||
"qunit": "^2.5.1",
|
||||
"qunitjs": "^2.4.1",
|
||||
"standard": "^11.0.1"
|
||||
"standard": "^11.0.1",
|
||||
"webpack": "^4.1.1",
|
||||
"webpack-cli": "^3.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsesc": "^2.5.1",
|
||||
"webpack": "^4.1.1",
|
||||
"webpack-cli": "^2.0.12"
|
||||
"jsesc": "^2.5.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Octo Unit Tests</title>
|
||||
<link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.3.0.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
<script src="https://code.jquery.com/qunit/qunit-2.3.0.js"></script>
|
||||
<!-- Include sources -->
|
||||
<script src="../lib/utils/init.js"></script>
|
||||
<script src="../lib/utils/block.js"></script>
|
||||
<script src="../lib/utils/common.js"></script>
|
||||
<script src="../lib/utils/objects.js"></script>
|
||||
<script src="../lib/utils/platform.js"></script>
|
||||
<script src="../lib/utils/prototypes.js"></script>
|
||||
<script src="../lib/utils/script.js"></script>
|
||||
<script src="../lib/logging/console.js"></script>
|
||||
<script src="../lib/make/init.js"></script>
|
||||
<script src="../lib/make/arrays.js"></script>
|
||||
<script src="../lib/make/colors.js"></script>
|
||||
<script src="../lib/make/files.js"></script>
|
||||
<script src="../lib/make/fonts.js"></script>
|
||||
<script src="../lib/make/mime.js"></script>
|
||||
<script src="../lib/make/network.js"></script>
|
||||
<script src="../lib/make/numbers.js"></script>
|
||||
<script src="../lib/make/shaders.js"></script>
|
||||
<script src="../lib/make/text.js"></script>
|
||||
<script src="../lib/make/types.js"></script>
|
||||
<script src="../lib/make/units.js"></script>
|
||||
<script src="../lib/random/mersennetwister.js"></script>
|
||||
<script src="../lib/random/random.js"></script>
|
||||
<!-- Include tests -->
|
||||
<script src="random/mersennetwister.js"></script>
|
||||
<script src="random/random.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,58 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
QUnit.test("MersenneTwister test uniform distribution", function(assert) {
|
||||
const N = Math.pow(2, 18), TRIES = 10, XSQ = 293.25; // quantile of chi-square dist. k=255, p=.05
|
||||
let mt = new MersenneTwister();
|
||||
mt.seed(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let data = new Uint32Array(N), sh;
|
||||
for (let i = 0; i < data.length; ++i) {
|
||||
data[i] = mt.int32();
|
||||
}
|
||||
for (sh = 0; sh <= 24; ++sh) {
|
||||
let bins = new Uint32Array(256);
|
||||
for (let b of data) {
|
||||
++bins[(b >>> sh) & 0xFF];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 255)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq >= XSQ)
|
||||
break;
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
}
|
||||
if (sh == 25) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ);
|
||||
});
|
||||
|
||||
QUnit.test("MersenneTwister test float distribution", function(assert) {
|
||||
const N = Math.pow(2, 18), TRIES = 3, XSQ = 564.7; // quantile of chi-square dist. k=511, p=.05
|
||||
let tries = [], mt = new MersenneTwister();
|
||||
mt.seed(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(512);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = (mt.real2() * bins.length) >>> 0;
|
||||
if (tmp >= bins.length) throw "random.float() >= 1.0";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 511)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
|
@ -1,892 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
QUnit.test("random.init() is required", function(assert) {
|
||||
assert.throws(random.number, /undefined/, "twister should be uninitialized before random.init()");
|
||||
random.init(1);
|
||||
random.number();
|
||||
});
|
||||
|
||||
QUnit.test("random.number() corner cases", function(assert) {
|
||||
random.init(Math.random() * 0x100000000);
|
||||
let sum = 0;
|
||||
for (let i = 0; i < 100; ++i)
|
||||
sum += random.number(0);
|
||||
assert.equal(sum, 0);
|
||||
for (let i = 0; i < 100; ++i)
|
||||
sum += random.number(1);
|
||||
assert.equal(sum, 0);
|
||||
let bins = new Uint32Array(2);
|
||||
for (let i = 0; i < 100; ++i)
|
||||
++bins[random.number(2)];
|
||||
assert.equal(bins[0] + bins[1], 100);
|
||||
assert.ok(bins[0] > 20);
|
||||
sum = 0;
|
||||
for (let i = 0; i < 15; ++i)
|
||||
sum |= random.number();
|
||||
assert.equal(sum>>>0, 0xFFFFFFFF);
|
||||
});
|
||||
|
||||
QUnit.test("random.number() uniform distribution", function(assert) {
|
||||
const N = Math.pow(2, 17), TRIES = 3, XSQ = 564.7; // quantile of chi-square dist. k=511, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(512);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.number(bins.length);
|
||||
if (tmp >= bins.length) throw "random.number() >= limit";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 511)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.float() uniform distribution", function(assert) {
|
||||
const N = Math.pow(2, 17), TRIES = 3, XSQ = 564.7; // quantile of chi-square dist. k=511, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(512);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = (random.float() * bins.length) >>> 0;
|
||||
if (tmp >= bins.length) throw "random.float() >= 1.0";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 511)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.range() uniform distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 66.34; // quantile of chi-square dist. k=49, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(50);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.range(0, bins.length - 1);
|
||||
if (tmp >= bins.length) throw "random.range() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 49)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.range() uniform distribution with offset", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 66.34; // quantile of chi-square dist. k=49, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(50);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.range(10, 10 + bins.length - 1) - 10;
|
||||
if (tmp < 0) throw "random.range() < lower bound";
|
||||
if (tmp >= bins.length) throw "random.range() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 49)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.range() PRNG reproducibility", function(assert) {
|
||||
let seed, result1, result2;
|
||||
seed = Math.random() * 0x100000000;
|
||||
for (let t = 0; t < 50; ++t) {
|
||||
random.init(seed);
|
||||
result1 = random.range(1, 20);
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
random.init(seed);
|
||||
result2 = random.range(1, 20);
|
||||
assert.equal(result1, result2, "both results are the same")
|
||||
}
|
||||
seed = random.number();
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("random.ludOneTo() distribution", function(assert) {
|
||||
const N = 1e5, TRIES = 3, XSQ = 123.22; // quantile of chi-square dist. k=99, p=.05
|
||||
let dist = new Uint32Array(100), tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
/* build the ideal distribution for comparison
|
||||
* I thought this would be the PDF of the log-normal distribution, but I couldn't get mu & sigma figured out? */
|
||||
for (let i = 0; i < (100 * dist.length); ++i) {
|
||||
dist[Math.floor(Math.exp(i / (100*dist.length) * Math.log(dist.length)))] += N / (dist.length * 100);
|
||||
}
|
||||
assert.equal(dist[0], 0);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(dist.length), xsq = 0;
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.ludOneTo(bins.length)>>>0;
|
||||
if (tmp >= bins.length) throw "random.ludOneTo() > upper bound"; // this could happen..
|
||||
++bins[tmp];
|
||||
}
|
||||
assert.equal(bins[0], 0);
|
||||
for (let i = 1; i < bins.length; ++i) {
|
||||
xsq += Math.pow(bins[i] - dist[i], 2) / dist[i];
|
||||
}
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 99)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.item() exception cases", function(assert) {
|
||||
assert.throws(random.item, /received an invalid object/);
|
||||
assert.throws(function(){ return random.item(1); }, /received an invalid object/);
|
||||
assert.throws(function(){ return random.item("1"); }, /received an invalid object/);
|
||||
assert.throws(function(){ return random.item({}); }, /received an invalid object/);
|
||||
});
|
||||
|
||||
QUnit.test("random.item() distribution with list", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.item([99, 100, 101]) - 99;
|
||||
if (tmp < 0) throw "random.item() < lower bound";
|
||||
if (tmp >= bins.length) throw "random.item() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.key() distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.key({99: 0, 100: 0, 101: 0}) - 99;
|
||||
if (tmp < 0) throw "random.key() < lower bound";
|
||||
if (tmp >= bins.length) throw "random.key() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.bool() distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(2);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.bool();
|
||||
if (tmp === true)
|
||||
tmp = 1;
|
||||
else if (tmp === false)
|
||||
tmp = 0;
|
||||
else
|
||||
assert.ok(false, "unexpected random.bool() result: " + tmp);
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 1)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.pick() cases", function(assert) {
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
let tmp = Math.random();
|
||||
assert.equal(tmp, random.pick(tmp));
|
||||
}
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
let tmp = (Math.random() * 100) >>> 0;
|
||||
assert.equal(tmp, random.pick(tmp));
|
||||
}
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
let tmp = Math.random() + "";
|
||||
assert.equal(tmp, random.pick(tmp));
|
||||
}
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
let tmp = Math.random();
|
||||
assert.equal(tmp, random.pick([tmp]));
|
||||
}
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
let tmp = Math.random();
|
||||
assert.equal(tmp, random.pick(function(){ return tmp; }));
|
||||
}
|
||||
for (let i = 0; i < 100; ++i) {
|
||||
let tmp = Math.random();
|
||||
assert.equal(tmp, random.pick(function(){ return [tmp]; }));
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test("random.pick() with equal distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.pick([0, [1, 1], function(){ return 2; }]);
|
||||
if (tmp < 0) throw "random.pick() < lower bound";
|
||||
if (tmp >= bins.length) throw "random.pick() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.pick() with unequal distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.pick([[0, 1], [1], function(){ return [2]; }]);
|
||||
if (tmp < 0) throw "random.pick() < lower bound";
|
||||
if (tmp >= bins.length) throw "random.pick() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = Math.pow(bins[0] - N / 6, 2) / (N / 6) + Math.pow(bins[1] - N / 2, 2) / (N / 2) + Math.pow(bins[2] - N / 3, 2) / (N / 3);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.chance(2) distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(2);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.chance(2);
|
||||
if (tmp === true)
|
||||
tmp = 1;
|
||||
else if (tmp === false)
|
||||
tmp = 0;
|
||||
else
|
||||
assert.ok(false, "unexpected random.chance() result: " + tmp);
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 1)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.chance(undefined) distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(2);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.chance();
|
||||
if (tmp === true)
|
||||
tmp = 1;
|
||||
else if (tmp === false)
|
||||
tmp = 0;
|
||||
else
|
||||
assert.ok(false, "unexpected random.chance() result: " + tmp);
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 1)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.chance(3) distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(2);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.chance(3);
|
||||
if (tmp === true)
|
||||
tmp = 0;
|
||||
else if (tmp === false)
|
||||
tmp = 1;
|
||||
else
|
||||
assert.ok(false, "unexpected random.chance() result: " + tmp);
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = Math.pow(bins[0] - (N / 3), 2) / (N / 3) + Math.pow(bins[1] - (2 * N / 3), 2) / (2 * N / 3);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 1)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.chance(1000) distribution", function(assert) {
|
||||
const N = 1e6, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(2);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.chance(1000);
|
||||
if (tmp === true)
|
||||
tmp = 0;
|
||||
else if (tmp === false)
|
||||
tmp = 1;
|
||||
else
|
||||
assert.ok(false, "unexpected random.chance() result: " + tmp);
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = Math.pow(bins[0] - (N / 1000), 2) / (N / 1000) + Math.pow(bins[1] - (999 * N / 1000), 2) / (999 * N / 1000);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 1)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.choose() with equal distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.choose([[1, 0], [1, 1], [1, 2]]);
|
||||
if (tmp >= bins.length) throw "random.choose() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.choose() with unequal distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.choose([[1, 0], [2, 1], [1, 2]]);
|
||||
if (tmp >= bins.length) throw "random.choose() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = Math.pow(bins[0] - N / 4, 2) / (N / 4) + Math.pow(bins[1] - N / 2, 2) / (N / 2) + Math.pow(bins[2] - N / 4, 2) / (N / 4);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.choose() with unequal distribution and pick", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.choose([[1, 0], [2, [1, 2]], [1, function(){ return 2; }]]);
|
||||
if (tmp >= bins.length) throw "random.choose() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = Math.pow(bins[0] - N / 4, 2) / (N / 4) + Math.pow(bins[1] - N / 4, 2) / (N / 4) + Math.pow(bins[2] - N / 2, 2) / (N / 2);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.choose(flat) with unequal distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.choose([[1, 0], [2, 1], [1, 2]], true);
|
||||
if (tmp >= bins.length) throw "random.choose() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = Math.pow(bins[0] - N / 4, 2) / (N / 4) + Math.pow(bins[1] - N / 2, 2) / (N / 2) + Math.pow(bins[2] - N / 4, 2) / (N / 4);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.choose(flat) equal distribution with types not picked", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
const v1 = 1, v2 = [12], v3 = function(){};
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.choose([[1, v1], [1, v2], [1, v3]], true);
|
||||
if (tmp === v1)
|
||||
tmp = 0;
|
||||
else if (tmp === v2)
|
||||
tmp = 1;
|
||||
else if (tmp === v3)
|
||||
tmp = 2;
|
||||
else
|
||||
assert.ok(false, "unexpected random.choose() result: " + tmp);
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.weighted() with equal distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.item(random.weighted([{w: 1, v: 0}, {w: 1, v: 1}, {w: 1, v: 2}]));
|
||||
if (tmp >= bins.length) throw "random.weighted() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.weighted() with unequal distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.item(random.weighted([{w: 1, v: 0}, {w: 2, v: 1}, {w: 1, v: 2}]));
|
||||
if (tmp >= bins.length) throw "random.weighted() > upper bound";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = Math.pow(bins[0] - N / 4, 2) / (N / 4) + Math.pow(bins[1] - N / 2, 2) / (N / 2) + Math.pow(bins[2] - N / 4, 2) / (N / 4);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.weighted() equal distribution with types not picked", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
const v1 = 1, v2 = [12], v3 = function(){};
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.item(random.weighted([{w: 1, v: v1}, {w: 1, v: v2}, {w: 1, v: v3}]));
|
||||
if (tmp === v1)
|
||||
tmp = 0;
|
||||
else if (tmp === v2)
|
||||
tmp = 1;
|
||||
else if (tmp === v3)
|
||||
tmp = 2;
|
||||
else
|
||||
assert.ok(false, "unexpected random.weighted() result: " + tmp);
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.use() distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 3.84; // quantile of chi-square dist. k=1, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(2);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let rnd = Math.random(), use = random.use(rnd);
|
||||
if (use === rnd)
|
||||
use = 1;
|
||||
else if (use === "")
|
||||
use = 0;
|
||||
else
|
||||
assert.ok(false, "unexpected random.use() result: " + use);
|
||||
++bins[use];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 1)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.shuffle() distribution", function(assert) {
|
||||
const N = 1e4, M = 10, TRIES = 3, XSQ = 123.23; // quantile of chi-square dist. k=M*M-1, p=.05
|
||||
// XXX: shouldn't k be M! ?
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(M * M);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let array = [];
|
||||
for (let j = 0; j < M; ++j)
|
||||
array.push(j);
|
||||
random.shuffle(array);
|
||||
for (let j = 0; j < M; ++j)
|
||||
++bins[j * M + array[j]];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / M; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 99)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.shuffled() distribution", function(assert) {
|
||||
const N = 1e4, M = 10, TRIES = 3, XSQ = 123.23; // quantile of chi-square dist. k=M*M-1, p=.05
|
||||
// XXX: shouldn't k be M! ?
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(M * M);
|
||||
let array_ref = [];
|
||||
for (let j = 0; j < M; ++j)
|
||||
array_ref.push(j);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let array = random.shuffled(array_ref);
|
||||
for (let j = 0; j < M; ++j) {
|
||||
++bins[j * M + array[j]];
|
||||
if (array_ref[j] !== j)
|
||||
throw "array modified";
|
||||
}
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / M; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 99)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
||||
|
||||
QUnit.test("random.subset() with equal distribution", function(assert) {
|
||||
/*
|
||||
* this doesn't specify limit, so length distribution should be even, and selections should be even within each length
|
||||
*/
|
||||
const N = 1e4, M = 3, TRIES = 3, B0_XSQ = 5.99, B1_XSQ = 15.51, B2_XSQ = 38.89, LEN_XSQ = 7.81; // quantile of chi-square dist. k=[2,8,26,3], p=.05
|
||||
let bin0_xsq, bin1_xsq, bin2_xsq, length_xsq;
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = [new Uint32Array(3), new Uint32Array(9), new Uint32Array(27)], lengths = new Uint32Array(M+1);
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.subset([0, [1, 1], function(){ return 2; }]);
|
||||
if (tmp.length > M) throw "random.subset() result length > input";
|
||||
++lengths[tmp.length];
|
||||
if (tmp.length)
|
||||
++bins[tmp.length-1][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
|
||||
}
|
||||
bin0_xsq = bins[0].reduce(function(a, v){ let e = N / (M + 1) / Math.pow(M, 1); return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
bin1_xsq = bins[1].reduce(function(a, v){ let e = N / (M + 1) / Math.pow(M, 2); return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
bin2_xsq = bins[2].reduce(function(a, v){ let e = N / (M + 1) / Math.pow(M, 3); return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
length_xsq = lengths.reduce(function(a, v){ let e = N / (M + 1); return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (bin0_xsq < B0_XSQ && bin1_xsq < B1_XSQ && bin2_xsq < B2_XSQ && length_xsq < LEN_XSQ) {
|
||||
assert.ok(true, "Expected lengths x^2 to be < " + LEN_XSQ + ", got " + length_xsq + " on attempt #" + (attempt + 1));
|
||||
assert.ok(true, "Expected length=1 x^2 to be < " + B0_XSQ + ", got " + bin0_xsq + " on attempt #" + (attempt + 1));
|
||||
assert.ok(true, "Expected length=2 x^2 to be < " + B1_XSQ + ", got " + bin1_xsq + " on attempt #" + (attempt + 1));
|
||||
assert.ok(true, "Expected length=3 x^2 to be < " + B2_XSQ + ", got " + bin2_xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
console.log("Expected lengths x^2 to be < " + LEN_XSQ + ", got " + length_xsq);
|
||||
console.log("Expected length=1 x^2 to be < " + B0_XSQ + ", got " + bin0_xsq);
|
||||
console.log("Expected length=2 x^2 to be < " + B1_XSQ + ", got " + bin1_xsq);
|
||||
console.log("Expected length=3 x^2 to be < " + B2_XSQ + ", got " + bin2_xsq);
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq low enough");
|
||||
});
|
||||
|
||||
QUnit.test("random.subset(limit) with equal distribution", function(assert) {
|
||||
/*
|
||||
* limit is specified, so length should always == limit, and selections should be even
|
||||
*/
|
||||
const N = 1e4, M = 3, TRIES = 3, B0_XSQ = 5.99, B1_XSQ = 15.51, B2_XSQ = 38.89, B3_XSQ = 101.88; // quantile of chi-square dist. k=[2,8,26,80], p=.05
|
||||
let bin0_xsq, bin1_xsq, bin2_xsq, bin3_xsq;
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < 100; ++attempt) {
|
||||
if (random.subset([1,2,3], 0).length !== 0) throw "random.subset(..., 0) returned non-empty array";
|
||||
}
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = [new Uint32Array(3), new Uint32Array(9), new Uint32Array(27), new Uint32Array(81)];
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let tmp = random.subset([0, 1, 2], 1);
|
||||
if (tmp.length !== 1) throw "random.subset() result length != limit";
|
||||
++bins[0][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
|
||||
tmp = random.subset([0, 1, 2], 2);
|
||||
if (tmp.length !== 2) throw "random.subset() result length != limit";
|
||||
++bins[1][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
|
||||
tmp = random.subset([0, 1, 2], 3);
|
||||
if (tmp.length !== 3) throw "random.subset() result length != limit";
|
||||
++bins[2][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
|
||||
tmp = random.subset([0, 1, 2], 4);
|
||||
if (tmp.length !== 4) throw "random.subset() result length != limit";
|
||||
++bins[3][tmp.reduce(function(a, v){ return a * 3 + v; }, 0)];
|
||||
}
|
||||
bin0_xsq = bins[0].reduce(function(a, v){ let e = N / Math.pow(M, 1); return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
bin1_xsq = bins[1].reduce(function(a, v){ let e = N / Math.pow(M, 2); return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
bin2_xsq = bins[2].reduce(function(a, v){ let e = N / Math.pow(M, 3); return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
bin3_xsq = bins[3].reduce(function(a, v){ let e = N / Math.pow(M, 4); return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (bin0_xsq < B0_XSQ && bin1_xsq < B1_XSQ && bin2_xsq < B2_XSQ && bin3_xsq < B3_XSQ) {
|
||||
assert.ok(true, "Expected length=1 x^2 to be < " + B0_XSQ + ", got " + bin0_xsq + " on attempt #" + (attempt + 1));
|
||||
assert.ok(true, "Expected length=2 x^2 to be < " + B1_XSQ + ", got " + bin1_xsq);
|
||||
assert.ok(true, "Expected length=3 x^2 to be < " + B2_XSQ + ", got " + bin2_xsq);
|
||||
assert.ok(true, "Expected length=4 x^2 to be < " + B3_XSQ + ", got " + bin3_xsq);
|
||||
return;
|
||||
}
|
||||
}
|
||||
console.log("Expected length=1 x^2 to be < " + B0_XSQ + ", got " + bin0_xsq);
|
||||
console.log("Expected length=2 x^2 to be < " + B1_XSQ + ", got " + bin1_xsq);
|
||||
console.log("Expected length=3 x^2 to be < " + B2_XSQ + ", got " + bin2_xsq);
|
||||
console.log("Expected length=4 x^2 to be < " + B3_XSQ + ", got " + bin3_xsq);
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq low enough");
|
||||
});
|
||||
|
||||
QUnit.test("random.pop() distribution", function(assert) {
|
||||
const N = 1e4, TRIES = 3, XSQ = 5.99; // quantile of chi-square dist. k=2, p=.05
|
||||
let tries = [];
|
||||
random.init(Math.random() * 0x100000000);
|
||||
for (let attempt = 0; attempt < TRIES; ++attempt) {
|
||||
let bins = new Uint32Array(3);
|
||||
const orig = [99, 100, 101];
|
||||
for (let i = 0; i < N; ++i) {
|
||||
let arr = orig.slice(), tmp = random.pop(arr) - 99;
|
||||
if (tmp < 0) throw "random.pop() < lower bound";
|
||||
if (tmp >= bins.length) throw "random.pop() > upper bound";
|
||||
if (arr.length !== 2) throw "random.pop() did not pop";
|
||||
if (arr.reduce(function(a, v){ return a + v; }, tmp) !== 201) throw "random.pop() sum error";
|
||||
++bins[tmp];
|
||||
}
|
||||
let xsq = bins.reduce(function(a, v){ let e = N / bins.length; return a + Math.pow(v - e, 2) / e; }, 0);
|
||||
/*
|
||||
* XSQ = scipy.stats.chi2.isf(.05, 2)
|
||||
* if xsq > XSQ, the result is biased at 95% significance
|
||||
*/
|
||||
if (xsq < XSQ) {
|
||||
assert.ok(true, "Expected x^2 to be < " + XSQ + ", got " + xsq + " on attempt #" + (attempt + 1));
|
||||
return;
|
||||
}
|
||||
tries.push(xsq);
|
||||
}
|
||||
assert.ok(false, "Failed in " + TRIES + " attempts to get xsq lower than " + XSQ + ": "+ tries);
|
||||
});
|
Loading…
Reference in a new issue