Create a variable number of terms in an anonymous function that outputs a vector - matlab

I'd like to create an anonymous function that does something like this:
n = 5;
x = linspace(-4,4,1000);
f = #(x,a,b,n) a(1)*exp(b(1)^2*x.^2) + a(2)*exp(b(2)^2*x.^2) + ... a(n)*exp(b(n)^2*x.^2);
I can do this as such, without passing explicit parameter n:
f1 = #(x,a,b) a(1)*exp(-b(1)^2*x.^2);
for j = 2:n
f1 = #(x,a,b) f1(x,a,b) + a(j)*exp(b(j)^2*x.^2);
end
but it seems, well, kind of hacky. Does someone have a better solution for this? I'd like to know how someone else would treat this.

Your hacky solution is definitely not the best, as recursive function calls in MATLAB are not very efficient, and you can quickly run into the maximum recursion depth (500 by default).
You can introduce a new dimension along which you can sum up your arrays a and b. Assuming that x, a and b are row vectors:
f = #(x,a,b,n) a(1:n)*exp((b(1:n).^2).'*x.^2)
This will use the first dimension as summing dimension: (b(1:n).^2).' is a column vector, which produces a matrix when multiplied by x (this is a dyadic product, to be precise). The resulting n * length(x) matrix can be multiplied by a(1:n), since the latter is a matrix of size [1,n]. This vector-matrix product will also perform the summation for us.
Mini-proof:
n = 5;
x = linspace(-4,4,1000);
a = rand(1,10);
b = rand(1,10);
y = 0;
for k=1:n
y = y + a(k)*exp(b(k)^2*x.^2);
end
y2 = a(1:n)*exp((b(1:n).^2).'*x.^2); %'
all(abs(y-y2))<1e-10
The last command returns 1, so the two are essentially identical.

Related

Meshgrid and double for-loops does not result in the same matrix, why?

I am trying to evaluate all values the expression f = 2y-exp(z) can take for different values of z and y. Were y and z are two vectors of length M. I am wondering why the two approaches for generating the expression f yields different results.
Using meshgrid:
[Y,Z] = meshgrid(y,z);
argument = 2*Y-exp(Z);
and with double for-loops
argument_new = zeros(M,M);
for i = 1:length(y)
for j = 1:length(z)
argument_new(i,j) = 2*y(i)-exp(z(j));
end
end
Any hints will be highly appreciated!
That's because of the way meshgrid creates 'inverted' directions. I don't find the right words, but here is an example illustrating with your code.You see that if you uncomment option 2 and use argument_new(j,i) instead of argument_new(i,j) both matrices are equal (as obtained with isequal).
clear
clc
M = 20;
y = 1:M;
z = 1:M;
[Y,Z] = meshgrid(y,z);
argument = 2*Y-exp(Z);
argument_new = zeros(M,M);
for i = 1:length(y)
for j = 1:length(z)
%// 1)
argument_new(i,j) = 2*y(i)-exp(z(j));
%// 2)
%// argument_new(j,i) = 2*y(i)-exp(z(j));
end
end
isequal(argument,argument_new) %// Gives 0 for option 1 and 1 for option 2.
Blame that on meshgrid:
MESHGRID is like NDGRID except that the order of the first two input
and output arguments are switched (i.e., [X,Y,Z] = MESHGRID(x,y,z)
produces the same result as [Y,X,Z] = NDGRID(y,x,z)).
Solution: use ndgrid, which doesn't do that switching, and is thus more "natural":
[Y,Z] = ndgrid(y,z);
argument = 2*Y-exp(Z);
Or in your code, after meshgrid, add a transpose operation: argument = argument.';)
They are the same, you should just transpose either one (' in Matlab), or you can replace i by j and vice versa in the for loops

Efficient way to apply arrayfun to a matrix (i.e. R^N to R^M)

I have a function that transforms R^N to R^M. For simplicity, lets just let it be the identity function #(z) z where z may be a vector. I want to apply a function to a list of parameters of size K x N and have it map to K x M output.
Here is my attempt:
function out_matrix = array_fun_matrix(f, vals)
for i=1:size(vals,1)
f_val = f(vals(i,:));
if(size(f_val,1) > 1) %Need to stack up rows, so convert as required.
f_val = f_val';
end
out_matrix(i,:) = f_val;
end
end
You can try it with
array_fun_matrix(#(z) z(1)^2 + z(2)^2 + z(3), [0 1 0; 1 1 1; 1 2 1; 2 2 2])
The question: Is there a better and more efficient way to do this with vectorization, etc.? Did I miss a built-in function?
Examples of non-vectorizable functions: There are many, usually involving elaborate sub-steps and numerical solutions. A trivial example is something like looking for the numerical solution to an equation, which in term is using numerical quadrature. i.e. let params = [b c] and solve for the a such that int_0^a ((z + b)^2) dz = c
(I know here you could do some calculus, but the integral here is stripped down). Implementing this example,
find_equilibrium = #(param) fzero(#(a) integral(#(x) (x + param(1)).^2 - param(2), 0, a), 1)
array_fun_matrix(find_equilibrium, [0 1; 0 .8])
You can use the cellfun function, but you'll need to manipulate your data a bit:
function out_matrix = array_fun_matrix(f, vals)
% Convert your data to a cell array:
cellVals = mat2cell(vals, ones(1,size(vals,1)));
% apply the function:
out_cellArray = cellfun(f, cellVals, 'UniformOutput', false);
% Convert back to matrix:
out_matrix = cell2mat(out_cellArray);
end
If you don't like this implementation, you can improve the performance of yours by preallocating the out_matrix:
function out_matrix = array_fun_matrix(f, vals)
firstOutput = f(vals(1,:));
out_matrix = zeros(size(vals,1), length(firstOutput)); % preallocate for speed.
for i=1:size(vals,1)
f_val = f(vals(i,:));
if(size(f_val,1) > 1) %Need to stack up rows, so convert as required.
f_val = f_val';
end
out_matrix(i,:) = f_val;
end
end

MATLAB Discretizing Sine Function with +/-

Hello I am relatively new to MATLAB and have received and assignment in which we could use any programming language. I would like to continue MATLAB and have decided to use it for this assignment. The questions has to do with the following formula:
x(t) = A[1+a1*E(t)]*sin{w[1+a2*E(t)]*t+y}(+/-)a3*E(t)
The first question we have is to develop an appropriate discretization of x(t) with a time step h. I think i understand how to do this using step but because there is a +/- in the end I am running into errors. Here is what I have (I have simplified the equation by assigning arbitrary values to each variable):
A = 1;
E = 1;
a1 = 1;
a2 = 2;
a3 = 3;
w = 1;
y = 0;
% ts = .1;
% t = 0:ts:10;
t = 1:1:10;
x1(t) = A*(1+a1*E)*sin(w*(1+a2*E)*t+y);
x2(t) = a3*E;
y(t) = [x1(t)+x2(t), x1(t)-x2(t)]
plot(y)
The problem is I keep getting the following error because of the +/-:
In an assignment A(I) = B, the number of elements in B and I must be the same.
Error in Try1 (line 21)
y(t) = [x1(t)+x2(t), x1(t)-x2(t)]
Any help?? Thanks!
You can remove the (t) from the left-hand side of all three assignments.
y = [x1+x2, x1-x2]
MATLAB knows what to do with vectors and matrices.
Or, if you want to write it out the long way, tell MATLAB there will be two columns:
y(t, 1:2) = [x1(t)'+x2(t)', x1(t)'-x2(t)']
or two rows:
y(1:2, t) = [x1(t)+x2(t); x1(t)-x2(t)]
But this won't work when you have fractional values of t. The value in parentheses is required to be the index, not a dependent variable. If you want the whole vector, just leave it out.

Iterating over all integer vectors summing up to a certain value in MATLAB?

I would like to find a clean way so that I can iterate over all the vectors of positive integers of length, say n (called x), such that sum(x) == 100 in MATLAB.
I know it is an exponentially complex task. If the length is sufficiently small, say 2-3 I can do it by a for loop (I know it is very inefficient) but how about longer vectors?
Thanks in advance,
Here is a quick and dirty method that uses recursion. The idea is that to generate all vectors of length k that sum to n, you first generate vectors of length k-1 that sum to n-i for each i=1..n, and then add an extra i to the end of each of these.
You could speed this up by pre-allocating x in each loop.
Note that the size of the output is (n + k - 1 choose n) rows and k columns.
function x = genperms(n, k)
if k == 1
x = n;
elseif n == 0
x = zeros(1,k);
else
x = zeros(0, k);
for i = 0:n
y = genperms(n-i,k-1);
y(:,end+1) = i;
x = [x; y];
end
end
Edit
As alluded to in the comments, this will run into memory issues for large n and k. A streaming solution is preferable, which generates the outputs one at a time. In a non-strict language like Haskell this is very simple -
genperms n k
| k == 1 = return [n]
| n == 0 = return (replicate k 0)
| otherwise = [i:y | i <- [0..n], y <- genperms (n-i) (k-1)]
viz.
>> mapM_ print $ take 10 $ genperms 100 30
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,100]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,99]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,98]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,97]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,96]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,95]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,94]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,93]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,92]
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,91]
which runs virtually instantaneously - no memory issues to worry about.
In Python you could achieve something nearly as simple using generators and the yield keyword. In Matlab it is certainly possible, but I leave the translation up to you!
This is one possible method to generate all vectors at once (will give memory problems for moderately large n):
s = 10; %// desired sum
n = 3; %// number of digits
vectors = cell(1,n);
[vectors{:}] = ndgrid(0:s); %// I assume by "integer" you mean non-negative int
vectors = cell2mat(cellfun(#(c) reshape(c,1,[]), vectors, 'uni', 0).');
vectors = vectors(:,sum(vectors)==s); %// each column is a vector
Now you can iterate over those vectors:
for vector = vectors %// take one column at each iteration
%// do stuff with the vector
end
To avoid memory problems it is better to generate each vector as needed, instead of generating all of them initially. The following approach iterates over all possible n-vectors in one for loop (regardless of n), rejecting those vectors whose sum is not the desired value:
s = 10; %// desired sum
n = 3;; %// number of digits
for number = 0: s^n-1
vector = dec2base(number,s).'-'0'; %// column vector of n rows
if sum(vector) ~= s
continue %// reject that vector
end
%// do stuff with the vector
end

Looping with two variables from a vector

I have a 30-vector, x where each element of x follows a standardised normal distribution.
So in Matlab,
I have:
for i=1:30;
x(i)=randn;
end;
Now I want to create 30*30=900 elements from vector, x to make a 900-vector, C defined as follows:
I am unable to do the loop for two variables (k and l) properly. I have:
for k=1:30,l=1:30;
C(k,l)=(1/30)*symsum((x(i))*(x(i-abs(k-l))),1,30+abs(k-l));
end
It says '??? Undefined function or method 'symsum' for input arguments of type
'double'.'
I hope to gain from this a 900-vector, C which I will then rewrite as a matrix. The reason I have using two indices k and l instead of one is because I eventually want these indices to denote the (k,l)-entry of such a matrix so it is important that that my 900-vector will be in the form of C = [ row 1 row 2 row 3 ... row 30 ] so I can use the reshape tool i.e.
C'=reshape(C,30,30)
Could anyone help me with the code for the summation and getting such a 900 vector.
Let's try to make this a bit efficient.
n = 30;
x = randn(n,1);
%# preassign C for speed
C = zeros(n);
%# fill only one half of C, since it's symmetric
for k = 2:n
for l = 1:k-1
%# shift the x-vector by |k-l| and sum it up
delta = k-l; %# k is always larger than l
C(k,l) = sum( x(1:end-delta).*x(1+delta:end) );
end
end
%# fill in the other half of C
C = C + C';
%# add the diagonal (where delta is 0, and thus each
%# element of x is multiplied with itself
C(1:n+1:end) = sum(x.^2);
It seems to me that you want a matrix C of 30x30 elements.
Given the formula that you provided I would do
x = randn(1,30)
C = zeros(30,30)
for k=1:30
for l=1:30
v = abs(k-l);
for i =1:30-v
C(k,l) = C(k,l) + x(i)*x(i+v);
end
end
end
if you actually need the vector you can obtain it from the matrix.