agentscape
Version:
Agentscape is a library for creating agent-based simulations. It provides a simple API for defining agents and their behavior, and for defining the environment in which the agents interact. Agentscape is designed to be flexible and extensible, allowing
144 lines (127 loc) • 4.26 kB
text/typescript
import prand from 'pure-rand'
export default class RandomGenerator {
private generator: prand.RandomGenerator
public seed: number
constructor(seed?: number) {
this.seed = seed ?? Date.now() ^ (Math.random() * 0x100000000)
this.generator = prand.xoroshiro128plus(seed)
}
public jump(): void {
this.generator = this.generator.jump()
}
/**
* Returns a uniformly distributed random integer between min and max
*/
public uniformInt(min: number, max: number): number {
const [value, rng] = prand.uniformIntDistribution(min, max)(this.generator)
this.generator = rng
return value
}
/**
* Returns an array of uniformly distributed random integers between min and max
*/
public uniformIntArray(min: number, max: number, size: number): number[] {
const result: number[] = []
for (let i = 0; i < size; i++) {
result.push(this.uniformInt(min, max))
}
return result
}
/*
* Returns a uniformly distributed random float between min and max
*/
public uniformFloat(min: number, max: number) {
const [value, rng] = prand.uniformIntDistribution(min * 1000, max * 1000)(this.generator)
this.generator = rng
return value / 1000
}
/**
* Returns an array of uniformly distributed random floats between min and max.
*/
public uniformFloatArray(min: number, max: number, size: number): number[] {
const result: number[] = []
for (let i = 0; i < size; i++) {
result.push(this.uniformFloat(min, max))
}
return result
}
/**
* Returns a normally distributed random number with mean mu and standard deviation sigma.
*/
public normalFloat(mu: number, sigma: number): number {
let u = 0, v = 0
while(u === 0) u = 1 - this.uniformFloat(0, 1)
while(v === 0) v = this.uniformFloat(0, 1)
return sigma * Math.sqrt( -2.0 * Math.log( u ) ) * Math.cos( 2.0 * Math.PI * v ) + mu
}
/**
* Returns an array of normally distributed random numbers with mean mu and standard deviation sigma.
*/
public normalFloatArray(mu: number, sigma: number, size: number): number[] {
const result: number[] = []
for (let i = 0; i < size; i++) {
result.push(this.normalFloat(mu, sigma))
}
return result
}
/**
* Returns a Poisson distributed random number with mean lambda.
*/
public poissonInt(lambda: number): number {
const L = Math.exp(-lambda)
let k = 0
let p = 1
do {
k++
p *= this.uniformFloat(0, 1)
} while (p > L)
return k - 1
}
/**
* Returns an array of Poisson distributed random numbers with mean lambda.
*/
public poissonIntArray(lambda: number, size: number): number[] {
const result: number[] = []
for (let i = 0; i < size; i++) {
result.push(this.poissonInt(lambda))
}
return result
}
/**
* Picks a single random element from the array.
* Returns undefined if the array is empty.
*/
public pickRandom<T>(array: T[]): T {
if (array.length === 0) {
return undefined
}
return array[this.uniformInt(0, array.length - 1)]
}
/**
* Picks a random subset of the array without replacement.
* Returns an empty array if the array is empty.
*/
public pickRandomArray<T>(array: T[], size: number): T[] {
if (array.length === 0) {
return []
}
const result: T[] = []
const copy = array.slice()
for (let i = 0; i < size; i++) {
const index = this.uniformInt(0, copy.length - 1)
result.push(copy[index])
copy.splice(index, 1)
}
return result
}
public shuffle<T>(array: T[]): T[] {
const result = array.slice()
for (let i = result.length - 1; i > 0; i--) {
const j = this.uniformInt(0, i)
const temp = result[i]
result[i] = result[j]
result[j] = temp
}
return result
}
}