Can not use gamma function in an external function

5 ビュー (過去 30 日間)
Geovane Gomes
Geovane Gomes 2023 年 9 月 20 日
コメント済み: Geovane Gomes 2023 年 9 月 20 日
Dear,
I am trying to generate some random numbers with a specific distribution, but to calculate the parameters of this distribution I have to use the gamma function.
It works well when I use it in the same file, for example in live script, but from an external function does not work (see error below).
clear
mu = 0.15;
sigma = 0.03;
N = 1e3;
x0 = [2.001,1.0e3];
fun = @(x) sqrt(gamma(1-2/x)-(gamma(1-1/x)).^2)./gamma(1-1/x)-sigma/mu;
par2 = fzero(fun,x0);
par1 = mu/gamma(1-1/par2);
randomNumbers = gevrnd(1/par2,par1/par2,par1,N,1);
% checking
histogram(randomNumbers)
mu = mean(randomNumbers)
mu = 0.1482
sigma = std(randomNumbers)
sigma = 0.0275
Now trying to use it in an external function, I got the error 'Unrecognized function or variable 'gamma'.
Can someone explain why this happens?
  2 件のコメント
Dyuman Joshi
Dyuman Joshi 2023 年 9 月 20 日
"Now trying to use it in an external function, I got the error 'Unrecognized function or variable 'gamma'."
What is the external function? How are you calling it?
Geovane Gomes
Geovane Gomes 2023 年 9 月 20 日
This one:
obj.means = 0.15;
obj.standardDeviations = 0.03;
obj.distributions = "Frechet";
obj.nSimulations = 2e4;
randomNumbers = generaterandomnumbers(obj);
Error using fzero>localFirstFcnEvalError
FZERO cannot continue because user-supplied function_handle ==> @(x)sqrt(gamma(1-2/x)-(gamma(1-1/x)).^2)./gamma(1-1/x)-sigma/mu failed with the error below.

Unrecognized function or variable 'gamma'.

Error in fzero (line 231)
localFirstFcnEvalError(FunFcn,FunFcnIn,ME);

Error in solution>generaterandomnumbers (line 46)
par2 = fzero(fun,x0);
function randomNumbers = generaterandomnumbers(obj)
nVariables = length(obj.means);
% Pre-allocate memory for the random numbers
randomNumbers = zeros(obj.nSimulations, nVariables);
for i = 1:nVariables
switch lower(obj.distributions{i})
case 'normal'
randomNumbers(:,i) = normrnd(obj.means(i), ...
obj.standardDeviations(i), obj.nSimulations, 1);
case 'binomial'
randomNumbers(:,i) = binornd(obj.means(i), ...
obj.standardDeviations(i), obj.nSimulations, 1);
case 'lognormal'
mu = log((obj.means(i) ^ 2) / ...
sqrt(obj.standardDeviations(i) ^ 2 + obj.means(i) ^ 2));
sigma = sqrt(log(obj.standardDeviations(i) ^ 2 / ...
(obj.means(i) ^ 2) + 1));
randomNumbers(:,i) = lognrnd(mu, sigma, obj.nSimulations, 1);
case {'gumbel', 'extreme type 1'}
gamma = 0.577216;
sigmaHat = sqrt(6) * obj.standardDeviations(i) / pi;
muHat = obj.means(i) - gamma * sigmaHat;
pd = makedist('GeneralizedExtremeValue', 'k', 0, ...
'sigma', sigmaHat, 'mu', muHat);
randomNumbers(:,i) = random(pd, obj.nSimulations, 1);
case {'gumbel min', 'extreme type 1 min'}
gamma = 0.577216;
sigmaHat = sqrt(6) * obj.standardDeviations(i) / pi;
muHat = obj.means(i) + gamma / sigmaHat;
randomNumbers(:,i) = evrnd(muHat, sigmaHat, ...
obj.nSimulations, 1);
case 'frechet'
x0 = [2.001,1.0e3];
mu = obj.means(i);
sigma = obj.standardDeviations(i);
fun = @(x) sqrt(gamma(1-2/x)-(gamma(1-1/x)).^2)./gamma(1-1/x)-sigma/mu;
par2 = fzero(fun,x0);
par1 = mu/gamma(1-1/par2);
randomNumbers = gevrnd(1/par2,par1/par2,par1,N,1);
otherwise
error('Invalid distribution: %s', obj.distributions{i});
end
end
end

サインインしてコメントする。

採用された回答

Dyuman Joshi
Dyuman Joshi 2023 年 9 月 20 日
編集済み: Dyuman Joshi 2023 年 9 月 20 日
Using function names as variable names is not a good idea - in your case gamma.
I have changed the names to gamma0 and added a random value for N in the frechet case (as it was not defined), and the code runs without an errror.
obj.means = 0.15;
obj.standardDeviations = 0.03;
obj.distributions = "Frechet";
obj.nSimulations = 2e4;
randomNumbers = generaterandomnumbers(obj)
randomNumbers = 5×1
0.1178 0.1207 0.1649 0.1623 0.1244
function randomNumbers = generaterandomnumbers(obj)
nVariables = length(obj.means);
% Pre-allocate memory for the random numbers
randomNumbers = zeros(obj.nSimulations, nVariables);
for i = 1:nVariables
switch lower(obj.distributions{i})
case 'normal'
randomNumbers(:,i) = normrnd(obj.means(i), ...
obj.standardDeviations(i), obj.nSimulations, 1);
case 'binomial'
randomNumbers(:,i) = binornd(obj.means(i), ...
obj.standardDeviations(i), obj.nSimulations, 1);
case 'lognormal'
mu = log((obj.means(i) ^ 2) / ...
sqrt(obj.standardDeviations(i) ^ 2 + obj.means(i) ^ 2));
sigma = sqrt(log(obj.standardDeviations(i) ^ 2 / ...
(obj.means(i) ^ 2) + 1));
randomNumbers(:,i) = lognrnd(mu, sigma, obj.nSimulations, 1);
case {'gumbel', 'extreme type 1'}
%% Name changed
gamma0 = 0.577216;
sigmaHat = sqrt(6) * obj.standardDeviations(i) / pi;
muHat = obj.means(i) - gamma0 * sigmaHat;
pd = makedist('GeneralizedExtremeValue', 'k', 0, ...
'sigma', sigmaHat, 'mu', muHat);
randomNumbers(:,i) = random(pd, obj.nSimulations, 1);
case {'gumbel min', 'extreme type 1 min'}
%% Name changed
gamma0 = 0.577216;
sigmaHat = sqrt(6) * obj.standardDeviations(i) / pi;
muHat = obj.means(i) + gamma0 / sigmaHat;
randomNumbers(:,i) = evrnd(muHat, sigmaHat, ...
obj.nSimulations, 1);
case 'frechet'
x0 = [2.001,1.0e3];
mu = obj.means(i);
sigma = obj.standardDeviations(i);
fun = @(x) sqrt(gamma(1-2/x)-(gamma(1-1/x)).^2)./gamma(1-1/x)-sigma/mu;
par2 = fzero(fun,x0);
par1 = mu/gamma(1-1/par2);
%% Value added
N=5;
randomNumbers = gevrnd(1/par2,par1/par2,par1,N,1);
otherwise
error('Invalid distribution: %s', obj.distributions{i});
end
end
end
  2 件のコメント
Dyuman Joshi
Dyuman Joshi 2023 年 9 月 20 日
Though, variables defined within a case are not accessible to another case and MATLAB executes only one case of any switch statement.
So for the input you have provided, only the 2nd last case is executed and gamma is not over-writed. But the error still occurs. Hmmm.
Geovane Gomes
Geovane Gomes 2023 年 9 月 20 日
Thank you very much for your help. It works.
"N" is actually "obj.nSimulations". It was wrong. Thanks again.

サインインしてコメントする。

その他の回答 (0 件)

タグ

製品


リリース

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by