How to draw from exponential distribution in Ruby? - ruby

In Ruby, I need to draw from an exponential distribution with mean m. Please show me how to do it quickly and efficiently. Eg. let's have:
m = 4.2
def exponential_distribution
rand( m * 2 )
end
But of course, this code is wrong, and also, it only returns whole number results. I'm already tired today, please hint me towards a good solution.

If you want to do it from scratch you can use inversion.
def exponential(mean)
-mean * Math.log(rand) if mean > 0
end
If you want to parameterize it with rate lambda, the mean and rate are inverses of each other. Divide by -lambda rather than multiplying by -mean.
Technically it should be log(1.0 - rand), but since 1.0 - rand has a uniform distribution you can save one arithmetic operation by just using rand.

How about using the distribution gem? Here's an example:
require 'distribution'
mean = 4.2
lambda = mean**-1
# generate a rng with exponential distribution
rng = Distribution::Exponential.rng(lambda)
# sample a value
sample = rng.call
If you need to change the value of lambda very often it might be useful to use the p_value method directly. A good sample can be found in the source code for Distribution::Exponential#rng, which basically just uses p_value internally. Here's an example of how to do it:
require 'distribution'
# use the same rng for each call
rng = Random
1.step(5, 0.1) do |mean|
lambda = mean**-1
# sample a value
sample = Distribution::Exponential.p_value(rng.rand, lambda)
end

Related

How can I use randjump instead of generating a certain number of random numbers?

I am trying to "skip forward" a few realizations by using the function Future.randjump(), but it doesn't seem to behave as I expect it to. The following code gives me the desired result, where jumping forward 1 steps gives the same result as if I had called rand(rng) twice, i.e. the two println display the same number:
using Random, Future
rng = MersenneTwister(123);
new_rng = Future.randjump(rng, 1)
rand(rng)
rand(rng)
println(rand(rng))
println(rand(new_rng))
However, if I add one extra call to rand(rng) before the call to randjump(), the two printed numbers are completely different:
using Random, Future
rng = MersenneTwister(123);
rand(rng) # Added line
new_rng = Future.randjump(rng, 1)
rand(rng)
rand(rng)
println(rand(rng))
println(rand(new_rng))
I expected that the two calls to println() would display the same thing even in the second case, how come they don't? Is there a way I can use randjump() in the second case to get the same realizations as if I had called rand(rng) several times? Thank you in advance.
One unit of randjump corresponds to generation of two floating point numbers.
Consider this example
julia> rng = MersenneTwister(123);
julia> rng2 = Future.randjump(rng, 1);
julia> rand(rng, 4)
4-element Vector{Float64}:
0.7684476751965699
0.940515000715187
0.6739586945680673
0.3954531123351086
julia> rand(rng2,2)
2-element Vector{Float64}:
0.6739586945680673
0.3954531123351086
Note that in the second call (that is rand(rng2,2)) the both numbers are identical to the two last numbers in the first call (taht is rand(rng,2)).
Another issue is that different distributions might "consume" Float64 numbers from the stream at a different speed - so you need to check with a particular distribution how fast it consumes floats for the stream (some might also use buffering etc...).
Looking at the source code of randn (#edit randn()) it consumes one float and hence you get the same results for those two calls:
julia> randn(MersenneTwister(123),6)[3:end]
4-element Vector{Float64}:
1.142650902867199
0.45941562040708034
-0.396679079295223
-0.6647125451916877
julia> randn(Future.randjump(MersenneTwister(123),1),4)
4-element Vector{Float64}:
1.142650902867199
0.45941562040708034
-0.396679079295223
-0.6647125451916877
EDIT
Regarding your comment the size of Mersenne Twister state is 19937 bits and half-unit jumps are not supported. Running rand is mutating this state but not half-the way - so you end up with different bits. Note that an RNG is a sequence of states and the actual values are calculated from that state.
The correct pattern to synchronize random numbers in your computations is the following:
master_rng = MersenneTwister(123);
rng1 = Future.randjump(master_rng, big(10)^20)
# do whatever you want
rng2 = Future.randjump(master_rng, 2*big(10)^20)
# do whatever you want
rng3 = Future.randjump(master_rng, 3*big(10)^20)
# do whatever you want
With this pattern you can correctly maintains synchronization between random number streams and have full control whether the should overlap or not.

SARIMAX model in PyMC3

I would like to write down the following SARIMAX model (2,0,0) (2,0,0,12) in PyMC3 to perform bayesian estimation of its coefficients but I cannot figure out how to start with the seasonal part
Has anyone tries something like this?
with pm.Model() as ar2:
theta = pm.Normal("theta", 0.0, 1.0, shape=2)
sigma = pm.HalfNormal("sigma", 3)
likelihood = pm.AR("y", theta, sigma=sigma, observed=data)
trace = pm.sample(
1000,
tune=2000,
random_seed=13,
)
idata = az.from_pymc3(trace)
Although it would be best (e.g. best performance) if you can get an answer that uses PyMC3 exclusively, in case that does not exist yet, there is an alternative way to do this that uses the SARIMAX model in Statsmodels in combination with PyMC3.
There are too many details to repeat a full answer here, but basically you wrap the log-likelihood and gradient methods associated with a Statsmodels SARIMAX model. Here is a link to an example Jupyter notebook that shows how to do this:
https://www.statsmodels.org/stable/examples/notebooks/generated/statespace_sarimax_pymc3.html
I'm not sure if you'll still need it, however, expanding on cfulton's answer, here is how to fix the error in the statsmodels example (https://www.statsmodels.org/dev/examples/notebooks/generated/statespace_sarimax_pymc3.html, cell 8):
with pm.Model():
# Priors
arL1 = pm.Uniform('ar.L1', -0.99, 0.99)
maL1 = pm.Uniform('ma.L1', -0.99, 0.99)
sigma2 = pm.InverseGamma('sigma2', 2, 4)
# convert variables to tensor vectors
# # this is wrong:
theta = tt.as_tensor_variable([arL1, maL1, sigma2])
# # this is correct:
theta = tt.as_tensor_variable([arL1, maL1, sigma2], 'v')
# use a DensityDist (use a lamdba function to "call" the Op)
# # this is wrong:
# pm.DensityDist('likelihood', lambda v: loglike(v), observed={'v': theta})
# # this is correct:
pm.DensityDist('likelihood', lambda v: loglike(v), observed=theta)
# Draw samples
trace = pm.sample(ndraws, tune=nburn, discard_tuned_samples=True, cores=4)
I'm no pymc3/theano expert, but I think the error means that Theano has failed to associate the tensor's name with the values. If you define the name along with the values right at the beginning, it works.
I know it's not a direct answer to your question. Nevertheless, I hope it helps.

Assignment problems with simple random number generation in Modelica

I am relatively new to Modelica (Dymola-environment) and I am getting very desperate/upset that I cannot solve such a simple problem as a random number generation in Modelica and I hope that you can help me out.
The simple function random produces a random number between 0 and 1 with an input seed seedIn[3] and produces the output seed seedOut[3] for the next time step or event. The call
(z,seedOut) = random(seedIn);
works perfectly fine.
The problem is that I cannot find a way in Modelica to compute this assignment over time by using the seedOut[3] as the next seedIn[3], which is very frustrating.
My simple program looks like this:
*model Randomgenerator
Real z;
Integer seedIn[3]( start={1,23,131},fixed=true), seedOut[3];
equation
(z,seedOut) = random(seedIn);
algorithm
seedIn := seedOut;
end Randomgenerator;*
I have tried nearly all possibilities with algorithm assignments, initial conditions and equations but none of them works. I just simply want to use seedOut in the next time step. One problem seems to be that when entering into the algorithm section, neither the initial conditions nor the values from the equation section are used.
Using the 'sample' and 'reinit' functions the code below will calculate a new random number at the frequency specified in 'sample'. Note the way of defining the "start value" of seedIn.
model Randomgenerator
Real seedIn[3] = {1,23,131};
Real z;
Real[3] seedOut;
equation
(z,seedOut) = random(seedIn);
when sample(1,1) then
reinit(seedIn,pre(seedOut));
end when;
end Randomgenerator;
The 'pre' function allows the use of the previous value of the variable. If this was not used, the output 'z' would have returned a constant value. Two things regarding the 'reinint' function, it requires use of 'when' and requires 'Real' variables/expressions hence seedIn and seedOut are now defined as 'Real'.
The simple "random" generator I used was:
function random
input Real[3] seedIn;
output Real z;
output Real[3] seedOut;
algorithm
seedOut[1] :=seedIn[1] + 1;
seedOut[2] :=seedIn[2] + 5;
seedOut[3] :=seedIn[3] + 10;
z :=(0.1*seedIn[1] + 0.2*seedIn[2] + 0.3*seedIn[3])/(0.5*sum(seedIn));
end random;
Surely there are other ways depending on the application to perform this operation. At least this will give you something to start with. Hope it helps.

Lua math.random not working

So I'm trying to create a little something and I have looked all over the place looking for ways of generating a random number. However no matter where I test my code, it results in a non-random number. Here is an example I wrote up.
local lowdrops = {"Wooden Sword","Wooden Bow","Ion Thruster Machine Gun Blaster"}
local meddrops = {}
local highdrops = {}
function randomLoot(lootCategory)
if lootCategory == low then
print(lowdrops[math.random(3)])
end
if lootCategory == medium then
end
if lootCategory == high then
end
end
randomLoot(low)
Wherever I test my code I get the same result. For example when I test the code here http://www.lua.org/cgi-bin/demo it always ends up with the "Ion Thruster Machine Gun Blaster" and doesen't randomize. For that matter testing simply
random = math.random (10)
print(random)
gives me 9, is there something i'm missing?
You need to run math.randomseed() once before using math.random(), like this:
math.randomseed(os.time())
One possible problem is that the first number may not be so "randomized" in some platforms. So a better solution is to pop some random number before using them for real:
math.randomseed(os.time())
math.random(); math.random(); math.random()
Reference: Lua Math Library

using probability for rounding decimals

What might be a simple Ruby way to round numbers using probability, i.e., based on how close the value is to one boundary or the other (floor or ceiling)?
For example, given a current price value of 28.33, I need to add 0.014.
Equivalent to starting with 28.34 and needing to add 0.004, but the final value must be rounded to two decimal places(which can be provided as parameter, or fixed for now).
The final value should therefore be:
28.34 with 60% chance, since it is that much closer, OR
28.35 with 40% random chance
The reason it occured to me this could serve best is that the application is stateless and independent across runs, but still needs to approximate the net effect of accumulating the less significant digits normally rounded into oblivion (eg. micropenny values that do have an impact over time). For example, reducing a stop-loss by some variable increment every day (subtraction like -0.014 above instead).
It would be useful to extend this method to the Float class directly.
How about:
rand(lower..upper) < current ? lower.round(2) : upper.round(2)
EDIT:
The above will only work if you use Ruby 1.9.3 (due to earlier versions not supporting rand in a range).
Else
random_number = rand * (upper-lower) + lower
random_number < current ? lower.round(2) : upper.round(2)
Wound up using this method:
class Float
def roundProb(delta, prec=2)
ivalue=self
chance = rand # range 0..1, nominally averaged at 0.5
# puts lower=((ivalue + delta)*10**prec -0.5).round/10.0**prec # aka floor
# puts upper=((ivalue + delta)*10**prec +0.5).round/10.0**prec # ceiling
ovalue=((ivalue + delta)*10**prec +chance-0.5).round/10.0**prec # proportional probability
return ovalue
rescue
puts $#, $!
end
end
28.33.roundProb(0.0533)
=> 28.39
Maybe not the most elegant approach but seems to work for the general case of any precision, default 2. Even works on Ruby 1.8.7 I'm stuck with in one case, which lacks a precision parameter to round().

Resources