Nested anonymous functions including arrayfun - matlab

I'm trying to do something like the following code:
k = linspace(a,b);
x = c:0.01:d;
% k and x are of different sizes
f = #(s) arrayfun(#(t) normcdf(s, b0+b1*t, sigma), x);
y = arrayfun(f, k);
I get the following error
Error using arrayfun Non-scalar in Uniform output, at index 1,
output 1. Set 'UniformOutput' to false.
I'm trying to avoid using a for loop for each element in k.
Also, for each result matching an element in k, I need to do another small calculation
Example with a loop:
for i=1:m % m is the number of elements in k
f = #(t) normcdf(k(i), b0+b1*x, sigma);
y = arrayfun(f, x);
res(i) = trapz(x,y);
end
any idea how can I get the same result as the for loop with the first method?
and why am I getting the error?

I would suggest the following:
k = linspace(a,b);
x = c:0.01:d;
[X,K] = meshgrid(x,k)
y = arrayfun(#(p,t) normcdf(p, b0+b1*t, sigma), K(:), X(:))
res = cumtrapz(x,y)
Untested though as you gave no example data and desired results. Maybe you need to swap the order of x and k as well as X and K to get the desired result. (or use ndgrid instead of meshgrid, has the same effect)

Related

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

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.

Numerical Integral in MatLab using integral command

I am trying to compute the value of this integral using Matlab
Here the other parameters have been defined or computed in the earlier part of the program as follows
N = 2;
sigma = [0.01 0.1];
l = [15];
meu = 4*pi*10^(-7);
f = logspace ( 1, 6, 500);
w=2*pi.*f;
for j = 1 : length(f)
q2(j)= sqrt(sqrt(-1)*2*pi*f(j)*meu*sigma(2));
q1(j)= sqrt(sqrt(-1)*2*pi*f(j)*meu*sigma(1));
C2(j)= 1/(q2(j));
C1(j)= (q1(j)*C2(j) + tanh(q1(j)*l))/(q1(j)*(1+q1(j)*C2(j)*tanh(q1(j)*l)));
Z(j) = sqrt(-1)*2*pi*f(j)*C1(j);
Apprho(j) = meu*(1/(2*pi*f(j))*(abs(Z(j))^2));
Phi(j) = atan(imag(Z(j))/real(Z(j)));
end
%integration part
c1=w./(2*pi);
rho0=1;
fun = #(x) log(Apprho(x)/rho0)/(x.^2-w^2);
c2= integral(fun,0,Inf);
phin=pi/4-c1.*c2;
I am getting an error like this
could anyone help and tell me where i am going wrong.thanks in advance
Define Apprho in a separate *.m function file, instead of storing it in an array:
function [ result ] = Apprho(x)
%
% Calculate f and Z based on input argument x
%
% ...
%
meu = 4*pi*10^(-7);
result = meu*(1/(2*pi*f)*(abs(Z)^2));
end
How you calculate f and Z is up to you.
MATLAB's integral works by calling the function (in this case, Apprho) repeatedly at many different x values. The x values called by integral don't necessarily correspond to the 1: length(f) values used in your original code, which is why you received errors.

In matlab how to use if loop having condition (a is a scalar number and is equal to any element in a vector v of n length)

I have a function replace_me which is defined like as: function w = replace_me(v,a,b,c). The first input argument v is a vector, while a, b, and c are all scalars. The function replaces every element of v that is equal to a with b and c. For example, the command
x = replace_me([1 2 3],2,4,5); returns x as [1 4 5 3].
The code that I have created is
function w = replace_me(v,a,b,c)
[row,column]=size(v);
new_col=column+1;
w=(row:new_col);
for n=(1:column)
if a==v(n)
v(n)=b;
o=n;
d=n-1;
u=n+1;
for z=1:d
w(z)=v(z);
end
for z=u:column
w(z+1)=v(z);
end
w(o)=b;
w(o+1)=c;
end
end
end
It works perfectly fine for x = replace_me([1 2 3],2,4,5); I get required output but when I try x = replace_me([1 2 3], 4, 4, 5) my function fails.
To resolve this problem I want to use an if else statements having conditions that if a is equal to any element of vector v we would follow the above equation else it returns back the vector.
I tried to use this as if condition but it didn't worked
if v(1:column)==a
Any ideas
I'm not entirely sure if I understand what you are trying to achieve, but form what I understand you're looking for something like this:
function [v] = replace_me(v,a,b,c)
v = reshape(v,numel(v),1); % Ensure that v is always a column vector
tol = 0.001;
aPos = find( abs(v-a) < tol ); % Used tol to avoid numerical issues as mentioned by excaza
for i=numel(aPos):-1:1 % Loop backwards since the indices change when inserting elements
index = aPos(i);
v = [v(1:index-1); b; c; v(index+1:end)];
end
end
function w = move_me(v,a)
if nargin == 2
w=v(v~=a);
w(end+1:end+(length(v)-length(w)))=a;
elseif isscalar(v)
w=v;
else
w=v(v~=0);
w(end+1)=0;
end
end

Subscripted assignment dimension mismatch

So, I'm trying to do the Gauss-Seidel method in Matlab and I found a code that does this but when I apply it to my matrices I get the Subscripted assignment dimension mismatch. error. I will show you my code in order to get a better idea.
%size of the matrix
n = 10;
%my matrices are empty in the beginning because my professor wants to run the algorithm for n = 100
and n = 1000. A's diagonal values are 3 and every other value is -1. b has the constants and the
first and last value will be 2,while every other value will be 1.
A = [];
b = [];
%assign the values to my matrices
for i=1:n
for j=1:n
if i == j
A(i,j) = 3;
else
A(i,j) = -1;
end
end
end
for i=2:n-1
b(i) = 1;
end
%here is the Gauss-Seidel algorithm
idx = 0;
while max(error) > 0.5 * 10^(-4)
idx = idx + 1;
Z = X;
for i = 1:n
j = 1:n; % define an array of the coefficients' elements
j(i) = []; % eliminate the unknow's coefficient from the remaining coefficients
Xtemp = X; % copy the unknows to a new variable
Xtemp(i) = []; % eliminate the unknown under question from the set of values
X(i) = (b(i) - sum(A(i,j) * Xtemp)) / A(i,i);
end
Xsolution(:,idx) = X;
error = abs(X - Z);
end
GaussSeidelTable = [1:idx;Xsolution]'
MaTrIx = [A X b]
I get the error for the Xsolution(:,idx) = X; part. I don't know what else to do. The code posted online works though, and the only difference is that the matrices are hardcoded in the m-file and A is a 5x5 matrix while b is a 5x1 matrix.
I am unable to run your code because some variables are not initialised, at least error and X. I assume the Problem is caused because Xsolution is already initialised from a previous run with a different size. Insert a Xsolution=[] to fix this.
Besides removing the error I have some suggestions to improve your code:
Use Functions, there are no "left over" variables from a previous run, causing errors like you got here.
Don't use the variable name error or i. error is a build-in function to throw errors and i is the imaginary unit. Both can cause hard to debug errors.
Initialise A with A=-1*ones(n,n);A(eye(size(A))==1)=3;, it's faster not to use a for loop in this case. To initialise b you can simply write b(1)=0;b(2:n-1)=1;
Use preallocation
the first time you run the code, Xsolution(:,idx) = X will create a Xsolution with the size of X.
the second time you run it, the existing Xsolution does not fit the size of new X.
this is another reason why you always want to allocate the array before using it.

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