Random Number Generation to Memory from a Distribution using VBA - vba

I want to generate random numbers from a selected distribution in VBA (Excel 2007).
I'm currently using the Analysis Toolpak with the following code:
Application.Run "ATPVBAEN.XLAM!Random", "", A, B, C, D, E, F
Where
A = how many variables that are to be randomly generated
B = number of random numbers generated per variable
C = number corresponding to a distribution
1= Uniform
2= Normal
3= Bernoulli
4= Binomial
5= Poisson
6= Patterned
7= Discrete
D = random number seed
E = parameter of distribution (mu, lambda, etc.) depends on choice for C
(F) = additional parameter of distribution (sigma, etc.) depends on choice for C
But I want to have the random numbers be generated into an array, and NOT onto a sheet.
I understand that where the "" is designates where the random numbers should be printed to, but I don't know the syntax for assigning the random numbers to an array, or some other form of memory storage instead of to a sheet.
I've tried following the syntax discussed at this Analysis Toolpak site, but have had no success.
I realize that VBA is not the ideal place to generate random numbers, but I need to do this in VBA. Any help is much appreciated! Thanks!

Using the inbuilt functions is the key. There is a corresponding version for each of these functions but Poisson. In my presented solution I am using an algorithm presented by Knuth to generate a random number from the Poisson Distribution.
For Discrete or Patterned you obviously have to write your custom algorithm.
Regarding the seed you can place a Randomize [seed] before filling your array.
Function RandomNumber(distribution As Integer, Optional param1 = 0, Optional param2 = 0)
Select Case distribution
Case 1 'Uniform
RandomNumber = Rnd()
Case 2 'Normal
RandomNumber = Application.WorksheetFunction.NormInv(Rnd(), param1, param2)
Case 3 'Bernoulli
RandomNumber = IIf(Rnd() > param1, 1, 0)
Case 4 'Binomial
RandomNumber = Application.WorksheetFunction.Binom_Inv(param1, param2, Rnd())
Case 5 'Poisson
RandomNumber = RandomPoisson(param1)
Case 6 'Patterned
RandomNumber = 0
Case 7 'Discrete
RandomNumber = 0
End Select
End Function
Function RandomPoisson(ByVal lambda As Integer) 'Algorithm by Knuth
l = Exp(-lambda)
k = 0
p = 1
Do
k = k + 1
p = p * Rnd()
Loop While p > l
RandomPoisson = k - 1
End Function

Why not use the inbuilt functions?
Uniform = rnd
Normal = WorksheetFunction.NormInv
Bernoulli = iif(rnd()<p,0,1)
Binomial = WorksheetFunction.Binomdist
Poisson = WorksheetFunction.poisson
Patterned = for ... next
Discrete =
-
select case rnd()
case <0.1
'choice 1
case 0.1 to 0.4
'choice 2
case >0.4
'choice 3
end select

Related

Why does the 'i' need to be divided by 2 in caculating positional encoding?

In this transformer tutorial:
https://www.tensorflow.org/text/tutorials/transformer
def get_angles(pos, i, d_model):
angle_rates = 1 / np.power(10000, (2 * (i//2)) / np.float32(d_model))
return pos * angle_rates
I don't understand why 'i//2' is used, since in the original formula there is no specification of the integer division.
So what's the purpose of i//2?
according to the formula
PE(pos, 2i) = sin(1/100000^(2i /D) , PE(pos, 2i+1) = cos(1/100000^(2i
/D)
As you can see, for odd row, 2i -> 2i, for even row 2i+1 -> 2i, for example, a word embedding with [0,1,2,3,4,5,6,7] should transfer to [0,0,1,1,2,2,3,3], there is where i//2 comes from.

Using factorials to find combinations

So, this is a two part question but based on the same project. I am trying to write a small program that can illustrate how a computer can quickly crack a password, using a brute force attack. It only has three inputs: A check box to denote if it should use integers, a check box to denote if it should use letters, and a textbox to enter the password to be cracked. It then outputs the number of combinations. Here is my code:
dim a,b,c,d,P as double
'Using the following formula:
'P(n,r) = n!/(r!(n-r)!)
'Let's assume we are just using numbers, so n = 10
'r = the count of characters in the textbox.
a = factorial(n)
b = factorial(r)
c = (n - r)
d = factorial(c)
P = a / (b * d)
Output = "With a password of " & r & " characters and " & n & " possible values, the number of combinations are " & P
Me.RichTextBox1.Text = Output & vbCrLf
Function factorial(ByVal n As Integer) As Integer
If n <= 1 Then
Return 1
Else
Return factorial(n - 1) * n
End If
End Function
So, let's assume I'm only looking at the characters 0-9, with the following number of characters in a password, I get:
P(10,1) = 10!/(1! * (10-1)!) = 10
P(10,2) = 10!/(2! * (10-2)!) = 45
P(10,3) = 10!/(3! * (10-3)!) = 120
P(10,4) = 10!/(4! * (10-4)!) = 210
P(10,5) = 10!/(5! * (10-5)!) = 252
P(10,6) = 10!/(6! * (10-6)!) = 210
P(10,7) = 10!/(6! * (10-7)!) = 120
You can see the number of combinations goes down, once it gets past 5. I assume this is right, but wanted to check before I present this. Is this because the total number in the pool remains the same, while the sample increases?
My second question is about how to consider a password to crack that repeats numbers. Again, let's assume that we are just pulling from digits 0-9. If the sample size it two (lets say 15), then there are 45 possible combinations, right? But, what if they put in 55? Are there still 45 combinations? I suppose the computer still needs to iterate over every possible combination, so it would still be considered 45 possibilities?

VBA random numbers produces a repeating sequence at regular intervals

This code is supposed to generate a sequence of 10,000 random numbers in VBA. For some reason I am only able to produce a unique sequence of length 5842, and then it repeats. But, and this is the strangest part, each time I run the code, the sequence starts in a different place. For example in one run, the elements following element 2660 are the same as those following element 8502 (8502-2660= 5842). The next run, I get a sequence that repeats following elements 3704 and 9546 (9546-3704=5842). And so on.
Function NormRand() As Double
' NormRand returns a randomly distributed drawing from a
' standard normal distribution i.e. one with:
' Average = 0 and Standard Deviation = 1.0
Dim fac As Double, rsq As Double, v1 As Double, v2 As Double
Static flag As Boolean, gset As Double
' Each pass through the calculation of the routine produces
' two normally-distributed deviates, so we only need to do
' the calculations every other call. So we set the flag
' variable (to true) if gset contains a spare NormRand value.
If flag Then
NormRand = gset
' Force calculation next time.
flag = False
Else
' Don't have anything saved so need to find a pair of values
' First generate a co-ordinate pair within the unit circle:
Do
v1 = 2 * Rnd - 1#
v2 = 2 * Rnd - 1#
rsq = v1 * v1 + v2 * v2
Loop Until rsq <= 1#
' Do the Math:
fac = Sqr(-2# * Log(rsq) / rsq)
' Return one of the values and save the other (gset) for next time:
NormRand = v2 * fac
gset = v1 * fac
flag = True
End If
End Function
For some reason I am only able to produce a unique sequence of length
5842, and then it repeats. But, and this is the strangest part, each
time I run the code, the sequence starts in a different place
That's by design and well known - that's why the number generation is labelled pseudo random and not random.
By the way, I notice that you are multiplying the two values. That may not be a good idea - as mentioned here.
In your function, you may try to replace Rnd with RndDbl:
Public Function RndDbl(Optional ByRef Number As Single) As Double
' Exponent to shift the significant digits of a single to
' the least significant digits of a double.
Const Exponent As Long = 7
Dim Value As Double
' Generate two values like:
' 0.1851513
' 0.000000072890967130661
' and add these.
Value = CDbl(Rnd(Number)) + CDbl(Rnd(Number) * 10 ^ -Exponent)
RndDbl = Value
End Function
and then modify your code to include a dynamic seed by calling Timer:
Do
v1 = 2 * RndDbl(-Timer) - 1#
v2 = 2 * RndDbl(-Timer) - 1#
rsq = v1 + v2
Loop Until rsq <= 1#
The generated values will still not be true random, but should not take form of a repeated sequence.

VB challenge/ help MONTE CARLO INTEGRATION

Im trying to create Monte-Carlo simulation that can be used to derive estimates for integration problems (summing up the area under
a curve). Have no idea what to do now and i am stuck
"to solve this problem we generate a number (say n) of random number pairs for x and y between 0 and 1, for each pair we see if the point (x,y) falls above or below the line. We count the number of times this happens (say c). The area under the curve is computed as c/n"
Really confused please help thank you
Function MonteCarlo()
Dim a As Integer
Dim b As Integer
Dim x As Double
Dim func As Double
Dim total As Double
Dim result As Double
Dim j As Integer
Dim N As Integer
Console.WriteLine("Enter a")
a = Console.ReadLine()
Console.WriteLine("Enter b")
b = Console.ReadLine()
Console.WriteLine("Enter n")
N = Console.ReadLine()
For j = 1 To N
'Generate a new number between a and b
x = (b - a) * Rnd()
'Evaluate function at new number
func = (x ^ 2) + (2 * x) + 1
'Add to previous value
total = total + func
Next j
result = (total / N) * (b - a)
Console.WriteLine(result)
Console.ReadLine()
Return result
End Function
You are using the rejection method for MC area under the curve.
Do this:
Divide the range of x into, say, 100 equally-spaced, non-overlapping bins.
For your function y = f(x) = (x ^ 2) + (2 * x) + 1, generate e.g. 10,000 values of y for 10,000 values of x = (b - a) * Rnd().
Count the number of y-values in each bin, and divide by 10,000 to get a "bin probability." --> p(x).
Next, the proper way to randomly simulate your function is to use the rejection method, which goes as follows:
4a. Draw a random x-value using x = (b - a) * Rnd()
4b. Draw a random uniform U(0,1). If U(0,1) is less than p(x) add a count to the bin.
4c. Continue steps 4a-4b 10000 times.
You will now be able to simulate your y=f(x) function using the rejection method.
Overall, you need to master these approaches before you do what you want since it sounds like you have little experience in bin counts, simulation, etc. Area under the curve is always one using this approach, so just be creative for integrating using MC.
Look at some good textbooks on MC integration.

Matlab: how do I run the optimization (fmincon) repeately?

I am trying to follow the tutorial of using the optimization tool box in MATLAB. Specifically, I have a function
f = exp(x(1))*(4*x(1)^2+2*x(2)^2+4*x(1)*x(2)+2*x(2)+1)+b
subject to the constraint:
(x(1))^2+x(2)-1=0,
-x(1)*x(2)-10<=0.
and I want to minimize this function for a range of b=[0,20]. (That is, I want to minimize this function for b=0, b=1,b=2 ... and so on).
Below is the steps taken from the MATLAB's tutorial webpage(http://www.mathworks.com/help/optim/ug/nonlinear-equality-and-inequality-constraints.html), how should I change the code so that, the optimization will run for 20 times, and save the optimal values for each b?
Step 1: Write a file objfun.m.
function f = objfun(x)
f = exp(x(1))*(4*x(1)^2+2*x(2)^2+4*x(1)*x(2)+2*x(2)+1)+b;
Step 2: Write a file confuneq.m for the nonlinear constraints.
function [c, ceq] = confuneq(x)
% Nonlinear inequality constraints
c = -x(1)*x(2) - 10;
% Nonlinear equality constraints
ceq = x(1)^2 + x(2) - 1;
Step 3: Invoke constrained optimization routine.
x0 = [-1,1]; % Make a starting guess at the solution
options = optimoptions(#fmincon,'Algorithm','sqp');
[x,fval] = fmincon(#objfun,x0,[],[],[],[],[],[],...
#confuneq,options);
After 21 function evaluations, the solution produced is
x, fval
x =
-0.7529 0.4332
fval =
1.5093
Update:
I tried your answer, but I am encountering problem with your step 2. Bascially, I just fill the my step 2 to your step 2 (below the comment "optimization just like before").
%initialize list of targets
b = 0:1:20;
%preallocate/initialize result vectors using zeros (increases speed)
opt_x = zeros(length(b));
opt_fval = zeros(length(b));
>> for idx = 1, length(b)
objfun = #(x)objfun_builder(x,b)
%optimization just like before
x0 = [-1,1]; % Make a starting guess at the solution
options = optimoptions(#fmincon,'Algorithm','sqp');
[x,fval] = fmincon(#objfun,x0,[],[],[],[],[],[],...
#confuneq,options);
%end the stuff I fill in
opt_x(idx) = x
opt_fval(idx) = fval
end
However, it gave me the output is:
Error: "objfun" was previously used as a variable, conflicting
with its use here as the name of a function or command.
See "How MATLAB Recognizes Command Syntax" in the MATLAB
documentation for details.
There are two things you need to change about your code:
Creation of the objective function.
Multiple optimizations using a loop.
1st Step
For more flexibility with regard to b, you need to set up another function that returns a handle to the desired objective function, e.g.
function h = objfun_builder(x, b)
h = #(x)(objfun(x));
function f = objfun(x)
f = exp(x(1))*(4*x(1)^2+2*x(2)^2+4*x(1)*x(2)+2*x(2)+1) + b;
end
end
A more elegant and shorter approach are anonymous functions, e.g.
objfun_builder = #(x,b)(exp(x(1))*(4*x(1)^2+2*x(2)^2+4*x(1)*x(2)+2*x(2)+1) + b);
After all, this works out to be the same as above. It might be less intuitive for a Matlab-beginner, though.
2nd Step
Instead of placing an .m-file objfun.m in your path, you will need to call
objfun = #(x)(objfun_builder(x,myB));
to create an objective function in your workspace. In order to loop over the interval b=[0,20], use the following loop
%initialize list of targets
b = 0:1:20;
%preallocate/initialize result vectors using zeros (increases speed)
opt_x = zeros(length(b))
opt_fval = zeros(length(b))
%start optimization of list of targets (`b`s)
for idx = 1, length(b)
objfun = #(x)objfun_builder(x,b)
%optimization just like before
opt_x(idx) = x
opt_fval(idx) = fval
end