Passing additional arguments through function handle to do optimization in Matlab - matlab

I have a function to optimize, say f,in matlab, the function depends on variable x=(x(1),x(2))over which I want to optimize and two parameters n and c which does not need to be optimize, In other words, I have an matrix of values for n and c and I want to find optimal x values for each n and c.
Here is my code:
clear all;
clc;
close all;
f=#(x,n,c)n*x(1)+(x(2)+3*c)/(x(1)+c);
for n=1:10
for c=1:20
x=zeros(length(n),length(c));
fun{n,c}=#(x)f(x,n,c);
options=optimset('Algorithm','interior-point')
x(n,c)=fmincon(fun{n,c},[0;0],[1 0;-1 0;0 1;0 -1],[40;0;40;0],[],[],[],[],[],options);
end
end
??? Subscripted assignment dimension mismatch.
Error in ==> forloop2 at 10
x(n,c)=fmincon(fun{n,c},[0;0],[1 0;-1 0;0 1;0
-1],[40;0;40;0],[],[],[],[],[],options);
Any helps? Thank you so much!

I'm afraid you didn't actually ask a Question, but here's an answer:
function myOptimization
clear all;
clc;
close all;
results=cell(10,20);
for n=1:10
for c=1:20
options=optimset('Algorithm','interior-point');
fmincon(#(x)fun(x,n,c),[0;0],[1 0;-1 0;0 1;0 -1],[40;0;40;0],[],[],[],[],[],options);
resultingCoordinates=fmincon(#(x)fun(x,n,c),[0;0],[1 0;-1 0;0 1;0 -1],[40;0;40;0],[],[],[],[],[],options);
results{n,c}=resultingCoordinates;
end
end
results
end
function f=fun(x,n,c)
f=n*x(1)+(x(2)+3*c)/(x(1)+c);
end
You made at least 3 errors in your original code.
First, x(n,c) = fmincon... doesn't work because fmincon returns an vector with the optimal coordinates as the first output argument. Therefore, you are trying to assign a vector to a single location in the matrix "x", which is the source of your error. I put the optimal coordinates in a cell array, so that I can store all the output coordinates. If you wanted the optimal "f-value" to be assigned to your results as a matrix, you can use [~,f(n,c)]=fmincon... .
Second, "x" is a really bad name for your output matrix, even if you wanted to save the coordinates. It may even cause you errors as it's used to represent the input to your objective function, not the optimum coordinates. Use a different name for the optimum coordinates or optimal function values, which reflects that these are results.
Third, you don't need to continuously re-allocate the output matrix/cell array each time you change your parameters. Your essentially trying to clear the results each iteration, which doesn't work if you want to save them.
I also split up your objective function to be a function, and the optimization of that function to be another.
I hope this helps. In the future, please try to define a clear question on Stack Overflow.

Related

Matlab. Poisson fit. Factorial

I have a histogram that seems to fit a poisson distribution.
In order to fit it, I declare the function myself as follows
xdata; ydata; % Arrays in which I have stored the data.
%Ydata tell us how many times the xdata is repeated in the set.
fun= #(x,xdata) (exp(-x(1))*(x(1).^(xdata)) )/(factorial(xdata)) %Function I
% want to use in the fit. It is a poisson distribution.
x0=[1]; %Approximated value of the parameter lambda to help the fit
p=lsqcurvefit(fun,x0,xdata,ydata); % Fit in the least square sense
I find an error. It probably has to do with the "factorial". Any ideas?
Factorial outputs a vector from vector xdata. Why are you using .xdata in factorial?
For example:
data = [1 2 3];
factorial(data) is then [1! 2! 3!].
Try ./factorial(xdata) (I cannot recall if the dot is even necessary at this case.)
You need to use gamma(xdata+1) function instead of factorial(xdata) function. Gamma function is a generalized form of factorial function which can be used for real and complex numbers. Thus, your code would be:
fun = #(x,xdata) exp(-x(1))*x(1).^xdata./gamma(xdata+1);
x = lsqcurvefit(fun,1,xdata,ydata);
Alternatively, you can MATLAB fitdist function which is already optimized and you might get better results:
pd = fitdist(xdata,'Poisson','Frequency',ydata);
pd.lambda

Parallelize MATLAB for loop to calculate MLE

I am attempting to speed up my MATLAB code by using parfor, however, I am doing it incorrectly. My code is rather simple, I am fitting some data using MATLAB's built-in mle function by using varying initial guesses for the mean (mm) and variance (vv). onestagepdf2 is my probability density function.
Here is the code snippit:
mm=linspace(.1, 1, 2); % mean
vv=linspace(.1, 2, 2); % variance
N=length(mm);
n=length(vv);
pd=zeros(n*N,2);
ld = NaN*ones(n*N,1);
options = statset('MaxIter',10000, 'MaxFunEvals',10000);
parfor i=1:N % pick a mean
m=mm(i);
parfor j=1:n % pick a variance
v=vv(j);
x0=[m,v];
[p,conf1]=mle(data,'pdf',#onestagepdf2,'start',x0, 'upperbound', [Inf Inf],'lowerbound',[0 0],'options',options)
pd(n*(i-1)+j,:)=p; % store parameter values from mle
l=onestagepdf2(data,p(1),p(2)); % evaluate pdf with parameter values
ld(n*(i-1)+j)=sum(log(l)); % store likelihood value
end
end
The error that I receive is:
'The variable pd in a parfor cannot be classified.'
pd = zeros(n, N, 2); %initialise culprits
ld= zeros(n,N);
parfor ii=1:N % pick a mean
m=mm(ii);
for jj=1:n % Parallellise the second parfor
v=vv(jj);
x0=[m,v];
[p,conf1]=mle(data,'pdf',#onestagepdf2,'start',x0, 'upperbound', [Inf Inf],'lowerbound',[0 0],'options',options)
pd(ii, jj, :) = p;=p; % store parameter values from mle
l=onestagepdf2(data,p(1),p(2)); % evaluate pdf with parameter values
ld(ii,jj)=sum(log(l)); % store likelihood value
end
end
Your pd was indeed the culprit, as #Trilarion stated, for the error you got. Probably ld also isn't too great, with the same syntax, so initialise that as well. This happened because parfor wants to know what the size of all variables within the loop is before executing. That this is a fixed maximum size is unknown to MATLAB, since you are using the loop variables to "change" the size.
Probably you had "orange wiggles" below those two lines (like spell-check errors) when you ran this as a for loop saying that "pd appears to be growing in size each iteration. Please consider preallocating for speed". This is required by parfor, since the order of iteration is not sequential it is impossible to grow arrays this way.
Secondly, you cannot nest parfor loops. You can use things like a function with a parfor and run that within the parfor, but that won't get you a speed-up since you are already using all your workers.
See Saving time and memory using parfor in Matlab? for more general information on parfor especially on speed.
You want a sliced, output variable but Matlab is not clever enough to detect that n*(i-1)+j is actually reasonable and won't interfere with an asynchronous evaluation.
Just do it as separate dimensions
pd = zeros(n, N, 2);
...
% in the loop
pd(i, j, :) = p;
That will work.
Please note, that Matlab does not allow nested parfors. However, you also do not need them if N is larger than the number of workers. See also the documentation.

How can I calculate dyadics in matlab without using for loops?

I was wondering if someone could help me with my problem.
Let say that I have the coordinates of MxN vectors in a tensor r of dimensions [M,N,3]. I would like to save in a 3M-by-3N block matrix all dyadic products r_0'*r_0, where r_0 is the vector r_0 = r(m,n,:) for some m and n, and I would like to do this without using for loops.
If haven't explain myself correctly, here is an example code that shows what I would like to obtain (but using for loops, of course):
N=10;
M=5;
r=rand(M,N,3);
Dyadic=zeros(3*M,3*N);
for m=1:M
a1=3*m-2;
a2=3*m;
for n=1:N
b1=3*n-2;
b2=3*n;
aux(3)=r(m,n,3);
aux(2)=r(m,n,2);
aux(1)=r(m,n,1);
Dyadic(a1:a2,b1:b2)=transpose(aux)*aux
end
end
Thanks in advance!
You need to use bsxfun(#times and then re-arrange elements to have the desired output -
%// Get the multipliication result
mat_mult = bsxfun(#times,permute(r,[1 2 4 3]),r);
%// OR if you would like to keep mat_mult as 3D that could be potentially faster -
%// mat_mult = bsxfun(#times,reshape(r,[],3),permute(reshape(r,[],3),[1 3 2]));
%// Re-arrange elements to have them the way you are indexing in nested loops
Dyadic = reshape(permute(reshape(mat_mult,M,N,3,[]),[3 1 4 2]),M*3,N*3);
The major play about this solution is really the re-arrangement of elements after we have the multiplication result.
Quick runtime tests with the input r as 1000 x 1000 x 3 sized array, show that this bsxfun based approach gives over 20x speedup over the nested loop code listed in the question!

Vectorizing code

I dont quite get the vectorizing way of thinking of matlab, mostly due to the simple examples provided in the documentation, and i hope someone can help me understand it a little better.
So, what i'm trying to accomplish is to take a sample of NxN from a matrix of ncols x nrows x ielements and compute the average for each ielement and store the maximum of the averages. Using for loops, the code would look like this:
for x = 1+margin : nrows-margin
for y = 1+margin : ncols-margin
for i=1:ielem
% take a NxN sample
sample = input_matrix(y-margin:y+margin,x-margin:x+margin,i)
% compute the average of all elements
result(i) = mean2(sample);
end %for i
% store the max of the computed averages
output_matrix(y,x)=max(result);
end %for y
end %for x
can anyone do a good vectorization of this example of a situation ? T
First of all, vectorization is not as important as it once was, due to enhancements in compiling the code before it is ran, but it's still a very common practice and can lead to some enhancements. Older Matlab version executed one line at a time, which would leave a for loop much slower than a vectorized version of the same code.
The part of your matrix that could be vectorized is the inner more for loop. I'll show a simple example of what you are trying to do, I'll let you take the example and put it into your code.
input=randn(5,5,3);
max(mean(mean(input,1),2))
Basically, the inner two mean take the mean of the input array, and the outer max will find the maximum value over the range. If you want, you can break it out step by step, and see what it does. The mean(input,1) will take the mean over the first dimension, mean(input,2) over the second, etc. After the first two means are done, all that is left is a vector, which the max function will easily work. It should be noted that the size of the vector pre-max is [1 1 3], the dimensions are preserved when doing this operation.

Indexing Matrices Matlab

I'm trying to compute two matrices , one of which is 400*2 and the other being 20*20. The first one contains x and y coordinates of 400 points and the second being another 400 points with x's being 2nd(i,i) and y's being (i,k) both i and k's are 20 number counters.I'm trying to compute the distances between those 2 matrix points which would give me 400*400 matrix. The code i'm using is ;
for i=1:20
for j=1:400
for k=1:20
L(j,)=sqrt((C(j,1)-M(i,i))^2+(C(j,2)-M(k,i))^2);
end
end
end
C being the first matrix and M being the second. Now i know i made it sound a little hard but the trouble is i cant find a counter to give to L(j, ) that part. If you guys have any idea please do tell...
Edit: Well first of all think there is 2 point vectors. X's being -0.95:0.1:0.95 and y's are the same. M vector is that all of the x's paired with a Y so it would make 20*20 matrix or a 400*2 however i could not make it work like a 400*2 so have gone with 20*20.The matrix is a little hard for me to do so my indexing of M shows that.If you got a better way to pair them i would appreciate it as well.
My matrix looks like this ;
-0.95 -0.85 -0.75...
-0.95 -0.85 -0.75 ...
.
.
.
The above code should be very slow... Using a lot of for-loop is not "matlab-style"
What I would do is:
Mdiag=repmat(diag(M)',20,1);
L=pdist2(C,[Mdiag(:) M(:)]);
The first line extracts the diagonal terms of M and repeat them.
After that [Mdiag(:) M(:)] is a standard form of your second set of points.
pdist2 is a function that compute all the pairwise distances.
Does it matter what order they are in? I am assuming it doesn't, so long as you know what that order is. I'd use this:
for i=1:20
for j=1:400
for k=1:20
L(j,(i-1)*20+k) = sqrt((C(j,1)-M(i,i))^2+(C(j,2)-M(k,i))^2);
end
end
end