apply arrayfun for a couple of values - matlab

I wrote a syntax that calculate values of a function in different values.
For example
x1=[1 2 10 11];
x2=[10 11 12 14];
C= arrayfun (#(t1,t2) myfunction(A,B,t1,t2),x1,x2,'UniformOutput',0);
% A and B are matrixs
In this example the function will do an operation on A(x1,x2) and B(x1,x2) . The problem is that arrayfun will work on each couple (x1(1),x2(1)), x1(2),x2(2)),etc. But I want it to work on all the values of x1 and x2 (16 couples of values so that it can be applied also to for example (x1(1),x2(3))).
Is there any way to do that without a loop?

using ndgrid:
[X Y] = ndgrid(x1,x2);
C= arrayfun (#(x1,x2) myfunction(A,B,t1,t2),X(:),Y(:),'UniformOutput',0);

So I'm going to offer the "dumb" way of doing it without you having to modify your call to your function:
x1=[1 2 10 11];
x2=[10 11 12 14];
v = combvec(x1,x2);
X1 = v(1,:);
X2 = v(2,:);
C= arrayfun (#(X1,X2) myfunction(A,B,t1,t2),X1,X2,'UniformOutput',0);
This effectively calculated all combinations of x1 and x2, then you input it thru your function in pairs just like you were doing it before.

Related

How to create a symmetric matrix where each row/column is a subset of a known vector [duplicate]

This question already has an answer here:
How do I generate the following matrix and vector from the given input data in MATLAB?
(1 answer)
Closed 5 years ago.
I have a 7*1 vector a = (1:7).'. I want to form a matrix A of size 4*4 from vector a such that the elements of a form the anti-diagonals of matrix A as follows:
A = [1 2 3 4;
2 3 4 5;
3 4 5 6;
4 5 6 7]
I would like this to work for a general a, not just when the elements are consecutive integers.
I appreciate any help.
Setting up the indexing
Adding the two outputs of meshgrid can give the indices:
[x, y] = meshgrid(1:4, 0:3);
x + y;
% ans = [1 2 3 4
% 2 3 4 5
% 3 4 5 6
% 4 5 6 7];
If a was just as in your example you could stop there. Alternatively, use this to index a general vector a. For comparison, I'll use the same example input as rahnema1 did for their method:
a = [4 6 2 7 3 5 1];
[x, y] = meshgrid(1:4, 0:3);
A = a(x + y);
% A = [4 6 2 7
% 6 2 7 3
% 2 7 3 5
% 7 3 5 1]
There are many ways you could create the indices instead of using meshgrid, see the benchmarking functions below for some exampels!
Benchmarking and seven different methods.
Here are some timings for running different methods, including methods using cumsum, repmat, hankel and a simple for loop. This benchmark was done in Matlab 2015b, so takes advantage of Matlab optimisations etc. which the Octave benchmarks in rahnema1's answer might not do. I also use the timeit function which is more robust than tic/toc because it does multiple trials etc.
function benchie()
n = 10000; % (large) square matrix size
a = 1:2*n-1; % array of correct size, could be anything this long
f1 = #() m1(a,n); disp(['bsxfun: ', num2str(timeit(f1))]);
f2 = #() m2(a,n); disp(['cumsum: ', num2str(timeit(f2))]);
f3 = #() m3(a,n); disp(['meshgrid: ', num2str(timeit(f3))]);
f4 = #() m4(a,n); disp(['repmat: ', num2str(timeit(f4))]);
f5 = #() m5(a,n); disp(['for loop: ', num2str(timeit(f5))]);
f6 = #() m6(a,n); disp(['hankel1: ', num2str(timeit(f6))]);
f7 = #() m7(a,n); disp(['hankel2: ', num2str(timeit(f7))]);
end
% Use bsxfun to do broadcasting of addition
function m1(a,n); A = a(bsxfun(#plus, (1:n), (0:n-1).')); end
% Use cumsum to do cumulative vertical addition to create indices
function m2(a,n); A = a(cumsum([(1:n); ones(n-1,n)])); end
% Add the two meshgrid outputs to get indices
function m3(a,n); [x, y] = meshgrid(1:n, 0:n-1); A = a(x + y); end
% Use repmat twice to replicate the meshgrid results, for equivalent one liner
function m4(a,n); A = a(repmat((1:n)',1,n) + repmat(0:n-1,n,1)); end
% Use a simple for loop. Initialise A and assign values to each row in turn
function m5(a,n); A = zeros(n); for ii = 1:n; A(:,ii) = a(ii:ii+n-1); end; end
% Create a Hankel matrix (constant along anti-diagonals) for indexing
function m6(a,n); A = a(hankel(1:n,n:2*n-1)); end
% Create a Hankel matrix directly from elements
function m7(a,n); A = hankel(a(1:n),a(n:2*n-1)); end
Output:
bsxfun: 1.4397 sec
cumsum: 2.0563 sec
meshgrid: 2.0169 sec
repmat: 1.8598 sec
for loop: 0.4953 sec % MUCH quicker!
hankel1: 2.6154 sec
hankel2: 1.4235 sec
So you are best off using rahnema1's suggestion of bsxfun or direct generation of a hankel matrix if you want a one liner, here is a brilliant StackOverflow answer which explains some of bsxfun's advantages: In Matlab, when is it optimal to use bsxfun?
However, the for loop is more than twice as quick! Conclusion: Matlab has lots of neat ways to achieve things like this, sometimes a simple for loop with some appropriate pre-allocation and Matlab's internal optimisations can be the quickest.
You can use hankel:
n= 4;
A= hankel(a(1:n),a(n:2*n-1))
Other solution(expansion/bsxfun):
In MATLAB r2016b /Octave It can be created as:
A = a((1:4)+(0:3).')
In pre r2016b you can use bsxfun:
A = a(bsxfun(#plus,1:4, (0:3).'))
Example input/output
a = [4 6 2 7 3 5 1]
A =
4 6 2 7
6 2 7 3
2 7 3 5
7 3 5 1
Using the benchmark provided by #Wolfie tested in Octave:
_____________________________________
|Method |memory peak(MB)|timing(Sec)|
|=========|===============|===========|
|bsxfun |2030 |1.50 |
|meshgrid |3556 |2.43 |
|repmat |2411 |2.64 |
|hankel |886 |0.43 |
|for loop |886 |0.82 |

Recurring Function with Matrix Input

I believe most functions in MATLAB should be able to receive matrix input and return the output in the form of matrix.
For example sqrt([1 4 9]) would return [1 2 3].
However, when I tried this recurring factorial function:
function k = fact(z)
if z ~= 0
k = z * fact(z-1);
else
k = 1;
end
end
It works perfectly when a number is input into fact. However, when a matrix is input into fact, it returns the matrix itself, without performing the factorial function.
E.g.
fact(3) returns 6
fact([1 2 3]) returns [1 2 3] instead of [1 2 6].
Any help is appreciated. Thank you very much!
Since MATLAB is not known to be good with recursive functions, how about a vectorized approach? Try this for a vector input -
mat1 = repmat([1:max(z)],[numel(z) 1])
mat1(bsxfun(#gt,1:max(z),z'))=1
output1 = prod(mat1,2)
Sample run -
z =
1 2 7
output1 =
1
2
5040
For the sake of answering your original question, here's the annoying loopy code for a vector or 2D matrix as input -
function k1 = fact1(z1)
k1 = zeros(size(z1));
for ii = 1:size(z1,1)
for jj = 1:size(z1,2)
z = z1(ii,jj);
if z ~= 0
k1(ii,jj) = z .* fact1(z-1);
else
k1(ii,jj) = 1;
end
end
end
return
Sample run -
>> fact1([1 2 7;3 2 1])
ans =
1 2 5040
6 2 1
You can use the gamma function to compute the factorial without recursion:
function k = fact(z)
k = gamma(z+1);
Example:
>> fact([1 2 3 4])
ans =
1 2 6 24
Not sure if all of you know, but there is an actual factorial function defined in MATLAB that can take in arrays / matrices of any size, and computes the factorial element-wise. For example:
k = factorial([1 2 3 4; 5 6 7 8])
k =
1 2 6 24
120 720 5040 40320
Even though this post is looking for a recursive implementation, and Divakar has provided a solution, I'd still like to put my two cents in and suggest an alternative. Also, let's say that we don't have access to factorial, and we want to compute this from first principles. What I would personally do is create a cell array that's the same size as the input matrix, but each element in this cell array would be a linear index array from 1 up to the number defined for each location in the original matrix. You would then apply prod to each cell element to compute the factorial. A precondition is that no number is less than 1, and that all elements are integers. As such:
z1 = ... ; %// Define input matrix here
z1_matr = arrayfun(#(x) 1:x, z1, 'uni', 0);
out = cellfun(#prod, z1_matr);
If z1 = [1 2 3 4; 5 6 7 8];, from my previous example, we get the same output with the above code:
out =
1 2 6 24
120 720 5040 40320
This will obviously be slower as there is an arrayfun then cellfun call immediately after, but I figured I'd add another method for the sake of just adding in another method :) Not sure how constructive this is, but I figured I'd add my own method and join Divakar and Luis Mendo :)

Creating a matrix from a function handle (MATLAB)

What I intend to do is very simple but yet I haven't found a proper way to do it. I have a function handle which depends on two variables, for example:
f = #(i,j) i+j
(mine is quite more complicated, though)
What I'd like to do is to create a matrix M such that
M(i,j) = f(i,j)
Of course I could use a nested loop but I'm trying to avoid those. I've already managed to do this in Maple in a quite simple way:
f:=(i,j)->i+j;
M:=Matrix(N,f);
(Where N is the dimension of the matrix) But I need to use MATLAB for this. For now I'm sticking to the nested loops but I'd really appreciate your help!
Use bsxfun:
>> [ii jj] = ndgrid(1:4 ,1:5); %// change i and j limits as needed
>> M = bsxfun(f, ii, jj)
M =
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
5 6 7 8 9
If your function f satisfies the following condition:
C = fun(A,B) accepts arrays A and B of arbitrary, but equal size and returns output of the same size. Each element in the output array C is the result of an operation on the corresponding elements of A and B only. fun must also support scalar expansion, such that if A or B is a scalar, C is the result of applying the scalar to every element in the other input array.
you can dispose of ndgrid. Just add a transpose (.') to the first (i) vector:
>> M = bsxfun(f, (1:4).', 1:5)
Function handles can accept matrices as inputs. Simply pass a square matrix of size N where the values corresponds to the row number for i, and a square matrix of size N where the values correspond to the column number for j.
N = 5;
f = #(i,j) i+j;
M = f(meshgrid(1:N+1), meshgrid(1:N+1)')

Force entries of a matrix to be a variable

I have a square matrix that I need to use with fminsearch. Some of the values of the matrix need to be variable because they are the values that I will be using with fminsearch, and I need to preserve their location in the matrix. So for example, with
X=[1,2,3;4,5,6;7,8,9];
I would like make this
p(1)=a1;
p(2)=a2;
p(3)=a3;
p(4)=a4;
X=[1, 2, a1 ; a2, 5, a3 ; 7, 8, a4];
So that I could do operations on X to create something to be minimized with fminsearch. For example, suppose I wanted to find a1, a2, a3, and a4 so that I minimized C in the following code, which computes the summed entropy of a given matrix:
Ent=zeros(size(X,1),1);
for k=1:size(X,2);
const=X(k,:);
logX=log(X(k,:));
logX=logX';
Ent(k,:)=const*logX;
end
Ent=-Ent;
C=sum(Ent);
Is this possible with MATLAB? Suppose further I had an nxn matrix with q paramaters, how would I adjust the idea to minimize the same C?
EDIT:
I figured out how to do what I want. However it has come to me that a gradient descent algorithm is really a better way of doing this. I'll post a sample of what I was doing:
function test()
[new_param entropy]=fminsearch(#Cost,[3,3,3]);
function C=Cost(p)
X=rand(5);
X(1,1)=p(1);
X(2,2)=p(2);
X(3,3)=p(3);
Ent=zeros(size(X,1),1);
for k=1:size(X,2);
const=X(k,:);
logX=log(X(k,:));
logX=logX';
Ent(k,:)=const*logX;
end
Ent=-Ent;
C=sum(Ent);
end
X(1,1)=new_param(1);
X(2,2)=new_param(2);
X(3,3)=new_param(3);
X
new_param
entropy
end
I think that you could try something like this:
A = #(x) [1 2 x(1); 3 4 x(2); 5 6 x(3)];
or, alternatively, making use of the Symbolic Toolbox:
syms x y z
A = [1 2 x; 3 4 y; 5 6 z];
I may misunderstand, but I think it is as simple as this:
X=[1, 2, p(1) ; p(2), 5, p(3) ; 7, 8, p(4)];
After updating p just run this statement again and you have your desired X.

vectorized function fminsearch

Thank you very much,first. The first code runs well:
function f=malibu(m1,m2,m3,k,l,t)
f=(m1.*k+(m1+m2).*l).*exp(-m3.*t);
end
function loglik= modelmalibu(p)
global k l t x n m2 m3;
f =malibu(p,m2,m3,k,l,t);
if f==0;
loglik0=0;
else
loglik0=(x.*log(f)+(n-x).*log(1-f));%minus likelihood
end
loglik=sum(-loglik0);
end
clear all;
global n t x k l m2 m3;
m1=0.1;
m2=0.2;
m3=0.3;
t=[1 3 6 9 12 18]';
k=[1 1 2 3 3 4]';
l=[0 0 1 3 4 5]';
y=meltem(m1,m2,m3,k,l,t);
n=100;%trial
x=y.*n;%correct replies
pstart=0.3;
[p1,modelvalue]=fminsearch(#modelmalibu,pstart);
But the similar code for more variable gives error out.
function w=anemon(m1,m2,m3,X,Y,k,l)
w=(m1.*k+(m1+m2).*l)+X.*exp(-m3.*Y);
end
function loglik= modelanemon(p)
global n x m2 m3 X Y k l ;
f =anemon(p,m2,m3,X,Y,k,l);
if f==0;
loglik0=0;
else
loglik0=(x*log(f)+(n-x)*log(1-f));%minus likelihood
end
loglik=sum(-loglik0);
end
clear;
global n x Ydata kdata ldata m1 m2 m3;
%parameters
m1=0.002;
m2=0.0001;
m3=7;
%given data
Xdata=[1 3 6 9 10 12]';
Ydata=[11 13 41 81 121 181]';
kdata=[1 1 2 4 5 4]';
ldata=[1 1 3 3 4 5]';
y=anemon(m1,m2,m3,Xdata,Ydata,kdata,ldata);
n=10;
x=y.*n;
pstart=2;
[pbest,modelvalue]=fminsearch(#modelanemon,pstart);
I've actually tried to use your advises, but if I would write an inequality instead of f==0, the first code fall down as well.
I think you are mixing up two concepts.
vectorization: does refer in how to write your code so it can use some of the acceleration functions in your CPU. it has nothing to do with fminsearch. See: http://en.wikipedia.org/wiki/Vectorization_(parallel_computing)
I suppose you want to write your function such that it accepts a vector as input. Easiest way is to just use a function handle like this:
fh = #(x) my_complicated_function(const1, const2, x(1), x(2), x(3) )
In this case my_complicated_function has 5 inputs, and you take the first 2 constant and input a 3 dim vector for the other 3. Fminsearch will work with that.
You would call
x_opt = fminsearch(fh, [1,2,3])
Besides some tips for the code:
Don't use == for comparison of numbers - go for eg. abs(x1-x2)<0.1 instead
interpanemon looks very strange - it doesn't do what one would call interpolation, and if you look - in every iteration p is recalculated so only the last calculation takes effect. As it looks it should output a constant value - no use optimizing that.
The use of a precalculated Z is probably not what you want. It already determines your optimum. If you use linear optimization the optimum must be already in Z - no need doing interpolation.
The invocation in your case might look like:
min_p = fminsearch(#(x) interpanemon(5,Ydata,x,m2,m3,Z,X,Y,kdata,ldata) ,1)
Overall it looks very unusual - it could really help if you would explain the ideas WHY you choose to do it like this. Also it might help if you restate the problem in a simpler form.