/// <summary> /// Construct with the provided RNG source. /// </summary> public UniformDistribution(IRandomSource rng, float scale, bool signed) { _rng = rng; _scale = scale; _signed = signed; // Note. We predetermine which of these four function variants to use at construction time, // thus avoiding the two condition tests on each invocation of Sample(). // I.e. this is a micro-optimization. if (signed) { if (1.0 == scale) { _sampleFn = () => { return((_rng.NextFloat() - 0.5f) * 2.0f); }; } else { _sampleFn = () => { return((_rng.NextFloat() - 0.5f) * 2.0f * scale); }; } } else { if (1.0 == scale) { _sampleFn = () => { return(_rng.NextFloat()); }; } else { _sampleFn = () => { return(_rng.NextFloat() * scale); }; } } }
/// <summary> /// Initialise agent and prey positions. The prey is positioned randomly with at least 4 empty squares between it and a wall (in all directions). /// The agent is positioned randomly but such that the prey is within sensor range (distance 2 or less). /// </summary> public void InitPositions() { // Random position at least 4 units away from any wall. _preyPos.X = 4 + _rng.Next(__gridSize - 8); _preyPos.Y = 4 + _rng.Next(__gridSize - 8); // Agent position. The angle from the prey is chosen at random, and the distance from the prey is randomly chosen between 2 and 4. float t = 2f * MathF.PI * _rng.NextFloat(); // Random angle. float r = MathF.FusedMultiplyAdd(2f, _rng.NextFloat(), 2f); // A distance between 2 and 4. _agentPos.X = _preyPos.X + (int)MathF.Truncate(MathF.Cos(t) * r); _agentPos.Y = _preyPos.Y + (int)MathF.Truncate(MathF.Sin(t) * r); }
/// <summary> /// Fill a span with samples from a binary/Bernoulli distribution with the given probaility of sampling 'true'. /// </summary> /// <param name="rng">Random source.</param> /// <param name="probability">Probability of sampling 'true'.</param> /// <param name="span">The span to fill with samples.</param> public static void SampleBernoulli(IRandomSource rng, float probability, Span <bool> span) { for (int i = 0; i < span.Length; i++) { span[i] = rng.NextFloat() < probability; } }
/// <summary> /// Fill an array with samples from a binary/Bernoulli distribution with the specified boolean true probability. /// </summary> /// <param name="rng">Random source.</param> /// <param name="probability">Probability of sampling boolean true.</param> /// <param name="buf">The array to fill with samples.</param> public static void SampleBernoulli(IRandomSource rng, float probability, bool[] buf) { for (int i = 0; i < buf.Length; i++) { buf[i] = (rng.NextFloat() < probability); } }
/// <summary> /// Fill a span with samples from the uniform distribution with interval [0, 1). /// </summary> /// <param name="rng">Random source.</param> /// <param name="span">The span to fill with samples.</param> public static void Sample(IRandomSource rng, Span <float> span) { for (int i = 0; i < span.Length; i++) { span[i] = rng.NextFloat(); } }
/// <summary> /// Fill an array with samples from the uniform distribution with interval [0, 1). /// </summary> /// <param name="rng">Random source.</param> /// <param name="buf">The array to fill with samples.</param> public static void Sample(IRandomSource rng, float[] buf) { for (int i = 0; i < buf.Length; i++) { buf[i] = rng.NextFloat(); } }
/// <summary> /// Fill an array with samples from the uniform distribution with interval [0, max). /// </summary> /// <param name="rng">Random source.</param> /// <param name="max">Maximum value (exclusive).</param> /// <param name="buf">The array to fill with samples.</param> public static void Sample(IRandomSource rng, float max, float[] buf) { Debug.Assert(max >= 0.0); for (int i = 0; i < buf.Length; i++) { buf[i] = rng.NextFloat() * max; } }
/// <summary> /// Fill a span with samples from the uniform distribution with interval [0, max). /// </summary> /// <param name="rng">Random source.</param> /// <param name="max">Maximum value (exclusive).</param> /// <param name="span">The span to fill with samples.</param> public static void Sample(IRandomSource rng, float max, Span <float> span) { Debug.Assert(max >= 0.0); for (int i = 0; i < span.Length; i++) { span[i] = rng.NextFloat() * max; } }
/// <summary> /// Take a sample from the uniform distribution with interval (-1, 1). /// </summary> /// <param name="rng">Random source.</param> /// <returns>A random sample.</returns> public static float SampleSigned(IRandomSource rng) { float sample = rng.NextFloat(); if (rng.NextBool()) { sample *= -1.0f; } return(sample); }
/// <summary> /// Take a sample from the standard Gaussian distribution, i.e. with mean of 0 and standard deviation of 1. /// </summary> /// <param name="rng">Random source.</param> /// <returns>A pair of random samples (because the Box-Muller transform generates samples in pairs).</returns> public static (float, float) Sample(IRandomSource rng) { // Generate two new Gaussian values. float x, y, sqr; // We need a non-zero random point inside the unit circle. do { x = (2f * rng.NextFloat()) - 1f; y = (2f * rng.NextFloat()) - 1f; sqr = (x * x) + (y * y); }while(sqr > 1f || sqr == 0f); // Make the Box-Muller transformation. float fac = MathF.Sqrt((-2f * MathF.Log(sqr)) / sqr); // Return two samples. return(x * fac, y *fac); }
/// <summary> /// Returns a random value sampled from the standard Gaussian distribution, i.e., with mean of 0 and standard deviation of 1. /// </summary> /// <param name="rng">Random source.</param> /// <returns>A new random sample.</returns> public static float Sample(IRandomSource rng) { for (;;) { // Generate 64 random bits. ulong u = rng.NextULong(); // Note. 32 random bits are required and therefore the lowest 32 bits are discarded // (a typical characteristic of PRNGs is that the least significant bits exhibit lower // quality randomness than the higher bits). // Select a segment (7 bits, bits 32 to 38). int s = (int)((u >> 32) & 0x7f); // Select the sign bit (bit 39), and convert to a single-precision float value of -1.0 or +1.0 accordingly. // Notes. // Here we convert the single chosen bit directly into IEEE754 single-precision floating-point format. // Previously this conversion used a branch, which is considerably slower because modern superscalar // CPUs rely heavily on branch prediction, but the outcome of this branch is pure random noise and thus // entirely unpredictable, i.e. the absolute worse case scenario! float sign = BitConverter.Int32BitsToSingle(unchecked ((int)(((u & 0x80_0000_0000UL) >> 8) | __oneBits))); // Get a uniform random value with interval [0, 2^24-1], or in hexadecimal [0, 0xff_ffff] // (i.e. a random 24 bit number) (bits 40 to 63). ulong u2 = u >> 40; // Special case for the base segment. if (s == 0) { if (u2 < __xComp[0]) { // Generated x is within R0. return(u2 * __INCR * __A_Div_Y0 * sign); } // Generated x is in the tail of the distribution. return(SampleTail(rng) * sign); } // All other segments. if (u2 < __xComp[s]) { // Generated x is within the rectangle. return(u2 * __INCR * __x[s] * sign); } // Generated x is outside of the rectangle. // Generate a random y coordinate and test if our (x,y) is within the distribution curve. // This execution path is relatively slow/expensive (makes a call to Math.Exp()) but is relatively rarely executed, // although more often than the 'tail' path (above). float x = u2 * __INCR * __x[s]; if (__y[s - 1] + ((__y[s] - __y[s - 1]) * rng.NextFloat()) < GaussianPdfDenormF(x)) { return(x * sign); } } }
/// <summary> /// Fill a span with samples from the uniform distribution with interval [min, max). /// </summary> /// <param name="rng">Random source.</param> /// <param name="min">Minimum value (inclusive).</param> /// <param name="max">Maximum value (exclusive).</param> /// <param name="span">The span to fill with samples.</param> public static void Sample(IRandomSource rng, float min, float max, Span <float> span) { Debug.Assert(max >= min); float delta = max - min; for (int i = 0; i < span.Length; i++) { span[i] = min + (rng.NextFloat() * delta); } }
/// <summary> /// Fill an array with samples from the uniform distribution with interval [min, max). /// </summary> /// <param name="rng">Random source.</param> /// <param name="min">Minimum value (inclusive).</param> /// <param name="max">Maximum value (exclusive).</param> /// <param name="buf">The array to fill with samples.</param> public static void Sample(IRandomSource rng, float min, float max, float[] buf) { Debug.Assert(max >= min); float delta = max - min; for (int i = 0; i < buf.Length; i++) { buf[i] = min + (rng.NextFloat() * delta); } }
/// <summary> /// Take a sample from the uniform distribution with interval (-max, max). /// </summary> /// <param name="rng">Random source.</param> /// <param name="max">Maximum absolute value (exclusive).</param> /// <returns>A random sample.</returns> public static float SampleSigned(IRandomSource rng, float max) { Debug.Assert(max >= 0.0); float sample = rng.NextFloat() * max; if (rng.NextBool()) { sample *= -1.0f; } return(sample); }
/// <summary> /// Fill an array with samples from the uniform distribution with interval (-max, max). /// </summary> /// <param name="rng">Random source.</param> /// <param name="max">Maximum absolute value (exclusive).</param> /// <param name="buf">The array to fill with samples.</param> public static void SampleSigned(IRandomSource rng, float max, float[] buf) { Debug.Assert(max >= 0.0); for (int i = 0; i < buf.Length; i++) { float sample = rng.NextFloat() * max; if (rng.NextBool()) { sample *= -1.0f; } buf[i] = sample; } }
/// <summary> /// Sample from the provided discrete probability distribution. /// </summary> /// <param name="rng">Random source.</param> /// <param name="dist">The discrete distribution to sample from.</param> /// <returns>A sample from the discrete distribution.</returns> public static int Sample(IRandomSource rng, DiscreteDistribution dist) { float[] pArr = dist.Probabilities; // Obtain a random threshold value by sampling uniformly from interval [0,1). float thresh = rng.NextFloat(); // ENHANCEMENT: Precalc running sum over pArr, and use binary search over pArr if its length is > 10 (or thereabouts). // Loop through the discrete probabilities, accumulating as we go and stopping once // the accumulator is greater than the random sample. float acc = 0f; for (int i = 0; i < pArr.Length; i++) { acc += pArr[i]; if (acc > thresh) { return(dist.Labels[i]); } } // We might get here through floating point arithmetic rounding issues. // e.g. accumulator == throwValue. // Find a nearby non-zero probability to select. // Wrap around to start of array. for (int i = 0; i < pArr.Length; i++) { if (pArr[i] != 0.0) { return(dist.Labels[i]); } } // If we get here then we have an array of zero probabilities. throw new InvalidOperationException("Invalid operation. No non-zero probabilities to select."); }
/// <summary> /// Take a sample from the uniform distribution with interval [0, max). /// </summary> /// <param name="rng">Random source.</param> /// <param name="max">Maximum value (exclusive).</param> /// <returns>A random sample.</returns> public static float Sample(IRandomSource rng, float max) { Debug.Assert(max >= 0.0); return(rng.NextFloat() * max); }
/// <summary> /// Add objects to the Box2d world. /// </summary> protected override void PopulateWorld() { // ==== Define the ground body ==== BodyDef groundBodyDef = new BodyDef(); groundBodyDef.Position.Set(_trackLengthHalf, -1f); // Call the body factory which creates the ground box shape. // The body is also added to the world. Body groundBody = _world.CreateBody(groundBodyDef); // Define the ground box shape. PolygonDef groundShapeDef = new PolygonDef(); // The extents are the half-widths of the box. groundShapeDef.SetAsBox(_trackLengthHalf + 1f, 1f); groundShapeDef.Friction = _simParams._defaultFriction; groundShapeDef.Restitution = _simParams._defaultRestitution; groundShapeDef.Filter.CategoryBits = 0x3; // Add the ground shape to the ground body. groundBody.CreateShape(groundShapeDef); // Add some small mounds/bumps to the ground. for (float x = -1f; x < 40f; x += 0.4f + ((_rng.NextFloat() - 0.5f) * 0.15f)) { WalkerWorldUtils.CreateMound(_world, x, 0f, _simParams._defaultFriction, _simParams._defaultRestitution); } // ==== Define walker torso. float walkerX = 0f; float walkerY = 1.30f;// + ((float)_rng.NextDouble() * 0.1f); BodyDef torsoBodyDef = new BodyDef(); torsoBodyDef.Position.Set(walkerX, walkerY); torsoBodyDef.IsBullet = true; // Create walker torso. _torsoBody = _world.CreateBody(torsoBodyDef); PolygonDef torsoShapeDef = new PolygonDef(); torsoShapeDef.SetAsBox(0.10f, 0.30f); torsoShapeDef.Friction = _simParams._defaultFriction; torsoShapeDef.Restitution = 0f; torsoShapeDef.Density = 2f; torsoShapeDef.Filter.CategoryBits = 0x2; _torsoBody.CreateShape(torsoShapeDef); _torsoBody.SetMassFromShapes(); // ===== Create legs. // Leg joint definition. RevoluteJointDef jointDef = new RevoluteJointDef(); jointDef.CollideConnected = false; jointDef.EnableMotor = true; jointDef.MaxMotorTorque = 0f; // Other re-usable stuff . const float legRadius = 0.05f; // Half the thickness of the leg Vec2 upperLegPosBase = new Vec2(walkerX, walkerY - 0.25f); Vec2 lowerLegPosBase = new Vec2(walkerX, walkerY - 0.75f); // ===== Create left leg. // Upper leg. Body upperLeftLegBody = CreatePole(upperLegPosBase, 0.5f, (float)SysMath.PI, legRadius, 2f, 0x1); // Join to torso (hip joint) jointDef.Initialize(_torsoBody, upperLeftLegBody, upperLegPosBase); _leftHipJoint = (RevoluteJoint)_world.CreateJoint(jointDef); // Lower leg. _leftLowerLegBody = CreatePole(lowerLegPosBase, __lowerLegLength, (float)SysMath.PI, legRadius, 2f, 0x1); // Join to upper leg (knee joint) jointDef.Initialize(upperLeftLegBody, _leftLowerLegBody, lowerLegPosBase); _leftKneeJoint = (RevoluteJoint)_world.CreateJoint(jointDef); // ===== Create right leg. // Upper leg. Body upperRightLegBody = CreatePole(upperLegPosBase, 0.5f, (float)SysMath.PI, legRadius, 2f, 0x1); // Join to torso (hip joint) jointDef.Initialize(_torsoBody, upperRightLegBody, upperLegPosBase); _rightHipJoint = (RevoluteJoint)_world.CreateJoint(jointDef); // Lower leg. _rightLowerLegBody = CreatePole(lowerLegPosBase, __lowerLegLength, (float)SysMath.PI, legRadius, 2f, 0x1); // Join to upper leg (knee joint) jointDef.Initialize(upperRightLegBody, _rightLowerLegBody, lowerLegPosBase); _rightKneeJoint = (RevoluteJoint)_world.CreateJoint(jointDef); }
/// <summary> /// Sample from a binary/Bernoulli distribution with the given probaility of sampling 'true'. /// </summary> /// <param name="rng">Random number generator.</param> /// <param name="probability">Probability of sampling boolean true.</param> /// <returns>A boolean random sample.</returns> public static bool SampleBernoulli(IRandomSource rng, float probability) { return(rng.NextFloat() < probability); }
/// <summary> /// Get a sample from the uniform distribution with interval [0, scale). /// </summary> public float Sample(float scale) { return(_rng.NextFloat() * scale); }
/// <summary> /// Take a sample from the uniform distribution with interval [min, max). /// </summary> /// <param name="rng">Random source.</param> /// <param name="min">Minimum value (inclusive).</param> /// <param name="max">Maximum value (exclusive).</param> /// <returns>A random sample.</returns> public static float Sample(IRandomSource rng, float min, float max) { Debug.Assert(max >= min); return(min + (rng.NextFloat() * (max - min))); }
/// <summary> /// Take a sample from the uniform distribution with interval [0, 1). /// </summary> /// <param name="rng">Random source.</param> /// <returns>A random sample.</returns> public static float Sample(IRandomSource rng) { return(rng.NextFloat()); }