Search Unity

  1. Engage, network and learn at Unite Austin 2017, Oct 3 - 5. Get your ticket today!
    Dismiss Notice
  2. Introducing the Unity Essentials Packs! Find out more.
    Dismiss Notice
  3. Check out all the fixes for 5.6 on the patch releases page.
    Dismiss Notice
  4. Unity 2017.1 is now released.
    Dismiss Notice
  5. Unity 2017.2 beta is now available for download.
    Dismiss Notice

[Update v2.0] Make It Random: A Fast, Flexible, Extensible, and Feature-Rich RNG Library

Discussion in 'Assets and Asset Store' started by AndyGainey, Nov 18, 2016.

  1. AndyGainey

    AndyGainey

    Joined:
    Dec 2, 2015
    Posts:
    210
    News: Version 2.0 has been released. Includes non-uniform distributions, and the basic edition is now free! goto details;

    [​IMG]

    A serious RNG library for serious engineers.

    Purchase now on the Asset Store: $20 Complete Edition | Free Basic Edition

    View the full online documentation, skim through the quick start, or check out the demos.

    Make It Random is a fast, flexible, extensible, and feature-rich random number generation library. Unlike UnityEngine.Random, Make It Random provides the following benefits:
    • Offers a wide variety of utilities on top of the basic random number generation.
    • Produces higher quality uniform distributions of integer and floating point numbers.
    • Allows multiple concurrent random engines, each seeded differently, independently generating sequences of random values.
    • Can be seeded using a wider variety of data, such as strings or byte arrays of any length.
    • Can be used on any thread, not just the main thread.
    • Includes multiple random engine algorithms and supports implementation of your own.
    • Reduces confusion about whether the lower and upper bounds of ranges are inclusive or exclusive.
    The categories of random data that Make It Random can generate includes:
    • bits
    • integers
    • floating point numbers
    • angles
    • vectors and quaternions
    • strings
    • dice rolls
    • colors (includes Make It Colorful)
    In addition, Make It Random includes utilities for the following, with support for non-uniform weights where applicable:
    • evaluating probabilities
    • sampling from distributions
    • selecting elements from a list
    • selecting values from an enumeration
    • selecting values from the set {-1, 0, +1}
    • shuffling a list
    The library is very extensible, supporting whatever new underlying RNGs and extension functions you might want.

    Full source code is included.

    For inquiries or suggestions, feel free to use this thread, or contact me on Twitter @AndyGainey or email againey@experilous.com.

    The Details

    Random Engines
    • XorShift128+ is great for general use.
    • XorShift1024* offers a huge state space and long period, ideal for card games.
    • An instance of SplitMix64 uses just 8 bytes of memory.
    • XorShiftAdd is optimal for 32-bit platforms.
    • Wrappers for UnityEngine.Random and System.Random allow them to be used with all the available extension functions.
    • An abstract base class to simply the process of porting your favorite random engine or creating your own.

    Random Integers
    • Supports all built-in integer types, both signed and unsigned, for 8-, 16-, 32-, and 64-bit sizes, so that you can directly and optimally get the type you need.
    • Explicit upper and lower bound inclusiveness. Open, closed, and half-open ranges all supported, with no need to frequently check documentation to be reminded of what a function does.
    • Overloads make it easy to provide both an upper and lower bound, or just an upper bound with an implicit lower bound of 0, or no bound at all to pull from the full range of the integer type requested.

    Random Floating Point Numbers
    • Direct support for both float and double.
    • Explicit upper and lower bound inclusiveness, as with integer ranges.
    • Perfect uniformity and no irregular clumpiness for the unit range (between 0 and 1).
    • Incredibly fast implementation, no division or remainder operations involved.
    • Special functions for increased precision near zero, and for the signed unit range (between -1 and +1).

    Probabilities and Chance
    • Easy way to get a direct true or false result, including a zero-parameter 50/50 chance function.
    • Direct probabilities: likelihood of true value, specified between 0 and 1.
    • Ratio of true to false: n true results for every m false results.
    • Frequency: n true results out of d total results.

    Distribution Sampling
    • Sample from the following continuous distributions: uniform, triangular, trapezoidal, linear, Hermite spline, normal, and exponential.
    • Combine piecewise uniform, linear, or Hermite spline distributions to form more complex aggregate distributions.
    • Initialize Hermite spline distributions using Unity animation curves, making it easy to configure the shape directly from the editor.
    [​IMG]

    Vectors and Quaternions
    • High precision 2D, 3D, and 4D unit vectors.
    • Uniformly distributed 2D vectors within circles, circular rings, squares, rectangles, parallelograms, and triangles
    • Uniformly distributed 3D vectors within spheres, spherical shells, cubes, boxes, and rhomboids.
    • Very fast implementation fixed point intermediate arithmetic, guarantees reliable determinism across platforms.

    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]

    Strings
    • Fast binary, octal, decimal, hexadecimal, and base64 strings.
    • Alphabetic, alphanumeric, and identifier strings, with nuanced control over separators like spaces or underscores.
    • Strings made from custom character sets, also with separator control.

    Angles
    • Degrees and radians both supported.
    • Half (180°) and full (360°) revolution ranges.
    • Signed (centered on 0°) and unsigned ranges (starting at 0° upward).

    Dice
    • Any number of sides per die, any number of dice.
    • Options to keep or drop the n highest or lowest rolls from a group.
    • Dice string parsing to make use of common dice notation such as "4d6k3" to roll 4 6-sided dice and keep the highest 3.

    Colors
    • Supports standard RGB, plus all the color spaces provided by Make It Colorful: HSV, HSL, HSY, HCV, HCL, HCY, CMY, and CMYK.
    • Pick random colors uniformly from within an entire color space.
    • Randomly modify one or more components of an existing color according to specifiable constraints.
    • Easily lighten or darken, brighten or dull, or hue shift an existing color.

    [​IMG]

    List Access and Shuffling
    • Supports arrays and anything implementing IList<T>.
    • Can generate random indices for lists or directly pull elements.
    • Supports both uniform and weighted selection.
    • Shuffle in-place or into a different list.
    • Optionally force a shuffle to guarantee that all elements get moved to a new location.

    [​IMG]
    [​IMG]

    Enumerations
    • Automatically examines any desired enum type and prepares an efficient enumeration item generator.
    • Can treat duplicate values as either distinct or identical.
    • Can return both enumeration item value and name, useful when duplicate values are still considered distinct.
    • Can provide weights for the different items in an enumeration, influencing how likely each is to be randomly selected.

    {-1, 0, +1}
    • Great in certain numerical situations, to multiply an existing number to make it negative or positive, or to zero it out.
    • Similar probability, ratio, and frequency interfaces as for random true/false values.
    • Can be limited to just the pairs {0, 1} or {-1, +1}.

    Miscellaneous
    • Many operations can be wrapped into generator instances, remembering parameters and optimizing the generation process.
    • Numerous options for seeding random engines, all with a common interface regardless of engine implementation.
    • Easily store or load the state of a random engine as an opaque byte array, or access it using that engine's particular state format.
    • A global static instance available for convenience, if that interface suits your needs.

    Basic Edition

    The basic addition includes the core interface, one general-purpose random engine (XorShift128+), and the following utilities:
    • bits
    • integers
    • floating point numbers
    • probabilities

    Samples

    The following script can be used to place multiple copies of a prefab into the scene, with random positions selected near the surface of a sphere.

    Code (CSharp):
    1. using UnityEngine;
    2. using Experilous.MakeItRandom;
    3.  
    4. public void SphericalShellDistributor : MonoBehaviour
    5. {
    6.   public MeshRenderer prefab;
    7.   public int objectCount = 100;
    8.   public string randomSeed = "andy";
    9.   public float minShellRadius = 9f;
    10.   public float maxShellRadius = 11f;
    11.   public float minScale = 0.5f;
    12.   public float maxScale = 1.5f;
    13.  
    14.   protected void OnStart()
    15.   {
    16.     // Use the seed to create the random engine which
    17.     //  will provide the randomness of each child.
    18.     var random = MIRandom.CreateStandard(randomSeed);
    19.  
    20.     for (int i = 0; i < objectCount; ++i)
    21.     {
    22.       var meshRenderer = Instantiate(prefab);
    23.       var meshTransform = meshRenderer.transform;
    24.       meshTransform.SetParent(transform, false);
    25.  
    26.       // Assign a random position within the shell.
    27.       meshTransform.localPosition =
    28.       random.PointWithinSphericalShell(minRadius, maxRadius);
    29.  
    30.       // Give it a completely random orientation.
    31.       meshTransform.localRotation = random.Rotation();
    32.  
    33.       // Pick a random scale within the specified range.
    34.       var scale = random.RangeCC(minScale, maxScale);
    35.       meshTransform.localScale = new Vector3(scale, scale, scale);
    36.  
    37.       // Assign a color pulled randomly from the HCY color space.
    38.       meshRenderer.color = random.ColorHCY();
    39.     }
    40.   }
    41. }
    Here are quick samples from the various categories of random content generation available:
    Code (CSharp):
    1. // Initialize random engine with a specific seed
    2. var random = XorShift128Plus.Create("239361:purple_below ! Jupiterritory");
    3.  
    4. // Generate an integer where 1 <= n <= 10
    5. int num1to10 = random.RangeCC(1, 10);
    6.  
    7. // Generate a number where 0 <= n < 1
    8. float num0to1 = random.FloatCO();
    9.  
    10. // Flip a coin
    11. bool heads = random.Chance();
    12.  
    13. // Check a 3 in 10 probability
    14. bool criticalHit = random.Probability(3, 10);
    15.  
    16. // Generate a random height for a male character in cm
    17. float height = random.NormalSample(176f, 8f);
    18.  
    19. // Generate an angle in degrees where -90 < n < +90
    20. float angleNeg90toPos90 = random.SignedHalfAngleDegOO();
    21.  
    22. // Generate +1, -1, or 0 where +1 is twice as likely as -1, and 0 is rare
    23. int numPNZ = random.SignOrZero(200, 100, 1);
    24.  
    25. // Roll 43 20-sided dice
    26. int[] diceRolls = random.RollDice(43, 20);
    27.  
    28. // Roll 5 4-sided dice and just keep the sum
    29. int diceRollSum = random.SumRollDice(5, 4);
    30.  
    31. // Shuffle the array of earlier dice rolls
    32. random.Shuffle(diceRolls);
    33.  
    34. // Select a random die roll from the array
    35. int dieRoll = random.Element(diceRolls);
    36.  
    37. // Select index where higher die rolls are more likely to be picked
    38. int dieRollIndex = random.WeightedIndex(diceRolls);
    39.  
    40. // Generate a random 3D unit vector
    41. Vector3 direction = random.UnitVector3();
    42.  
    43. // Generate a position within a cirle of radius = 5
    44. Vector2 point = random.PointWithinCircle(5f);
    45.  
    46. // Generate a 32-character string with only alpha-numeric characters.
    47. string str = random.AlphaNumericString(32);
    48.  
    49. // Make a generator which will produce random font styles.
    50. var fontStyleGen = random.MakeEnumGenerator();
    51. // Generate a font style
    52. var style = fontStyleGen.Next();
    53.  
    54. // Pick a random warm color
    55. var color = random.ColorWarm();
    56. // Alter the color's hue randomly by no more than 1/10.
    57. color = random.HueShift((ColorHSV)color, 0.1f);

    Quick Links
     
    Last edited: Jan 14, 2017
    TeagansDad likes this.
  2. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    2,437
    I have seen nothing about random hash, especially random BIJECTIVE hash! Does this support this essential issue?

    Here is why this is essential:
    http://blog.runevision.com/2015/01/primer-on-repeatable-random-numbers.html

    Bijective hash is also great for procedural generation to sample 2^64 size list without any collision and without having to shuffle the list to begin with (instant shuffling!)
     
  3. AndyGainey

    AndyGainey

    Joined:
    Dec 2, 2015
    Posts:
    210
    Seeds are indeed passed through a hash function (based on FNV) before being written to a random engine's state.

    However, since the seed utility I wrote was designed for mapping seeds of any size to the appropriate state size of the random engine being initialized, I did not even think of supporting a bijective hash, and so I cannot guarantee that every seed whose size is not larger than the target state size maps to a unique RNG state. Given that all but one of the generators included have a 128-bit state, it's highly unlikely that two seeds used by a game will map to the same state, but yeah, for now, it is vaguely possible.

    Hash functions are already a feature on my to-do list, and I just added a note to consider making the seed hasher do perfect hashing when the seed is the same size as the target engine state. Thanks for the suggestion!
     
    TeagansDad and neoshaman like this.
  4. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    2,437
    Thank you so much, I have been looking so long for a good rng, using hacks and work around, but was never fully satisfied. I hope I can finally settle on your solution!
     
  5. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,075
    Finally a good "all in one" RNG Solution. Seems thoroughly thought through ;).
    It "only" supports uniform didstribution? Any plans of including a tool to recalculate them to other distributions?
    Are you aware that animation curves can be used to control probability ? Any chance this feature is included? (would also help with the above)
    How is the weighting applied. Say I have a List of 3 items and the first shall be picked 20%, second 30% and third 50% of the times. How would I do that with your package? Can I define absolute or relative probabilities somewehre?

    Anyway. Very good work. Will purchase it at the weekend. Thanks for your efforts.
     
  6. AndyGainey

    AndyGainey

    Joined:
    Dec 2, 2015
    Posts:
    210
    Non-uniform distributions are a feature I plan to add, and I've done a fair bit of preliminary research already, but for time-management purposes I chose to leave them for a future version. And using animation curves for custom distributions would be awesome, I agree. Depending on how underlying implementation works out for applying to various distribution shapes, supporting animation curves might be included in this first wave of non-linear distributions, or it might get held back until an even later update.

    The weighted selection functions can be found in RandomListAccess, in particular, WeightedIndex(...) to get an integer index and WeightedElement(...) to get an item without caring what the index is. In both cases, you can pass either an array of weights (must be the same length as the number of items you're selecting among), or a Func<int, TWeight> which maps element indices to weights (in case you store your weights in a container other than an array, or if you want to just write a simple switch statement to map indices to weights, or if you have a mathematical formula for calculating weights). Here's an example using an array:

    Code (CSharp):
    1. GameObject[] prefabs = ...;
    2. int[] prefabWeights = new int[] { 20, 30, 50 };
    3. IRandom random = MIRandom.CreateStandard();
    4.  
    5. GameObject randomPrefab = random.WeightedElement(prefabs, prefabWeights);
    You can optionally pass in a pre-computed sum of all the weights, which is recommended if you call these functions more than once without changing the weights or number of items. Otherwise, the sum will be computed on every call. And to simplify the process, MakeWeightedIndexGenerator(...) and MakeWeightedElementGenerator(...) will pre-compute everything and return a simple generator object that gives you a new random index or element each time you call Next().

    Code (CSharp):
    1. var randomPrefabGenerator = random.MakeWeightedElementGeneator(prefabs, prefabWeights);
    2. GameObject firstRandomPrefab = randomPrefabGenerator.Next();
    3. GameObject secondRandomPrefab = randomPrefabGenerator.Next();
    Two caveats: First, when writing the underlying algorithm, I focused too heavily on making sure that it was perfectly correct, and failed to notice that it was embarrassingly inefficient, until it was politely pointed out to me elsewhere. In short, I make multiple calls to the random engine to test probabilities when I only need to make a single call. I'm pretty certain I've written the correct implementation far in the past, and it just slipped my mind somehow this time around. The second caveat is that I appear to have missed a few overloads of WeightedElement(...) for weights of type float and double. The fixes will definitely be included in the first update to the package, for I must address this shame. :)
     
  7. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,075
    Thanks for the clarification. Sounds awesome. Especially the "MakeWeighted...Generator" should come in handy for that usecase.

    Who does not program bugs, should throw the first stone! ;)
     
  8. nixter

    nixter

    Joined:
    Mar 17, 2012
    Posts:
    316
    Most of the demos on your documentation page are not loading up correctly in WebGL. Except for the Colors demo, they are all loading the Performance demo, which causes a crash. This is happening in both Firefox and Chrome for me. I'm surprised no one has mentioned it yet.

    Interesting product. I'm looking forward to testing it out once this is fixed.
     
    AndyGainey likes this.
  9. AndyGainey

    AndyGainey

    Joined:
    Dec 2, 2015
    Posts:
    210
    Oh goodness, yup, wrong demos. They're fixed now (you may need to force-refresh the demos so that they don't pull the incorrect cached performance demo). Sorry about that, and thanks a ton for letting me know!

    The performance demo unfortunately didn't work for WebGL, as it is multithreaded at its core, so I removed it from the list of online demos. And then ironically I went and incorrectly built all the others so that they included that one specific incompatible scene. C'est la vie.
     
  10. AndyGainey

    AndyGainey

    Joined:
    Dec 2, 2015
    Posts:
    210
    Version 2.0 is incoming, with a focus on non-uniform distribution sampling, plus various other improvements and fixes. And the basic edition will drop its $5 price tag and be available for free! The documentation for v2.0 is here. Below you can find a sample of the various distributions, followed by the full change log:

    [​IMG]

    Features
    • Added distribution sampling, with initial support for continuous sampling from the following:
      • uniform distribution
      • triangular distribution
      • trapezoidal distribution
      • linear distribution
      • Hermite spline distribution
      • normal distribution
      • exponential distribution
      • piecewise uniform distribution
      • piecewise linear distribution
      • piecewise Hermite spline distribution
    • Added some common color categories for generating random colors, such as bold, pastel, somber, warm, and cool.
    Breaking Changes
    • Changed the elementCount parameter order for RandomListAccess.WeightedIndex(...) for better consistency and flexibility.
    • MIRandom.CreateStandard(...) functions now return IRandom instead of XorShift128Plus.
    • MIRandom.CreateStandard(...) functions may return an instance of some engine type other than XorShift128Plus, depending on the platform and compiler defines.
    Bug Fixes
    • Control flow in RandomGeometry.Rotation() tweaked so that the updated compiler in Unity 5.5 will not complain about an unset out parameter.
    • Fixed the version 0.1 backward-compatible code path for seeding XorShift128Plus so that it works in both the Complete and Basic edition by not depending on the existence of SplitMix64.
    • Corrected the version 0.1 backward-compatible code path for RandomGeometry.UnitVector2() to do the proper math instead of calling itself repeatedly and cause a stack overflow.
    General Fixes
    • Added missing float and double overloads for RandomListAccess.WeightedElement(...).
    Improvements
    • Improved weighted list index generation to only generate a single random value, instead of one per each weight.
    • Improved pre-computed weighted list index generation to operate in O(log n) time instead of O(n), by storing a cumulative weight sum array and performing a binary search on it.
    • Provided additional overloads for weighted list index/element generation to specify a subset of weights to use, convenient for manually resized arrays that may have more elements than are currently used.
    • Added WeightedRandomIndex and WeightedRandomElement extension functions for IList<T>.
    • Random engines now support equality comparisons, which check that both type and internal state are equal.
    • Parameter requirements for RandomInteger.RangeCO(...) using unsigned types loosened; an upper exclusive value of 0 will now generate a value within the entire range of the unsigned integer type.
    Demos
    • Added a distribution sampling demo scene.
    • The shuffle and weighted index generation demo will now repeatedly select new indices at a configurable frequency.
    • The random colors demo allows a more flexible method of generating colors from a selected color category.
     
    Last edited: Jan 11, 2017
  11. exiguous

    exiguous

    Joined:
    Nov 21, 2010
    Posts:
    1,075
    It's pretty crappy that UT does not allow 6 Star ratings! Your asset is definitely one of my top 3 assets (and I own alot!) considering features, support/devlopment, useability and quality. Thanks for your hard work Andy.
     
    AndyGainey likes this.
  12. AndyGainey

    AndyGainey

    Joined:
    Dec 2, 2015
    Posts:
    210
    Thank you so much for the support and kind words! The update should be available now. I'm glad you've found the library to be so useful. I hope the new features extend that usefulness even further!