Function differentiation - matlab

I have a function:
Where ||x|| is an Euclidean distance.
For given n (number of variables) I want Matlab to differentiate this function and then substitute real numbers into it.
What I truly don't understand how to do is:
1) How let Matlab create all these new n variables for later differentiation?
2) Each variable is a vector of dimension = d, i.e x=[x1, x2, ... xd], so later I want to differentiate function with respect to certain vector elements, for example with respect to x1, how can I do it?
EDIT 1: function should be differentiated at each x_i, where i=1:n

The derivative of a sum, is the sum of the derivatives of each element... so, we need to find the derivative only once (you can do this manually, if it is a simple function like in your toy-example, but we do this the general way, using the Symbolic Math Toolbox):
syms x y z % declaring 3 symolic variables
F = 1/(norm([x,y,z])); % declaring a function
f = diff(F,x) % calculate the derivative with regard to the symbolic variable x
f = -(abs(x)*sign(x))/(abs(x)^2 + abs(y)^2 + abs(z)^2)^(3/2)
you now have different options. You can use subs to evaluate the function f (simply assign numeric values to x,y, and z and call subs(f). Or, you create a (numeric) function handle by using matlabFunction (this is the way, I prefer)
fnc = matlabFunction(f); % convert to matlab function
Then, you just need to sum up the vector that you created (well, you need to sum up the sum of each of the two vector elements...)
% create arbitrary vector
n = 10;
x = rand(n+1,3);
% initialize total sum
SumFnc = 0;
% loop through elements
for i = 1:n
% calculate local sum
s = x(i,:)+x(i+1,:);
% call derivative-function + sum up
SumFnc = SumFnc + fnc(s(1),s(2),s(3));
end

Related

Create arrays based on a different array

% create variable x with array of all necessary values
x=linspace(0.1,13,50);
for i=x
% create equation to determine y
y=(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z=log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
Using Matlab and im trying to use values from my x array to create two arrays, y and z, im pretty new to matlab and im struggling, thanks.
The problem in you code is that you did not use for loop properly. You can run through the index of x, then assign x(i) to a new variable k in each iteration, i.e.,
x=linspace(0.1,13,50);
for k = 1:length(x)
i = x(k);
% create equation to determine y
y(k) =(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z(k) =log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
Since MATLAB is able to vectorize the operations, so you are recommended to do it like below to speed up (for loop in MATLAB is expensive)
x = linspace(0.1,13,50);
y = (sqrt(2*x).*4.*x.^3)./(4*x+7^(x/10));
z = log10(2*x+5)+(4*x+exp(x))./(2/3 + 4*x.^2);
Remarks: you should be careful about the difference between .* and *, or ./ and /, where * and / are not element-wise operations.
Method 1:
you can initialize y and z into empty arrays and just append the corresponding result at the end:
% create variable x with array of all necessary values
x=linspace(0.1,13,50);
y=[];
z=[];
for i=x
% create equation to determine y
y(end+1)=(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z(end+1)=log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
This approach can prove to be poor in terms of efficiency, since the size of y and z changes dynamically.
Method 2:
If you still want to use a for loop, it is better to preallocate memory for y and z and iterate the indices of x, something like:
% create variable x with array of all necessary values
x=linspace(0.1,13,50);
% Memory allocation
y = zeros(1, length(x));
z = zeros(1, length(x));
for i = 1 : length(x)
% create equation to determine y
y(i)=(sqrt(2.*x(i)*4*x(i).^3)/(4.*x(i)+7.^(x(i)/10));
%create equation to determine z
z(i)=log10(2.*x(i)+5)+(4.*x(i)+exp(x(i)))/(2./3+4.*x(i).^2);
end
Method 3 (preferred one):
It is generally more efficient to vectorize your implementations. In your case you could use something like:
x = linspace(0.1,13,50);
y = (sqrt(2.*x)*4*.*x.^3) ./ (4*x + 7.^(x./10));
z = log10(2*x+5) + (4*x + exp(x)) ./ (2/3 + 4*x.^2);

How to make a function that gives probabilities in a Geometric distribution?

I'm using MATLAB to make a function that returns the probability mass function (PMF) for a Geometric distribution when I enter the values of p, q, and the number of attempts (x) as the inputs.
My function:
function Probability = Geometric(p, q, x)
Probability = p*q^x-1
Now whenever I try to calculate the probability by typing in the values of p, q, and x, such as:
Geometric(0.5, 0.5, 1),
The exact error:
Geometric(0.5,0.5,1)
??? Undefined function or method 'Geometric' for input arguments of type 'double'.
I've tried changing functions, and reducing them to one input and one output.
I expect the probabilities to be calculated, but they just don't.
What's going wrong?
p*q^x-1 % Your original code
Your original code is taking q, raising it the xth power, multiplying it by p, then subtracting 1. This is equivalent to the following code which you certainly didn't intend.
(p*(q^x)) - 1 % What your code was doing written differently
Considering order of operations, the correction is easy.
p*q^(x-1) % Your corrected code
Another possible error source is your function is not saved as a standalone m-file "Geometric.m" which must also be on your MATLAB path (MATLAB has to "see" it). If you have your function file "MyFunction.m" stored in a folder, you can add that folder to MATLAB's visible path with one line (or manually navigate there). For more details, see how to create a function.
mypathtoMyFunction = 'C:\Users\SonnyJordan\Documents\SweetCode\FunctionFolder';
path(path,'mypathtoMyFunction')
A Full Solution (3 approaches)
From your parameterization of the Geometric distribution, you're wanting the support on {1, 2, 3, 4, ...}.
Two things. (1) I'd recommend an anonymous function for something like this. (2) There really isn't a need to separate p and q as separate variables since p + q = 1 and therefore one determines the other (i.e. q = 1-p).
Approach 1: Anonymous function
% MATLAB R2018b
geopmfh =#(p,k) p.*((1-p).^(k-1)); % Define pmf
k = 5; % Number of trials
p = 0.2; % Prob("Success" on trial)
geopmfh(p,k) % Probability
Above code is fully vectorized so you could pass it vectors and/or arrays of inputs.
A quick check to validate it is a valid probability mass function (pmf).
M = 500;
sum(geopmfh(p,[1:M])) % should return 1 if M large enough
Approach 2: Function (w/ error checking)
As an aside, making a function in MATLAB would make a lot of sense if you wanted to add error checking on the function inputs to ensure k is a positive integer and that p is between [0 1].
function [pmf] = geopmf(p,k)
%GEOPMF Calculates pmf for Geometric(p,k) distribution on {1,2,3,...}
% pmf = geopmf(p,k)
% p = n x d matrix of n d-dimensional success probabilities; must be [0,1]
% k = m x d matrix of m d-dimensional numbers of trials
% pmf = n x m matrix of probabilities
%
% Examples:
% k = 4; p = .5;
% pmf = geopmf(p,k) % pmf = 0.0625
% Input Error Checking ****************************************************
if isempty(p) | isempty(k), pmf = []; return, end
if nargin ~= 2, error('Function requires two inputs.'), end
if p < 0 | p > 1, error('p must be between 0 and 1.'), end
if k < 1 | ~isint(k), error('k must be positive integer & k > 0.'), end % with this parameterization
n = size(p,1); d = size(p,2);
m = size(k,1);
if isempty(p) | ~isnumeric(p) | ~ismatrix(p)
error('p must be non-empty numeric scalar, vector, or 2-D matrix.');
elseif isempty(k) | ~isnumeric(k) | ~ismatrix(k)
error('k must be non-empty numeric scalar, vector, or 2-D matrix.');
elseif size(k,2) ~=d
error('Rows of p and k must have same dimensions.');
end
% End (Input Error Checking) **********************************************
pmf = p.*((1-p).^(k-1));
end
Approach 3: MATLAB's built-in function
If you have the Statistics toolbox, MATLAB has a function for this already called geopdf but note it is parameterized according to the other "version" with support {0, 1, 2, ...} (see wiki page).
p.*((1-p).^k) % The other parameterization
geopdf(k,p) % Note order of inputs
You can correct for that by adjusting your input.
geopdf(k-1,p) % Subtract 1 trial
Code tested with MATLAB R2018b.

create matrix function of vector input variable (Matlab)

I'm having trouble creating a function that does what I want. I'm trying to create an anonymous function that, on accepting a vector of length N produces an NxN matrix. I'd like to populate each element of the matrix (ie, with a loop). A short example to be more specific:
N = 2;
Qjk = #(x,y) x * y;
for j = 1:N
for k = 1:N
Q(j,k) =#(x) Qjk(x(k),rand);
end
end
In the end this should produce, eg.:
Q = #(x) [.23*x(1), .16*x(2); .95*x(1), .62*x(2)]
I can write the final expression above by hand and it works as required, but I'm unable to automate this process with a loop/vectorization. Thanks.
So it is my understanding that you want to create a N x N matrix of elements where the input is a vector of length N?... and more specifically, you wish to take each element in the input vector x and generate a new 1 x N vector where each element in x gets scaled by this new 1 x N vector?
You can avoid loops by using bsxfun:
Q = bsxfun(#times, x(:).', rand(numel(x)));
I'm not sure what shape x is, whether it's a row or column vector but I'm not going to make any assumptions. x(:).' will ensure that your vector becomes a row vector. However, if you want to get your code working as it, get rid of the anonymous function declaration within the actual loop itself. Also, you'll probably want to call Qjk as that is the function you declared, not Q as that is the matrix you are trying to populate.
Simply do:
N = 2;
Q = zeros(N); % New - Allocate to be more efficient
Qjk = #(x,y) x * y;
for j = 1:N
for k = 1:N
Q(j,k) = Qjk(x(k),rand); % Change
end
end

Making a function in terms of a sum from 1 to n in Matlab

I'm trying to get Matlab to take this as a function of x_1 through x_n and y_1 through y_n, where k_i and r_i are all constants.
So far my idea was to take n from the user and make two 1×n vectors called x and y, and for the x_i just pull out x(i). But I don't know how to make an arbitrary sum in MATLAB.
I also need to get the gradient of this function, which I don't know how to do either. I was thinking maybe I could make a loop and add that to the function each time, but MATLAB doesn't like that.
I don't believe a loop is necessary for this calculation. MATLAB excels at vectorized operations, so would something like this work for you?
l = 10; % how large these vectors are
k = rand(l,1); % random junk values to work with
r = rand(l,1);
x = rand(l,1);
y = rand(l,1);
vals = k(1:end-1) .* (sqrt(diff(x).^2 + diff(y).^2) - r(1:end-1)).^2;
sum(vals)
EDIT: Thanks to #Amro for correcting the formula and simplifying it with diff.
You can solve for the gradient symbolically with:
n = 10;
k = sym('k',[1 n]); % Create n variables k1, k2, ..., kn
x = sym('x',[1 n]); % Create n variables x1, x2, ..., xn
y = sym('y',[1 n]); % Create n variables y1, y2, ..., yn
r = sym('r',[1 n]); % Create n variables r1, r2, ..., rn
% Symbolically sum equation
s = sum((k(1:end-1).*sqrt((x(2:end)-x(1:end-1)).^2+(y(2:end)-y(1:end-1)).^2)-r(1:end-1)).^2)
grad_x = gradient(s,x) % Gradient with respect to x vector
grad_y = gradient(s,y) % Gradient with respect to y vector
The symbolic sum and gradients can be evaluated and converted to floating point with:
% n random data values for k, x, y, and r
K = rand(1,n);
X = rand(1,n);
Y = rand(1,n);
R = rand(1,n);
% Substitute in data for symbolic variables
S = double(subs(s,{[k,x,y,r]},{[K,X,Y,R]}))
GRAD_X = double(subs(grad_x,{[k,x,y,r]},{[K,X,Y,R]}))
GRAD_Y = double(subs(grad_y,{[k,x,y,r]},{[K,X,Y,R]}))
The gradient function is the one overloaded for symbolic variables (type help sym/gradient) or see the more detailed documentation online).
Yes, you could indeed do this with a loop, considering that x, y, k, and r are already defined.
n = length(x);
s = 0;
for j = 2 : n
s = s + k(j-1) * (sqrt((x(j) - x(j-1)).^2 + (y(j) - y(j-1)).^2) - r(j-1)).^2
end
You should derive the gradient analytically and then plug in numbers. It should not be too hard to expand these terms and then find derivatives of the resulting polynomial.
Vectorized solution is something like (I wonder why do you use sqrt().^2):
is = 2:n;
result = sum( k(is - 1) .* abs((x(is) - x(is-1)).^2 + (y(is) - y(is-1)).^2 - r(is-1)));
You can either compute gradient symbolically or rewrite this code as a function and make a standard +-eps calculation. If you need a gradient to run optimization (you code looks like a fitness function) you could use algorithms that calculate them themselves, for example, fminsearch can do this

Write function with dynamic variables to get its Hessian matrix using syms, f, and hessian

My problem has 60 variables (x1 to x60) and here is the function:
f=(x1+x2+x3)*x1+(x2+x3+x4)*x2+...+(x58+x59+x60)*x58
I want to get the Hessian matrix of the function f. However, because there are so many variables, I don't want to write them one by one for syms and f.
I know I can manually calculate the Hessian matrix of the function f as the function is not too difficult. However, I occasionally need to change the form of the function, such as changing the function to (increase the number of variables in the brackets):
f=(x1+x2+x3+x4)*x1+(x2+x3+x4+x5)*x2+...+(x57+x58+x59+x60)*x57
Therefore, I don't want to manually compute the Hessian matrix of function f as long as the function form changes. Is there any easier way to use syms to write f with these 60 variables in MATLAB so that I can use hessian to get the Hessian matrix of f?
First, given the regular and simple nature of the function f described, your Hessian has a defined structure that can be directly calculated numerically. Like this, for example:
n = 60; % number of variables
b = 3; % number of terms in parentheses
h = diag(2+zeros(n,1));
for i = 1:b-1
d = diag(ones(n-i,1),i);
h = h+d+d.';
end
h(n-b+2:n,n-b+2:n) = 0
This can be done without a for loop via something like this:
n = 60; % number of variables
b = 3; % number of terms in parentheses
h = full(spdiags(repmat(ones(n,1),1,2*b-1),1-b:b-1,n,n)+speye(n));
h(n-b+2:n,n-b+2:n) = 0
Symbolically, you can create a vector of variables with sym to create your function and calculate the Hessian like this:
n = 60; % number of variables
b = 3; % number of terms in parentheses
x = sym('x',[n 1]); % vector of variables
f = 0;
for i = 1:n-b+1
f = f+sum(x(i:i+b-1))*x(i);
end
h = hessian(f,x)
It's possible to remove the for loops, but there won't be much performance benefit.