These are my backed up notes as I tried out various random generators and read prio art.
TODO
-
Try out the suggested algorithm that supports random access random number generation that isn't expensive.
-
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 usingnew Array(Math.pow(2,32)/32)
and then using a u32 and bit checks should work
- Note: To ensure every value was hit and only once:
- Shouldn't we be dividing by (MAX_U32-1), so that we can actually hit 1.0?
-
Add shuffling at some point
- Fisher-Yates Shuffle
- As found in here Mike Bostock's Visualizing Algorithms
- Fisher-Yates Shuffle
-
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?)
-
Find a good two way 32 bit hash
- This conversation looks very promising, lots of leads
- https://stackoverflow.com/questions/959916/way-to-encrypt-a-single-int
- Don't forget to make it invertible too for bonus points
- Allows going backwards from a hash to it's index
-
Neat Hash algorithms
-
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):
-
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://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:
-
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
- 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)
- this too
- Reversible LCG
- Why is it difficult to write a good PRNG in javascript?
- http://number-none.com/blow/blog/programming/2016/07/13/braid_particles_2.html
- https://github.com/davidbau/xsrand
- Looks very fast
-
Bit operations subtlties
-
Test (For each power of two bit range: 1, 2, 4, 8, 16, 32 bit range)
- First looping
- Coverage
- Uniformity
- Standard tests?
npm install arbitrary
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:
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));
- 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
- 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.
- Explain the benefits better. Is performance reason enough? Probably, espcially in Javascript.
- Reserve
arbitrary
npm module name - Use 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 and history lessong for the general MT work as well as the TinyMT implementation.
- Read through: PCG, A Family of Better Random Number Generators