Can't get Lotka-Volterra equations to oscillate stable with math.js - javascript

I'm trying to implement a simple Lotka-Volterra system in JavaScript, but get different result from what I see in academic papers and slides. This is my equations:
sim2.eval("dxdt(x, y) = (2 * x) - (x * y)");
sim2.eval("dydt(x, y) = (-0.25 * y) + (x * y)");
using coefficients a = 2, b = 1, c = 0.25 and d = 1. Yet, my result looks like this:
when I expected a stable oscillation as seen in these PDF slides:
Could it be the implementation of ndsolve that causes this? Or a machine error in JavaScript due to floating-point arithmetic?

Disregard, the error was simply using a too big evaluation step (dt = 0.1, must be 0.01 at least). The numerical method used is known for this problem.

For serious purposes use a higher order method, the minimum is fixed step classical Runge-Kutta. Then you can also use dt=0.1, it is stable for multiple periods, I tried tfinal=300 without problems. However you will see the step size in the graph as it is visibly piecewise linear. This is much reduced with half the step size, dt=0.05.
function odesolveRK4(f, x0, dt, tmax) {
var n = f.size()[0]; // Number of variables
var x = x0.clone(),xh=[]; // Current values of variables
var dxdt = [], k1=[], k2=[], k3=[], k4=[]; // Temporary variable to hold time-derivatives
var result = []; // Contains entire solution
var nsteps = math.divide(tmax, dt); // Number of time steps
dt2 = math.divide(dt,2);
dt6 = math.divide(dt,6);
for(var i=0; i<nsteps; i++) {
// compute the 4 stages if the classical order-4 Runge-Kutta method
k1 = f.map(function(fj) {return fj.apply(null, x.toArray()); } );
xh = math.add(x, math.multiply(k1, dt2));
k2 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
xh = math.add(x, math.multiply(k2, dt2));
k3 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
xh = math.add(x, math.multiply(k3, dt));
k4 = f.map(function(fj) {return fj.apply(null, xh.toArray()); } );
x = math.add(x, math.multiply(math.add(math.add(k1,k4), math.multiply(math.add(k2,k3),2)), dt6))
if( 0==i%50) console.log("%3d %o %o",i,dt,x.toString());
result.push(x.clone());
}
return math.matrix(result);
}
math.import({odesolveRK4:odesolveRK4});

Related

Outputs of feed-forward neural network approach 0

I am trying to create a simple feed-forward neural network in JavaScript using a tutorial found here. I believe that I followed the tutorial correctly, as when I trained it with an input matrix of [[0,0,1],[0,1,1],[1,0,1],[1,1,1]] and a solution matrix of [[0],[1],[1],[0]] the network performed as expected. However, when I tried to train the network using the MNIST handwritten number database and passing in larger matrices, all of the elements in the output array approached zero. I suspect that this has to do with the dot product of the input array and the weights returning an array filled with large numbers, but my attempts to scale down these number have caused the outputs to approach 1. Would anybody be able to figure out what is going wrong? My neural network has only one hidden layer with 300 neurons. The code snippet below shows the methods for my neural network, because I believe that that is where I am going wrong, but if you want to see my entire messy, undocumented program, it can be found here. I am unfamiliar with the math library that I am using, which means that I made some of my own methods to go along with the math methods.
multMatrices(a, b) returns the product of matrices a and b.
math.multiply(a, b) returns the dot product of the two matrices.
math.add(a, b) and math.subtract(a, b) perform matrix addition and subtraction, and
transposeMatrix(a) returns the transpose of matrix a.
setAll(a, b) performs an operation on every element of matrix a, be it plugging the element into the sigmoid function (1 / (1 + a^-e)) in the case of "sigmoid" or the sigmoid derivative function (a * (1-a)) in the case of "sigmoidDerivitive", or setting it equal to a random value between 0 and 0.05 in the case of "randomlow".
I found that setting weights to a value between 0 and 1 kept the loss at 0.9, so I set them now using "randomlow".
function NeuralNetwork(x, y){
//Initializing the neural network
this.input = x;
this.y = y;
this.sizes = [this.input._size[1], 300, this.y._size[1]];
this.layers = this.sizes.length - 1;
this.lyrs = [this.input];
this.weights = [];
this.dweights = [];
for(var i = 0; i < this.layers; i ++){
this.weights.push(new math.matrix());
this.weights[i].resize([this.sizes[i], this.sizes[i + 1]]);
this.weights[i] = setAll(this.weights[i], "randomlow");
}
this.output = new math.matrix();
this.output.resize(this.y._size);
};
NeuralNetwork.prototype.set = function(x, y){
//I train the network by looping through values from the database and passing them into this function
this.input = x;
this.lyrs = [this.input];
this.y = y;
};
NeuralNetwork.prototype.feedforward = function(){
//Looping through the layers and multiplying them by their respective weights
for(var i = 0; i < this.weights.length; i ++){
this.lyrs[i + 1] = math.multiply(this.lyrs[i], this.weights[i]);
this.lyrs[i + 1] = setAll(this.lyrs[i + 1], "sigmoid");
}
this.output = this.lyrs[this.lyrs.length - 1];
};
NeuralNetwork.prototype.backpropogate = function(){
//Backpropogating the network. I don't fully understand this part
this.antis = [
function(a, b, c){
return(
math.multiply(transposeMatrix(a[0]), multMatrices(math.multiply(multMatrices(math.multiply(math.subtract(b.y, b.output), 2), setAll(b.output, "sigmoidDerivitive")), transposeMatrix(c)), setAll(a[1], "sigmoidDerivitive")))
);
},
function(a, b, c){
return(
math.multiply(transposeMatrix(a[0]), multMatrices(math.multiply(math.subtract(b.y, b.output), 2), setAll(b.output, "sigmoidDerivitive")))
);
}];
this.input = [];
this.weightInput = 0;
for(var i = this.weights.length - 1; i >= 0; --i){
this.input.unshift(this.lyrs[i]);
this.weightInput = (i === this.weights.length - 1 ? 0 : this.weights[i + 1]);
this.dweights[i] = this.antis[i](this.input, this, this.weightInput);
}
for(var i = 0; i < this.dweights.length; i ++){
this.weights[i] = math.add(this.weights[i], this.dweights[i]);
}
};
As always, I appreciate any time spent trying to solve my problem. If my code is unintelligible, don't bother with it. JavaScript probably isn't the best language for this purpose, but I didn't want to follow a tutorial with the same language.
EDIT: This is a potential duplicate of this post, which was answered. If anybody is facing this problem, they should see if the answer over there is of help. As of now I have not tested it with my program.

JavaScript Pattern Comparison

I'm working on a small machine learning theoretical algorithm using nodeJs.
My goal is to compare many array patterns to one source pattern then return how
similar they are represented as a percent . For an example pattern1 maybe 80% similar to the source pattern .
What can be the best method for determining percent similarity for one array to another?
What I've done so far..
//source
var soureSequence = [0.53,0.55,0.50,0.40,0.50,0.52,0.58,0.60]
//patterns to compare
var sequence1 = [0.53,0.54,0.49,0.40,0.50,0.52,0.58,0.60]
var sequence2 = [0.53,0.55,0.50,0.42,0.50,0.53,0.57,0.62]
Since I've chosen a percent based outcome , I figured I should base my source pattern off percentage change from first value to second value in array .
var percentChange = (firstVal, secondVal) => {
var pChange = ((parseFloat(secondVal) - firstVal) /
Math.abs(firstVal)) * 100.00;
//To avoid NaN , Infinity , and Zero
if(!pChange || pChange == 0){
return 0.00000001
}
return pChange;
}
Here I will generate my source pattern from my source sequence
var storePattern = function(sequence){
var pattern = [];
for(var i = 0 ; i < sequence.length ; i++){
let $change = percentChange(sequence[i] , sequence[i + 1]);
if(i != sequence.length && $change ){
pattern.push($change)
}
}
return pattern;
}
var sourcePattern = storePattern(soureSequence);
Now I will create more patterns to be compared
var testPattern1 = storePattern(sequence1);
var testPattern2 = storePattern(sequence2);
Below is my comparison function
var processPattern = function(source , target){
var simularityArray = [];
for(var i = 0 ; i < target.length ; i++){
//Compare percent change at indexof testPattern to sourcePattern of same index
let change = Math.abs(percentChange(target[i] , source[i]));
simularityArray.push(100.00 - change);
}
var rating = simularityArray.reduce((a,b) => {
return a + b
});
//returns percent rating based of average of similarity pattern
rating = rating / parseFloat(source.length + ".00");
return rating;
}
Now I can try to estimate the similarity
var similarityOfTest1 = processPattern(sourcePattern , testPattern1)
My problem is that this only works on sequences within the same range of value .. for example 0.50 , 0.52 .. the percent change in these values would not be the same for 0.20 , 0.22 but the value difference is the same ie -> 0.02
I thought about a difference in value based pattern but at this point I'm lost.
All answers will be considered . Thanks for the help!
used reduce to get the difference than the average.
//patterns to compare
var sequence1 = [0.53,0.54,0.49,0.40,0.50,0.52,0.58,0.60]
var sequence2 = [0.53,0.55,0.50,0.42,0.50,0.53,0.57,0.62]
function diff(sequence){
var soureSequence = [0.53,0.55,0.50,0.40,0.50,0.52,0.58,0.60]
var delta = soureSequence.reduce(function (r, a, i, aa) {
i && r.push(a - sequence[i]);
return r;
}, []),
average = delta.reduce(function (a, b) { return a + b; }) / delta.length;
return {delta:delta, average:average}
}
console.log('sequence1',diff(sequence1));
console.log('sequence2',diff(sequence2));
In my experience, the similarity of two vectors (arrays) is measured using the dot product ex. Like it says in that link, you multiply each corresponding elements of the arrays, add those up, then divide by the magnitude of each array (square root of the sum of the squares of each component). Rosetta Code has an example of the dot product in JavaScript, copied here
// dotProduct :: [Int] -> [Int] -> Int
const dotProduct = (xs, ys) => {
const sum = xs => xs ? xs.reduce((a, b) => a + b, 0) : undefined;
return xs.length === ys.length ? (
sum(zipWith((a, b) => a * b, xs, ys))
) : undefined;
}
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = (f, xs, ys) => {
const ny = ys.length;
return (xs.length <= ny ? xs : xs.slice(0, ny))
.map((x, i) => f(x, ys[i]));
}
So, you would call
const score1 = dotProduct(sourceSequence, sequence1);
const score2 = dotProduct(sourceSequence, sequence2);
And whichever is bigger is the closer sequence to sourceSequence.
I'm not sure you need machine learning for this. You have a source pattern and you have some inputs and you basically want to perform a diff of the patterns.
Machine learning could be used to find the patterns, assuming you have some heuristic for measuring the error (if you're using unsupervised learning techniques) or you have sample sets to train the network.
But if you are simply wanting to measure the differences between one pattern and another pattern then just perform a diff operation. What you'll need to do is decide what differences your measuring and how to normalize the result.
I can't tell how exactly you would like to measure the similarity. I go by calculating the difference of corresponding items and accumulating these differences to see how much deviation it would result from the sum of the source array. You can play with the calculation the way you like.
function check([x,...xs],[y,...ys], state = {sumSource: 0, sumDiff: 0}){
state.sumSource += x;
state.sumDiff += Math.abs(x-y);
return xs.length ? check(xs,ys,state) : (100 - 100 * state.sumDiff / state.sumSource).toFixed(4) + "% similarity";
}
var soureSequence = [0.53,0.55,0.50,0.40,0.50,0.52,0.58,0.60],
sequence1 = [0.53,0.54,0.49,0.40,0.50,0.52,0.58,0.60],
sequence2 = [0.53,0.55,0.50,0.42,0.50,0.53,0.57,0.62];
console.log(check(soureSequence,sequence1));
console.log(check(soureSequence,sequence2));

Seeking a statistical javascript function to return p-value from a z-score

I need to convert z-scores to percentile. I found reference to a function in the jStat library that I could use (jstat.ztest), but the jStat documentation seems to be ahead of the available library because there is no such function in the currently available version of the library.
I think there is a more recent version of the library on GitHub, which may include the ztest function, but I am a linux novice and could not figure out how to build the library from the instructions. I spent most of a day learning about git bash and cygwin trying to build the library; I finally decided I'd be better off asking here.
So, could anyone point me toward a javascript function that would do what I need?
Alternatively, could anyone point me toward a built version of the jStat library with ztest function included?
I found this in a forum online and it works like a charm.
function GetZPercent(z)
{
//z == number of standard deviations from the mean
//if z is greater than 6.5 standard deviations from the mean
//the number of significant digits will be outside of a reasonable
//range
if ( z < -6.5)
return 0.0;
if( z > 6.5)
return 1.0;
var factK = 1;
var sum = 0;
var term = 1;
var k = 0;
var loopStop = Math.exp(-23);
while(Math.abs(term) > loopStop)
{
term = .3989422804 * Math.pow(-1,k) * Math.pow(z,k) / (2 * k + 1) / Math.pow(2,k) * Math.pow(z,k+1) / factK;
sum += term;
k++;
factK *= k;
}
sum += 0.5;
return sum;
}
And I don't need to include a large library just for the one function.
Just editing the code from Paul's answer for a two-sided t-test
function GetZPercent(z)
{
//z == number of standard deviations from the mean
//if z is greater than 6.5 standard deviations from the mean
//the number of significant digits will be outside of a reasonable
//range
if ( z < -6.5)
return 0.0;
if( z > 6.5)
return 1.0;
if (z > 0) { z = -z;}
var factK = 1;
var sum = 0;
var term = 1;
var k = 0;
var loopStop = Math.exp(-23);
while(Math.abs(term) > loopStop)
{
term = .3989422804 * Math.pow(-1,k) * Math.pow(z,k) / (2 * k + 1) / Math.pow(2,k) * Math.pow(z,k+1) / factK;
sum += term;
k++;
factK *= k;
}
sum += 0.5;
return (2*sum);
}
This seems like such a simple ask but I had a hard time tracking down a library that does this instead of copying some random code snippet. Best I can tell this will calculate z-score from a percentage using the simple-statistics library.
I took their documentation about cumulativestdnormalprobability and backed into the following algorithm. Feels like there should be an easier way but who knows.
https://simplestatistics.org/docs/#cumulativestdnormalprobability
const z_score = inverseErrorFunction((percentile_value - 0.5) / 0.5) * Math.sqrt(2);
As already correctly stated by Shane, the equation is an implementation of the Taylor Expansion of the normal cdf. The sum value iterates above and below the "real" value with increasing precision. If the value is close to 1 or 0 there is a very low, but existing, probability that sum will be >1 or <0, because of the (relatively) early break by loopstop.
The deviation is further strengthened by rounding 1/Math.sqrt(2*Math.Pi) to 0.3989422804 and the precision issues of javascript float numbers. Additionally, the provided solution will not work for z-scores >7 or <-7
I updated the code to be more accurate using the decimal.js npm library and to directly return the p-value:
function GetpValueFromZ(_z, type = "twosided")
{
if(_z < -14)
{
_z = -14
}
else if(_z > 14)
{
_z = 14
}
Decimal.set({precision: 100});
let z = new Decimal(_z);
var sum = new Decimal(0);
var term = new Decimal(1);
var k = new Decimal(0);
var loopstop = new Decimal("10E-50");
var minusone = new Decimal(-1);
var two = new Decimal(2);
let pi = new Decimal("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647")
while(term.abs().greaterThan(loopstop))
{
term = new Decimal(1)
for (let i = 1; i <= k; i++) {
term = term.times(z).times(z.dividedBy(two.times(i)))
}
term = term.times(minusone.toPower(k)).dividedBy(k.times(2).plus(1))
sum = sum.plus(term);
k = k.plus(1);
}
sum = sum.times(z).dividedBy(two.times(pi).sqrt()).plus(0.5);
if(sum.lessThan(0))
sum = sum.abs();
else if(sum.greaterThan(1))
sum = two.minus(sum);
switch (type) {
case "left":
return parseFloat(sum.toExponential(40));
case "right":
return parseFloat((new Decimal(1).minus(sum)).toExponential(40));
case "twosided":
return sum.lessThan(0.5)? parseFloat(sum.times(two).toExponential(40)) : parseFloat((new Decimal(1).minus(sum).times(two)).toExponential(40))
}
}
By increasing the Decimal.js precision value and decreasing the loopstop value you can get accurate p-values for very small (or very high) z-scores for the cost of calculation time.

A random()-like function without random()

Can I write a JavaScript function from scratch that behaves like Math.random?
(By that I mean without using Math.random.)
Yes you can, you can implement your own LCG number generator, but as Sarnold mentions you need to maintain state between calls.
Per #OscarGomez's answer regarding a linear congruential generator, here's an example of a random number generator as a plain JavaScript function. Of course, its quality of "randomness" (currently very poor due to a short cycle) appears to be dependent on picking good values for the constants in the enclosed object "o".
var random = (function() {
var o = {mod: 13, mul: 11, inc: 7, x: 0};
return function() {
return o.x = (o.mul * o.x + o.inc) % o.mod
}
})();
random(); // => 7
random(); // => 6
random(); // => 8
random(); // => 4
Here's a more portable version which can have separate generator instances and seeds:
function Random(s) {
this.seed = s || 0;
this.mod = 13;
this.mul = 11;
this.inc = 7;
this.x = this.seed;
}
Random.prototype.next = function() {
return (this.x = (this.mul * this.x + this.inc) % this.mod);
};
var r = new Random(1);
r.next(); // => 5
r.next(); // => 10
r.next(); // => 7
What I usually do when I need some randomness but am to lazy to look up the syntax is to implement the logistic map (a discrete chaotic system). In pseudo code this is like this:
var x = 0.234; // or some other number between 0 and 1 ( but not 0.5 )
for (var n=1; n<=100;n++){
x = 4 * x * (1-x); // this is the iteration
console.log(x);
}
This would print 100 somehow random numbers, not really random but for many situations random enough.
Sorry for not giving a javascript answer, I havent used that for a decade.

Seedable JavaScript random number generator

The JavaScript Math.random() function returns a random value between 0 and 1, automatically seeded based on the current time (similar to Java I believe). However, I don't think there's any way to set you own seed for it.
How can I make a random number generator that I can provide my own seed value for, so that I can have it produce a repeatable sequence of (pseudo)random numbers?
One option is http://davidbau.com/seedrandom which is a seedable RC4-based Math.random() drop-in replacement with nice properties.
If you don't need the seeding capability just use Math.random() and build helper functions around it (eg. randRange(start, end)).
I'm not sure what RNG you're using, but it's best to know and document it so you're aware of its characteristics and limitations.
Like Starkii said, Mersenne Twister is a good PRNG, but it isn't easy to implement. If you want to do it yourself try implementing a LCG - it's very easy, has decent randomness qualities (not as good as Mersenne Twister), and you can use some of the popular constants.
EDIT: consider the great options at this answer for short seedable RNG implementations, including an LCG option.
function RNG(seed) {
// LCG using GCC's constants
this.m = 0x80000000; // 2**31;
this.a = 1103515245;
this.c = 12345;
this.state = seed ? seed : Math.floor(Math.random() * (this.m - 1));
}
RNG.prototype.nextInt = function() {
this.state = (this.a * this.state + this.c) % this.m;
return this.state;
}
RNG.prototype.nextFloat = function() {
// returns in range [0,1]
return this.nextInt() / (this.m - 1);
}
RNG.prototype.nextRange = function(start, end) {
// returns in range [start, end): including start, excluding end
// can't modulu nextInt because of weak randomness in lower bits
var rangeSize = end - start;
var randomUnder1 = this.nextInt() / this.m;
return start + Math.floor(randomUnder1 * rangeSize);
}
RNG.prototype.choice = function(array) {
return array[this.nextRange(0, array.length)];
}
var rng = new RNG(20);
for (var i = 0; i < 10; i++)
console.log(rng.nextRange(10, 50));
var digits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
for (var i = 0; i < 10; i++)
console.log(rng.choice(digits));
If you want to be able to specify the seed, you just need to replace the calls to getSeconds() and getMinutes(). You could pass in an int and use half of it mod 60 for the seconds value and the other half modulo 60 to give you the other part.
That being said, this method looks like garbage. Doing proper random number generation is very hard. The obvious problem with this is that the random number seed is based on seconds and minutes. To guess the seed and recreate your stream of random numbers only requires trying 3600 different second and minute combinations. It also means that there are only 3600 different possible seeds. This is correctable, but I'd be suspicious of this RNG from the start.
If you want to use a better RNG, try the Mersenne Twister. It is a well tested and fairly robust RNG with a huge orbit and excellent performance.
EDIT: I really should be correct and refer to this as a Pseudo Random Number Generator or PRNG.
"Anyone who uses arithmetic methods to produce random numbers is in a state of sin."
--- John von Neumann
I use a JavaScript port of the Mersenne Twister:
https://gist.github.com/300494
It allows you to set the seed manually. Also, as mentioned in other answers, the Mersenne Twister is a really good PRNG.
The code you listed kind of looks like a Lehmer RNG. If this is the case, then 2147483647 is the largest 32-bit signed integer, 2147483647 is the largest 32-bit prime, and 48271 is a full-period multiplier that is used to generate the numbers.
If this is true, you could modify RandomNumberGenerator to take in an extra parameter seed, and then set this.seed to seed; but you'd have to be careful to make sure the seed would result in a good distribution of random numbers (Lehmer can be weird like that) -- but most seeds will be fine.
The following is a PRNG that may be fed a custom seed. Calling SeedRandom will return a random generator function. SeedRandom can be called with no arguments in order to seed the returned random function with the current time, or it can be called with either 1 or 2 non-negative inters as arguments in order to seed it with those integers. Due to float point accuracy seeding with only 1 value will only allow the generator to be initiated to one of 2^53 different states.
The returned random generator function takes 1 integer argument named limit, the limit must be in the range 1 to 4294965886, the function will return a number in the range 0 to limit-1.
function SeedRandom(state1,state2){
var mod1=4294967087
var mul1=65539
var mod2=4294965887
var mul2=65537
if(typeof state1!="number"){
state1=+new Date()
}
if(typeof state2!="number"){
state2=state1
}
state1=state1%(mod1-1)+1
state2=state2%(mod2-1)+1
function random(limit){
state1=(state1*mul1)%mod1
state2=(state2*mul2)%mod2
if(state1<limit && state2<limit && state1<mod1%limit && state2<mod2%limit){
return random(limit)
}
return (state1+state2)%limit
}
return random
}
Example use:
var generator1=SeedRandom() //Seed with current time
var randomVariable=generator1(7) //Generate one of the numbers [0,1,2,3,4,5,6]
var generator2=SeedRandom(42) //Seed with a specific seed
var fixedVariable=generator2(7) //First value of this generator will always be
//1 because of the specific seed.
This generator exhibit the following properties:
It has approximately 2^64 different possible inner states.
It has a period of approximately 2^63, plenty more than anyone will ever realistically need in a JavaScript program.
Due to the mod values being primes there is no simple pattern in the output, no matter the chosen limit. This is unlike some simpler PRNGs that exhibit some quite systematic patterns.
It discards some results in order to get a perfect distribution no matter the limit.
It is relatively slow, runs around 10 000 000 times per second on my machine.
Bonus: typescript version
If you program in Typescript, I adapted the Mersenne Twister implementation that was brought in Christoph Henkelmann's answer to this thread as a typescript class:
/**
* copied almost directly from Mersenne Twister implementation found in https://gist.github.com/banksean/300494
* all rights reserved to him.
*/
export class Random {
static N = 624;
static M = 397;
static MATRIX_A = 0x9908b0df;
/* constant vector a */
static UPPER_MASK = 0x80000000;
/* most significant w-r bits */
static LOWER_MASK = 0x7fffffff;
/* least significant r bits */
mt = new Array(Random.N);
/* the array for the state vector */
mti = Random.N + 1;
/* mti==N+1 means mt[N] is not initialized */
constructor(seed:number = null) {
if (seed == null) {
seed = new Date().getTime();
}
this.init_genrand(seed);
}
private init_genrand(s:number) {
this.mt[0] = s >>> 0;
for (this.mti = 1; this.mti < Random.N; this.mti++) {
var s = this.mt[this.mti - 1] ^ (this.mt[this.mti - 1] >>> 30);
this.mt[this.mti] = (((((s & 0xffff0000) >>> 16) * 1812433253) << 16) + (s & 0x0000ffff) * 1812433253)
+ this.mti;
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
this.mt[this.mti] >>>= 0;
/* for >32 bit machines */
}
}
/**
* generates a random number on [0,0xffffffff]-interval
* #private
*/
private _nextInt32():number {
var y:number;
var mag01 = new Array(0x0, Random.MATRIX_A);
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (this.mti >= Random.N) { /* generate N words at one time */
var kk:number;
if (this.mti == Random.N + 1) /* if init_genrand() has not been called, */
this.init_genrand(5489);
/* a default initial seed is used */
for (kk = 0; kk < Random.N - Random.M; kk++) {
y = (this.mt[kk] & Random.UPPER_MASK) | (this.mt[kk + 1] & Random.LOWER_MASK);
this.mt[kk] = this.mt[kk + Random.M] ^ (y >>> 1) ^ mag01[y & 0x1];
}
for (; kk < Random.N - 1; kk++) {
y = (this.mt[kk] & Random.UPPER_MASK) | (this.mt[kk + 1] & Random.LOWER_MASK);
this.mt[kk] = this.mt[kk + (Random.M - Random.N)] ^ (y >>> 1) ^ mag01[y & 0x1];
}
y = (this.mt[Random.N - 1] & Random.UPPER_MASK) | (this.mt[0] & Random.LOWER_MASK);
this.mt[Random.N - 1] = this.mt[Random.M - 1] ^ (y >>> 1) ^ mag01[y & 0x1];
this.mti = 0;
}
y = this.mt[this.mti++];
/* Tempering */
y ^= (y >>> 11);
y ^= (y << 7) & 0x9d2c5680;
y ^= (y << 15) & 0xefc60000;
y ^= (y >>> 18);
return y >>> 0;
}
/**
* generates an int32 pseudo random number
* #param range: an optional [from, to] range, if not specified the result will be in range [0,0xffffffff]
* #return {number}
*/
nextInt32(range:[number, number] = null):number {
var result = this._nextInt32();
if (range == null) {
return result;
}
return (result % (range[1] - range[0])) + range[0];
}
/**
* generates a random number on [0,0x7fffffff]-interval
*/
nextInt31():number {
return (this._nextInt32() >>> 1);
}
/**
* generates a random number on [0,1]-real-interval
*/
nextNumber():number {
return this._nextInt32() * (1.0 / 4294967295.0);
}
/**
* generates a random number on [0,1) with 53-bit resolution
*/
nextNumber53():number {
var a = this._nextInt32() >>> 5, b = this._nextInt32() >>> 6;
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
}
}
you can than use it as follows:
var random = new Random(132);
random.nextInt32(); //return a pseudo random int32 number
random.nextInt32([10,20]); //return a pseudo random int in range [10,20]
random.nextNumber(); //return a a pseudo random number in range [0,1]
check the source for more methods.
Here is quite an effective but simple javascript PRNG function that I like to use:
// The seed is the base number that the function works off
// The modulo is the highest number that the function can return
function PRNG(seed, modulo) {
str = `${(2**31-1&Math.imul(48271,seed))/2**31}`
.split('')
.slice(-10)
.join('') % modulo
return str
}
I hope this is what you're looking for.
Thank you, #aaaaaaaaaaaa (Accepted Answer)
I really needed a good non-library solution (easier to embed)
so... i made this class to store the seed and allow a Unity-esque "Next" ... but kept the initial Integer based results
class randS {
constructor(seed=null) {
if(seed!=null) {
this.seed = seed;
} else {
this.seed = Date.now()%4645455524863;
}
this.next = this.SeedRandom(this.seed);
this.last = 0;
}
Init(seed=this.seed) {
if (seed = this.seed) {
this.next = this.SeedRandom(this.seed);
} else {
this.seed=seed;
this.next = this.SeedRandom(this.seed);
}
}
SeedRandom(state1,state2){
var mod1=4294967087;
var mod2=4294965887;
var mul1=65539;
var mul2=65537;
if(typeof state1!="number"){
state1=+new Date();
}
if(typeof state2!="number"){
state2=state1;
}
state1=state1%(mod1-1)+1;
state2=state2%(mod2-1)+1;
function random(limit){
state1=(state1*mul1)%mod1;
state2=(state2*mul2)%mod2;
if(state1<limit && state2<limit && state1<mod1%limit && state2<mod2%limit){
this.last = random;
return random(limit);
}
this.last = (state1+state2)%limit;
return (state1+state2)%limit;
}
this.last = random;
return random;
}
}
And then checked it with these... seems to work well with random (but queryable) seed value (a la Minecraft) and even stored the last value returned (if needed)
var rng = new randS(9005646549);
console.log(rng.next(20)+' '+rng.next(20)+' '+rng.next(20)+' '+rng.next(20)+' '+rng.next(20)+' '+rng.next(20)+' '+rng.next(20));
console.log(rng.next(20) + ' ' + rng.next(20) + ' ' + rng.last);
which should output (for everybody)
6 7 8 14 1 12 6
9 1 1
EDIT: I made the init() work if you ever needed to reseed, or were testing values (this was necessary in my context as well)
Note: This code was originally included in the question above. In the interests of keeping the question short and focused, I've moved it to this Community Wiki answer.
I found this code kicking around and it appears to work fine for getting a random number and then using the seed afterward but I'm not quite sure how the logic works (e.g. where the 2345678901, 48271 & 2147483647 numbers came from).
function nextRandomNumber(){
var hi = this.seed / this.Q;
var lo = this.seed % this.Q;
var test = this.A * lo - this.R * hi;
if(test > 0){
this.seed = test;
} else {
this.seed = test + this.M;
}
return (this.seed * this.oneOverM);
}
function RandomNumberGenerator(){
var d = new Date();
this.seed = 2345678901 + (d.getSeconds() * 0xFFFFFF) + (d.getMinutes() * 0xFFFF);
this.A = 48271;
this.M = 2147483647;
this.Q = this.M / this.A;
this.R = this.M % this.A;
this.oneOverM = 1.0 / this.M;
this.next = nextRandomNumber;
return this;
}
function createRandomNumber(Min, Max){
var rand = new RandomNumberGenerator();
return Math.round((Max-Min) * rand.next() + Min);
}
//Thus I can now do:
var letters = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
var numbers = ['1','2','3','4','5','6','7','8','9','10'];
var colors = ['red','orange','yellow','green','blue','indigo','violet'];
var first = letters[createRandomNumber(0, letters.length)];
var second = numbers[createRandomNumber(0, numbers.length)];
var third = colors[createRandomNumber(0, colors.length)];
alert("Today's show was brought to you by the letter: " + first + ", the number " + second + ", and the color " + third + "!");
/*
If I could pass my own seed into the createRandomNumber(min, max, seed);
function then I could reproduce a random output later if desired.
*/
OK, here's the solution I settled on.
First you create a seed value using the "newseed()" function. Then you pass the seed value to the "srandom()" function. Lastly, the "srandom()" function returns a pseudo random value between 0 and 1.
The crucial bit is that the seed value is stored inside an array. If it were simply an integer or float, the value would get overwritten each time the function were called, since the values of integers, floats, strings and so forth are stored directly in the stack versus just the pointers as in the case of arrays and other objects. Thus, it's possible for the value of the seed to remain persistent.
Finally, it is possible to define the "srandom()" function such that it is a method of the "Math" object, but I'll leave that up to you to figure out. ;)
Good luck!
JavaScript:
// Global variables used for the seeded random functions, below.
var seedobja = 1103515245
var seedobjc = 12345
var seedobjm = 4294967295 //0x100000000
// Creates a new seed for seeded functions such as srandom().
function newseed(seednum)
{
return [seednum]
}
// Works like Math.random(), except you provide your own seed as the first argument.
function srandom(seedobj)
{
seedobj[0] = (seedobj[0] * seedobja + seedobjc) % seedobjm
return seedobj[0] / (seedobjm - 1)
}
// Store some test values in variables.
var my_seed_value = newseed(230951)
var my_random_value_1 = srandom(my_seed_value)
var my_random_value_2 = srandom(my_seed_value)
var my_random_value_3 = srandom(my_seed_value)
// Print the values to console. Replace "WScript.Echo()" with "alert()" if inside a Web browser.
WScript.Echo(my_random_value_1)
WScript.Echo(my_random_value_2)
WScript.Echo(my_random_value_3)
Lua 4 (my personal target environment):
-- Global variables used for the seeded random functions, below.
seedobja = 1103515.245
seedobjc = 12345
seedobjm = 4294967.295 --0x100000000
-- Creates a new seed for seeded functions such as srandom().
function newseed(seednum)
return {seednum}
end
-- Works like random(), except you provide your own seed as the first argument.
function srandom(seedobj)
seedobj[1] = mod(seedobj[1] * seedobja + seedobjc, seedobjm)
return seedobj[1] / (seedobjm - 1)
end
-- Store some test values in variables.
my_seed_value = newseed(230951)
my_random_value_1 = srandom(my_seed_value)
my_random_value_2 = srandom(my_seed_value)
my_random_value_3 = srandom(my_seed_value)
-- Print the values to console.
print(my_random_value_1)
print(my_random_value_2)
print(my_random_value_3)

Categories

Resources