Home > Mobile >  How to create a function handle of a function with both new input parameters and output parameters f
How to create a function handle of a function with both new input parameters and output parameters f

Time:09-17

I am trying to create a function and a function handle of the said function where the function takes in output parameters from the previous call and new input parameters and calculates the gradient in the function as given in the toy example shown below. I would like to pass the function handle to hmcSampler. However, I am having a problem in creating the function handle and would like some help.

To clarify: I want to call logPosterior with a new value of theta, but also with the theta and logpdf output from the previous call. And I need to do this through a function handle that will be called multiple times by a function I don't control, so I need either logPosterior or its handle to manage storing the old values. In the first call, there should be different values of theta and old_theta so that the function can get going.

%% Toy implementation of hmcsampler class in Matlab
NumPredictors = 2;

trueIntercept = 2;
trueBeta = [3;0];
NumData = 100;
rng('default') %For reproducibility
X = rand(NumData,NumPredictors);
mu = X*trueBeta   trueIntercept;
y = mu;

% define the mean and variance of normal distribution of each parameter
means = [0; 0];
standevs = [1;1];


% create multivariate normal log probability distribution
[logpdf, grad_logpdf] = @(theta)logPosterior(theta, old_theta, X, y, means, standevs, old_logpdf); % <- How to write this?
% create the startpoint from which sampling starts
startpoint = randn(2, 1);

% create an HMC sampler object
smp = hmcSampler(logpdf, startpoint);

% estimate maximum of log probability density
[xhat, fitinfo] = estimateMAP(smp);

num_chains = 4;
chains = cell(num_chains, 1);
burnin = 50000;
num_samples = 2000000;


function [logpdf, grad_logpdf] = logPosterior(theta, old_theta, X, y, means, standevs, old_logpdf)
    
    % values
    intercept = theta(1);
    beta = theta(2:end);
    y_computed = X*beta   intercept; 
    log_likelihood = log(y_computed);
    del_loglikelihood = log_likelihood - old_logpdf;
    del_params = theta - old_theta;
    grad_params1 = del_loglikelihood/del_params;
    
    % compute log priors and gradients of parameters
    log_prior_params = 0;
    grad_params2 = [];
    for i = 1:3
        [lp, grad] = normalDistGrad(theta(i), means(i), standevs(i));
        log_prior_params = log_prior_params   lp;
        grad_params2 = [grad_params2; grad];
    end
    % return the log posterior and its gradient
    logpdf = log_likelihood   log_prior_params;
    grad_logpdf = grad_params1   grad_params2;
end

function [lpdf,glpdf] = normalDistGrad(X, Mu, Sigma)
    Z = (X - Mu)./Sigma;
    lpdf = sum(-log(Sigma) - .5*log(2*pi) - .5*(Z.^2));
    glpdf = -Z./Sigma;
end

CodePudding user response:

matlab help

first define your function in a separate m file which is in your current path :

function [o1,o2]=myfunc(in1,in2,in3)
    o1=in1 in2 in3;
    o2=in3-in2;
end

then create handle to the function :

f=@myfunc;
f(1,2,3)
ans= 6

to use just one of inputs:

f=@(x)myfunc(x,3,5);
f(1)
ans=9

to get both output:

[a,b]=f(1);

or define one output in your function and reference their index after calling them :

function o=myfunc(in1,in2,in3)
    o1=in1 in2 in3;
    o2=in3-in2;
    o=[o1,o2];
end

...

CodePudding user response:

I would implement logPosterior as follows for it to keep track of the values in the last function call. A persistent variable is local to the function, but persists between calls, making it an ideal tool to give the function memory.

function [logpdf, grad_logpdf] = logPosterior(theta, X, y, means, standevs)
    persistent old_theta old_logpdf
    if isempty(old_theta)
       % function hasn't been called before, initialize the old values:
       old_theta = zeros(size(theta));
       old_logpdf = 0; % adjust to be meaningful initial values
    end

    % ... (your original function code here)

    % save new values as old values for next call
    old_theta = theta;
    old_logpdf = logpdf;
end

You wold now take a function handle as follows:

func = @(theta)logPosterior(theta, X, y, means, standevs);

func is the handle you'd pass into whatever function will call it. You could initialize the previous variables by running your function once (I'm not sure what a suitable initialization is!):

func(startpoint);
smp = hmcSampler(func, startpoint);
  • Related