Skip to content

Commit

Permalink
Adding more pseudo algoritmns
Browse files Browse the repository at this point in the history
  • Loading branch information
Gekctek committed Aug 2, 2024
1 parent 4c62eb5 commit 2c37ba0
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 74 deletions.
6 changes: 0 additions & 6 deletions Makefile

This file was deleted.

14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ getCurrentSeed : () -> Nat32

#### nextInt

Generates a random integer within the specified range (inclusive).
Generates a random integer within the specified range (exclusive).

```motoko
nextInt : (min : Int, max : Int) -> Int
```

#### nextNat

Generates a random natural number within the specified range (inclusive).
Generates a random natural number within the specified range (exclusive).

```motoko
nextNat : (min : Nat, max : Nat) -> Nat
Expand Down Expand Up @@ -137,14 +137,14 @@ Here are some examples of how to use the Pseudo Random Number Generator:
let prng = PseudoRandomX.fromSeed(0);
let randomInt = prng.nextInt(1, 10);
Debug.print("Random integer between 1 and 10 (inclusive): " # Int.toText(randomInt));
Debug.print("Random integer between 1 and 10 (exclusive): " # Int.toText(randomInt));
let randomCoin = prng.nextCoin();
Debug.print("Random coin flip: " # Bool.toText(randomCoin));
let randomFloat = prng.nextFloat(0.0, 1.0);
Debug.print("Random float between 0.0 and 1.0 (inclusive): " # Float.toText(randomFloat));
Debug.print("Random float between 0.0 and 1.0 (exclusive): " # Float.toText(randomFloat));
let buffer = Buffer.fromArray<Nat>([1, 2, 3, 4, 5]);
prng.shuffleBuffer(buffer);
Expand Down Expand Up @@ -205,15 +205,15 @@ nextRatio : (trueCount : Nat, totalCount : Nat) -> ?Bool

#### nextInt

Generates a random integer within the specified range (inclusive).
Generates a random integer within the specified range (exclusive).

```motoko
nextInt : (min : Int, max : Int) -> ?Int
```

#### nextNat

Generates a random natural number within the specified range (inclusive).
Generates a random natural number within the specified range (exclusive).

```motoko
nextNat : (min : Nat, max : Nat) -> ?Nat
Expand All @@ -235,7 +235,7 @@ Here are some examples of how to use the Finite Random Number Generator:
let entropy : Blob = ...; // Initialize with a proper seed
let randomGen = RandomX.fromEntropy(seed);
let ?randomInt = randomGen.nextInt(1, 10) else return #err("Not enough entropy");
Debug.print("Random integer between 1 and 10 (inclusive): " # Int.toText(randomInt));
Debug.print("Random integer between 1 and 10 (exclusive): " # Int.toText(randomInt));
let ?randomCoin = randomGen.nextCoin() else return #err("Not enough entropy");
Debug.print("Random coin flip: " # Bool.toText(randomCoin));
Expand Down
4 changes: 2 additions & 2 deletions mops.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[dependencies]
base = "0.11.1"
base = "0.12.0"

[package]
name = "xtended-random"
version = "0.1.0"
version = "1.0.0"
description = "A library for random helper funtions"
repository = "https://github.com/edjcase/motoko_random"
keywords = [ "random", "pseudo" ]
Expand Down
72 changes: 48 additions & 24 deletions src/PseudoRandomX.mo
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,25 @@ module {
shuffleBuffer : <T>(buffer : Buffer.Buffer<T>) -> ();
};

/// The kinds of pseudo-random number generation algorithms available.
/// - `#linearCongruential`: A simple and fast generator. Good for basic uses where speed is
/// prioritized over randomness quality
/// - `#xorshift32`: Offers a good balance of speed and randomness quality. Better statistical
/// properties than linear congruential
public type PseudoRandomKind = {
#linearCongruential;
#xorshift32;
};

/// Creates a new PseudoRandomGenerator from a Blob.
///
/// ```motoko include=import
/// let blob : Blob = ...;
/// let prng = PseudoRandom.fromBlob(blob);
/// ```
public func fromBlob(blob : Blob) : PseudoRandomGenerator {
public func fromBlob(blob : Blob, kind : PseudoRandomKind) : PseudoRandomGenerator {
let seed = convertBlobToSeed(blob);
LinearCongruentialGenerator(seed);
DefaultPseudoRandomGenerator(seed, kind);
};

/// Converts a Blob to a 32-bit seed for the random number generator.
Expand Down Expand Up @@ -76,49 +86,63 @@ module {
/// let seed : Nat32 = 12345;
/// let prng = PseudoRandom.fromSeed(seed);
/// ```
public func fromSeed(seed : Nat32) : PseudoRandomGenerator {
LinearCongruentialGenerator(seed);
public func fromSeed(seed : Nat32, kind : PseudoRandomKind) : PseudoRandomGenerator {
DefaultPseudoRandomGenerator(seed, kind);
};

/// Implements a Linear Congruential Generator for pseudo-random number generation.
public class LinearCongruentialGenerator(seed : Nat32) : PseudoRandomGenerator {
/// Implements the specified algorithm kinds for pseudo-random number generation.
public class DefaultPseudoRandomGenerator(seed : Nat32, kind : PseudoRandomKind) : PseudoRandomGenerator {
var currentSeed = seed;
let a : Nat32 = 1664525;
let c : Nat32 = 1013904223;

let nextSeedInternal = switch (kind) {
case (#linearCongruential) func() : Nat32 {
let a : Nat32 = 1664525;
let c : Nat32 = 1013904223;
currentSeed
|> Nat32.mulWrap(a, _)
|> Nat32.addWrap(_, c); // Overflow is ok
};
case (#xorshift32) func() : Nat32 {
var seed = currentSeed;
seed := seed ^ (seed << 13);
seed := seed ^ (seed >> 17);
seed := seed ^ (seed << 5);
seed;
};
};

/// Generates the next seed in the sequence.
private func nextSeed() : Nat32 {
currentSeed := currentSeed
|> Nat32.mulWrap(a, _)
|> Nat32.addWrap(_, c); // Overflow is ok
return currentSeed;
let nextSeed = func() : Nat32 {
let newSeed = nextSeedInternal();
currentSeed := newSeed;
newSeed;
};

/// Returns the current seed of the generator.
public func getCurrentSeed() : Nat32 {
currentSeed;
};

/// Generates a random integer within the specified range (inclusive).
/// Generates a random integer within the specified range (exclusive).
///
/// ```motoko include=import
/// let prng : PseudoRandomGenerator = ...;
/// let randomInt = prng.nextInt(1, 10);
/// let randomInt = prng.nextInt(0, 10); // [0, 10)
/// ```
public func nextInt(min : Int, max : Int) : Int {
if (min > max) {
Debug.trap("Min cannot be larger than max");
if (min >= max) {
Debug.trap("Max must be larger than min");
};
let randNat32 = nextSeed();
let rangeSize = max - min + 1;
let rangeSize = max - min;
min + (Nat32.toNat(randNat32) % rangeSize);
};

/// Generates a random natural number within the specified range (inclusive).
///
/// ```motoko include=import
/// let prng : PseudoRandomGenerator = ...;
/// let randomNat = prng.nextNat(1, 10);
/// let randomNat = prng.nextNat(0, 10); // [0, 10)
/// ```
public func nextNat(min : Nat, max : Nat) : Nat {
let randInt = nextInt(min, max);
Expand All @@ -139,7 +163,7 @@ module {
///
/// ```motoko include=import
/// let prng : PseudoRandomGenerator = ...;
/// let randomFloat = prng.nextFloat(0.0, 1.0);
/// let randomFloat = prng.nextFloat(0.0, 1.0); // [0.0, 1.0)
/// ```
public func nextFloat(min : Float, max : Float) : Float {
if (min > max) {
Expand All @@ -165,7 +189,7 @@ module {
if (trueCount > totalCount) {
Debug.trap("True count cannot be larger than total count");
};
let randomValue = nextNat(1, totalCount);
let randomValue = nextNat(1, totalCount + 1);
return randomValue <= trueCount;
};

Expand All @@ -181,7 +205,7 @@ module {
if (bufferSize == 0) {
Debug.trap("Cannot get random element from an empty buffer");
};
let randomIndex = nextNat(0, bufferSize - 1);
let randomIndex = nextNat(0, bufferSize);
buffer.get(randomIndex);
};

Expand All @@ -197,7 +221,7 @@ module {
if (arraySize == 0) {
Debug.trap("Cannot get random element from an empty array");
};
let randomIndex = nextNat(0, arraySize - 1);
let randomIndex = nextNat(0, arraySize);
array[randomIndex];
};

Expand Down Expand Up @@ -263,7 +287,7 @@ module {
var i : Nat = bufferSize;
for (item in buffer.vals()) {
i -= 1;
let randomIndex = nextNat(0, i);
let randomIndex = nextNat(0, i + 1);
let temp = buffer.get(i);
buffer.put(i, buffer.get(randomIndex));
buffer.put(randomIndex, temp);
Expand Down
Loading

0 comments on commit 2c37ba0

Please sign in to comment.