UNPKG

arbitrary

Version:
227 lines (201 loc) 11.9 kB
### Research These are my backed up notes as I tried out various random generators and read prio art. TODO - Tests - Shouldn't we be dividing by (MAX_U32-1), so that we can actually hit 1.0? - Need to think this out, want to make sure we are absolutely as close to unbiased in a direction as possible in generators such as (inclusive of both min/max) [-1,1] that want values between - Run exhaustive tests? (Maybe separately from main tests) - Run for both next/prev but also scramble/unscramble - Prelimary tests of calling generate.next 2^32 times took 70s, so it's entirely feasible to do exhaustive tests of properties - Note: To ensure every value was hit and only once: `new Array(Math.pow(2,32))` fails, but using `new Array(Math.pow(2,32)/32)` and then using a u32 and bit checks should work - Add shuffling at some point - [Fisher-Yates Shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) - As found in here Mike Bostock's [Visualizing Algorithms](https://bost.ocks.org/mike/algorithms/#sorting) - Cleanup API/module structure, support functional and OO styles - Functional: ``` import {seed, next, prev, scramble, unscramble, range, percent, float, bits, integer} from 'arbitrary'; let state = seed(state|undefined); // undefined is equivalent to 0. any non positive integer throws an exception const bitMask = bits(state, bitCount) // Roll the state forward one step before generating more values state = next(state); // Create a new stream of random numbers by deriving a new state from the existing one const fork = scramble(state); const anotherNumber = integer(forkedState, 0, 10); ``` - OO: ``` import {Generator} from 'arbitrary'; const generator = new Generator(state|undefined); // undefined is equivalent to 0. any non positive integer throws an exception // Generate a number between 0 and bitCount^2 - 1 (Using current generator state, AND advancing the state); generator.bits(bitCount); // Step the generator forward one step generator.next(); // Step the generator backwards one step generator.next(); - generate ``` - Random filling of 2d array (good for old school cross fade, but also for ray tracing?) - http://fabiensanglard.net/fizzlefade/index.php - Find a good two way 32 bit hash - [This conversation looks very promising, lots of leads](https://www.quora.com/How-do-you-symmetrically-encrypt-32-bit-auto-increment-IDs-to-avoid-using-64-bit-UUIDs-to-conceal-the-size-and-order-of-a-database-table) - https://github.com/0x4139/node-skip32 - https://stackoverflow.com/questions/959916/way-to-encrypt-a-single-int - ISAAC - https://www.npmjs.com/package/isaac - https://en.wikipedia.org/wiki/Cryptographically_secure_pseudorandom_number_generator - Don't forget to make it invertible too for bonus points - Allows going backwards from a hash to it's index - Neat Hash algorithms - https://www.npmjs.com/package/tifuhash - Goal builds an entire game world that is purely reversible - See if we can make card games reversible - Card game strategies - Character movement - Everything! (Or maybe make single simple game test beds. Especially classics like boids, A*, etc) - First test that this approach works for all number ranges - Then strip down use of Long library code - Really document and get it understood (Defer, maybe it's time to move on) - Now start thinking about a good API design - I prefer the var generate = arbitrary.Generator() and arbitrary.float(min|min,max) - Can we make it both play well with immutable style APIs and the convenience of a self mutating one? - Add an entry here (pointing to my implementation): - https://stackoverflow.com/questions/2911432/reversible-pseudo-random-sequence-generator - Consider making a generalized library for reversible applications (T-Functions (or is that just for bit oriented ones), T-Applications?) - Do try out xorshift - https://bitbucket.org/runevision/random-numbers-testing/src/16491c9dfa60417a5b25bd496e06a8f75b8f4f50/Assets/Implementations/RandomNumberGenerators/XorShift.cs?at=default&fileviewer=file-view-default - Does it have [0, 2^32) range? - Is it reversible in Javascript - Is it more performant? Generate random numbers. - More leads - Goldmine in Google Closure library: - https://github.com/google/closure-library/blob/master/closure/goog/math/long.js#L53 - https://en.wikipedia.org/wiki/Inversive_congruential_generator Using LCG First - Verify algorithm works at each range of values (no small walks because of integer precision issues) - Make sure all math works as expected for u32, addition and multiplication operations need to wrap correctly - Pretty sure multiplication blows past the precision needed when the state is near the top of the value range - Also the addition of the increment should wrap in 32 bit space I believe (Actually maybe not) - Add u32 - Add i32 - Add u32Range - Add i32Range - Make sure that the if we add a true random number generator that pulls from say Math.random() that we log a warning to indicate that you should only use it once LESSONS LEARNED SO FAR - Build everything with T-Functions (bijective operations on n-bit ring numbers) - You could likely build many structured generators such as spiral, hilbert space, random full coverage 2D sample, etc Search for algorithms with some or all of the following properties: - algorithm is reversible (you can go back to a previous state given a current state) - algorithm is random access (you can provide an index [0, 2^32) that generates a good random value) - fast - maximum period length for state bit size (ie 32 bit state should generate 2^32 unique values before looping again) - lastly but less important: the usual ideal PRNG properties Good References - http://www.pcg-random.org/ - V8 switched to new generator in 2015 - https://v8project.blogspot.com/2015/12/theres-mathrandom-and-then-theres.html TODO: - Explain each algorithm, cleanly and visually - Keep looking into this: - https://rosettacode.org/wiki/Random_number_generator_(included)#C.2B.2B - These seems good - https://www.npmjs.com/package/rng - https://www.npmjs.com/package/ivoire-one-of - https://www.npmjs.com/package/random-js - http://stackoverflow.com/questions/17625232/custom-linear-congruential-generator-in-javascript - http://jsfiddle.net/AbdiasSoftware/7VmR9/12/ - https://bocoup.com/weblog/random-numbers - https://gist.github.com/Protonk/5367430 (Gold it looks like) - I really like the sound of the webkit invertible mapping generator - https://en.wikipedia.org/wiki/T-function - https://eprint.iacr.org/2011/547.pdf - https://gist.github.com/Protonk/5367430#file-prng-js-L91-L109 - https://gist.github.com/Protonk/5367497 (includes link to C++ source) - Near random access (Log(n) n being skipp amount) - http://stackoverflow.com/a/38495314 (I believe this was mentioned in the above log too) - This looks promising (Sounds like you can jump to any point to generated a value) - http://stackoverflow.com/a/19508103 - Source: https://code.google.com/archive/p/javarng/source/default/source - this too - https://github.com/bobbaluba/rlcg - Reversible LCG - http://stackoverflow.com/a/16630535 - Why is it difficult to write a good PRNG in javascript? - https://github.com/nquinlan/better-random-numbers-for-javascript-mirror - http://number-none.com/blow/blog/programming/2016/07/13/braid_particles_2.html - https://marc-b-reynolds.github.io/shf/2016/04/19/prns.html - https://github.com/davidbau/xsrand - Looks very fast - https://github.com/davidbau/xsrand/blob/master/xor128.js#L4 - Bit operations subtlties - https://stackoverflow.com/questions/14061999/why-does-0x80000000-1-in-javascript-produce-a-negative-value - Learning a lot here: - http://www.ecma-international.org/ecma-262/7.0/index.html#sec-binary-bitwise-operators-runtime-semantics-evaluation - Use >>> where possible - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Unsigned_right_shift - Test (For each power of two bit range: 1, 2, 4, 8, 16, 32 bit range) - First looping - Coverage - Uniformity - Standard tests? - https://en.wikipedia.org/wiki/Randomness_tests # Installation npm install arbitrary # Usage ## Basics ```js var arbitrary = require('arbitrary'); console.log(arbitrary.float()); console.log(arbitrary.integer()); console.log(arbitrary.shuffle([1, 2, 3, 4])); console.log(arbitrary.choice([1, 2, 3, 4])); console.log(arbitrary.sample([1, 2, 3, 4], 2)); ``` Manage your own instances: ```js var arbitrary = require('arbitrary'), generate = new arbitrary.Generator(); console.log(generate.float()); console.log(generate.integer()); console.log(generate.shuffle([1, 2, 3, 4])); console.log(generate.choice([1, 2, 3, 4])); console.log(generate.sample([1, 2, 3, 4], 2)); ``` # Project Goals - Be able to easily clone a generator instance - Be able to step a generator backward (soft requirement, as it's 28 bytes for the total state. But that could add up if you want to go backwards in time and rollback generator state.) - Be efficient. - Provide Module Distributions - Vanilla .js file - Browserfy - Require - Bower # Todo - [ ] Add noise, shuffle, serialize(getState() instead?), deserialize(setState() instead?), functions. Also look for my other notes. - [ ] Should we add support for generating higher dimensional and compound objects like: Vector2D, Vector3D, rgb (compatible with svg/canvas/dom), rgba(compatible with svg/canvas/dom), normal2D, normal3D, quaternion, etc? - [ ] Checkout other PRNG libraries. - [Python's](https://docs.python.org/2/library/random.html#random.getstate) - [ ] Explain the benefits better. Is performance reason enough? Probably, espcially in Javascript. - [x] Reserve ```arbitrary``` npm module name - [ ] Use [WebCryptoAPI](http://www.w3.org/TR/WebCryptoAPI/) instead of time for original seed? Doesn't really make sense considering security is not our use case. - [ ] Try porting to javascript using emscripten - [ ] If emscripten doesn't work out well or at all, port it manually to Javascript. - [ ] Write tests - [ ] Make sure integer range parameters make sense - [ ] Make sure shuffles shuffle every element (Also that the last element is sometimes shuffled to, not just from which is guaranteed from our looping approach) - [ ] Sanity check distribution, performance, and anything else that adds integrity - [ ] Should we start guaranteeing backward compatible determism? (This might be too high of a constraint) - [ ] What about just general cross environment determinism (ie, same seed same outputs in every browser and node etc) - [ ] Give a [list of references](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/earticles.html) and history lessong for the general MT work as well as the TinyMT implementation. - [ ] Read through: [PCG, A Family of Better Random Number Generators](http://www.pcg-random.org/) # References - [Mersenne Twister Home Page](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html) - [TinyMT is a new small-sized variant of Mersenne Twister (MT) introduced by Mutsuo Saito and Makoto Matsumoto in 2011](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/TINYMT/index.html) - C/C++ implementation: [github.com/jj1bdx/TinyMT](https://github.com/jj1bdx/TinyMT)