Error with recursive function in m-file - matlab

I'm working on chapter 8 of A Course in Mathematical Biology. The textbook uses Maple, but includes this link, Computer course of Chapter 8 in Matlab. I'm told to put the following in an m-file:
% defining a recursive function in an m-file
function y = plot_traj(a)
RM = inline('a*x.*exp(-x)', 'a', 'x')
% Note that we are using an inline function. Sometimes it’s easier to do this.
% collecting list of x-coordinates
for i = 1:31,
X(i) = i - 1
end
% collecting list of y-coordinates
for i = 1:30,
Y(i+1)=RM(a,iter(i));
iter(i+1) = Y(i+1);
end
y = plot(X, Y, '*');
Now, save your m-file (as plot traj.m) and close it. Type the following into the command window:
>> plot traj(0.8)
>> plot traj(1.0)
>> plot traj(5.0)
>> plot traj(8.0)
>> plot traj(13.0)
>> plot traj(14.5)
>> plot traj(20.0)
However, when I type plot traj(0.8) into the command window I get this:
>> plot_traj(0.8)
Undefined function or variable "iter".
Error in plot_traj (line 13)
Y(i)=RM(a,iter(i));
I don't see anything wrong with line 13, and I've made sure that my code is exactly what is in the chapter. I've been doing fine with the codes up until this point. I'd appreciate it if anyone could provide some assistance. Thank you.

The problem at line 13 is that the iter local variable array has not been defined. So on the first iteration, the code tries to access iter(1) and fails. I looked at the link you provided and they missed it too. Based on previous examples in the Matlab_Course.pdf (and figure 8.6), the iter array should be initialized as
iter(1) = 1.0;
Just add this line prior to the for loop and you should be good to continue. I suspect also that this line should be added too (again based on the document)
Y(1)=iter(1);
to make sure that both iter and Y have the same length.
Note that it is a good habit to pre-allocate memory to arrays to avoid the internal resizing of matrices/arrays on each iteration of the loop (which can have a negative impact on performance). For this loop
for i = 1:30,
Y(i+1)=RM(a,iter(i));
iter(i+1) = Y(i+1);
end
you can observe that i iterates over 1 through 30, and we always populate Y(i+1) and iter(i+1). So both Y and iter are 31x1 vectors. We can allocate memory to each prior to entering the for loop as
iter = zeros(31,1);
Y = zeros(31,1);
iter(1) = 1;
Y(1) = iter(1);
The same should be done for X as well.

Related

Parse error at '[' : usage might be invalid MATLAB syntax

I am developing a small utility that calculates partial differential equation in MATLAB.
I am receiveing an error of invalid syntax:
Parse error at '[' : usage might be invalid MATLAB syntax in the function call, but I don't understand why:
Below the code I am using for the main_routine.m:
% pde operations ..
% Explicit (nonstiff) integration
if(mf == 1)
[t,u] = ode45(#pde_1, tout, u0, options);
end
%
% Implicit (sparse stiff) integration
if(mf == 2)
S = jpattern_num;
options = odeset(options, 'JPattern', S)
[t,u] = ode15s(#pde_1, tout, u0, options);
end
Function call to jpattern_num.m where the error is:
function S = jpattern_num
global n
% Set independent, dependent variables for the calculation
% of the sparsity pattern
tbase = 0;
for i=1:n
ybase(i) = 0.5;
end
ybase = ybase';
%
% Compute the corresponding derivative vector
ytbase = pde_1(tbase,ybase);
fac[]; % <-- Error Here but don't know wy
thresh = 1e-16;
vectorized = 'on';
[Jac,fac] = numjac(#pde_1, tbase, ybase, ytbase, thresh, fac, vectorized);
%
% Replace nonzero elements by "1" (so as to create a "0-1" map of the
% Jacobian matrix)
S = spones(sparse(Jac));
%
% Plot the map ….
What I tried so far:
1) I thought that it was just an array declaration problem but the error persists. I looked at the official documentation to double check possible discrepancies but I could not find the error.
2) This source was very useful as the user had a similar project.
I applied the same modification:
from
fac[];
I applied
fac();
But that didn't solve the problem unfortunately.
3) I dug more into the possible cause of the problem and came across this source, which always from official documentation. I applied what was advised but still the problem persists.
Please, if anyone had a similar problem, advise on how to sole this issue and guide to the right direction.
The line as it is now, is not creating an array. If you want to create an empty array, try
fac = [];
But the question is now, why passing an empty array to numjac? If the array will be created in the latter function, there is no need to pass it as an argument. In fact, if an array passed as an argument is modified in the function, Matlab creates a new array.

defining the X values for a code

I have this task to create a script that acts similarly to normcdf on matlab.
x=linspace(-5,5,1000); %values for x
p= 1/sqrt(2*pi) * exp((-x.^2)/2); % THE PDF for the standard normal
t=cumtrapz(x,p); % the CDF for the standard normal distribution
plot(x,t); %shows the graph of the CDF
The problem is when the t values are assigned to 1:1000 instead of -5:5 in increments. I want to know how to assign the correct x values, that is -5:5,1000 to the t values output? such as when I do t(n) I get the same result as normcdf(n).
Just to clarify: the problem is I cannot simply say t(-5) and get result =1 as I would in normcdf(1) because the cumtrapz calculated values are assigned to x=1:1000 instead of -5 to 5.
Updated answer
Ok, having read your comment; here is how to do what you want:
x = linspace(-5,5,1000);
p = 1/sqrt(2*pi) * exp((-x.^2)/2);
cdf = cumtrapz(x,p);
q = 3; % Query point
disp(normcdf(q)) % For reference
[~,I] = min(abs(x-q)); % Find closest index
disp(cdf(I)) % Show the value
Sadly, there is no matlab syntax which will do this nicely in one line, but if you abstract finding the closest index into a different function, you can do this:
cdf(findClosest(x,q))
function I = findClosest(x,q)
if q>max(x) || q<min(x)
warning('q outside the range of x');
end
[~,I] = min(abs(x-q));
end
Also; if you are certain that the exact value of the query point q exists in x, you can just do
cdf(x==q);
But beware of floating point errors though. You may think that a certain range outght to contain a certain value, but little did you know it was different by a tiny roundoff erorr. You can see that in action for example here:
x1 = linspace(0,1,1000); % Range
x2 = asin(sin(x1)); % Ought to be the same thing
plot((x1-x2)/eps); grid on; % But they differ by rougly 1 unit of machine precision
Old answer
As far as I can tell, running your code does reproduce the result of normcdf(x) well... If you want to do exactly what normcdf does them use erfc.
close all; clear; clc;
x = linspace(-5,5,1000);
cdf = normcdf(x); % Result of normcdf for comparison
%% 1 Trapezoidal integration of normal pd
p = 1/sqrt(2*pi) * exp((-x.^2)/2);
cdf1 = cumtrapz(x,p);
%% 2 But error function IS the integral of the normal pd
cdf2 = (1+erf(x/sqrt(2)))/2;
%% 3 Or, even better, use the error function complement (works better for large negative x)
cdf3 = erfc(-x/sqrt(2))/2;
fprintf('1: Mean error = %.2d\n',mean(abs(cdf1-cdf)));
fprintf('2: Mean error = %.2d\n',mean(abs(cdf2-cdf)));
fprintf('3: Mean error = %.2d\n',mean(abs(cdf3-cdf)));
plot(x,cdf1,x,cdf2,x,cdf3,x,cdf,'k--');
This gives me
1: Mean error = 7.83e-07
2: Mean error = 1.41e-17
3: Mean error = 00 <- Because that is literally what normcdf is doing
If your goal is not not to use predefined matlab funcitons, but instead to calculate the result numerically (i.e. calculate the error function) then it's an interesting challange which you can read about for example here or in this stats stackexchange post. Just as an example, the following piece of code calculates the error function by implementing eq. 2 form the first link:
nerf = #(x,n) (-1)^n*2/sqrt(pi)*x.^(2*n+1)./factorial(n)/(2*n+1);
figure(1); hold on;
temp = zeros(size(x)); p =[];
for n = 0:20
temp = temp + nerf(x/sqrt(2),n);
if~mod(n,3)
p(end+1) = plot(x,(1+temp)/2);
end
end
ylim([-1,2]);
title('\Sigma_{n=0}^{inf} ( 2/sqrt(pi) ) \times ( (-1)^n x^{2*n+1} ) \div ( n! (2*n+1) )');
p(end+1) = plot(x,cdf,'k--');
legend(p,'n = 0','\Sigma_{n} 0->3','\Sigma_{n} 0->6','\Sigma_{n} 0->9',...
'\Sigma_{n} 0->12','\Sigma_{n} 0->15','\Sigma_{n} 0->18','normcdf(x)',...
'location','southeast');
grid on; box on;
xlabel('x'); ylabel('norm. cdf approximations');
Marcin's answer suggests a way to find the nearest sample point. It is easier, IMO, to interpolate. Given x and t as defined in the question,
interp1(x,t,n)
returns the estimated value of the CDF at x==n, for whatever value of n. But note that, for values outside the computed range, it will extrapolate and produce unreliable values.
You can define an anonymous function that works like normcdf:
my_normcdf = #(n)interp1(x,t,n);
my_normcdf(-5)
Try replacing x with 0.01 when you call cumtrapz. You can either use a vector or a scalar spacing for cumtrapz (https://www.mathworks.com/help/matlab/ref/cumtrapz.html), and this might solve your problem. Also, have you checked the original x-values? Is the problem with linspace (i.e. you are not getting the correct x vector), or with cumtrapz?

octave plot does not work properly

CODE DELETED
Hi, the code above is my (slightly modified) rooo.m file.
I'm just trying to plot the function by typing into (octave) terminal
x = 1:1:40;
plot(x, rooo(x), '+');
But this will only print the graph of y=1.
I believe it's because of the y = 1; in the first line (btw the function itself returns the right value, say when I type rooo(3)).
When I change it to some other number (say b), the graph will show y =b.
Does anyone have an idea why this is happening??
I think it's not working because if you type rooo(x) at the command line, it will return a scalar result of 1, instead of a vector. The 1 < n logical condition doesn't work as you intended to when n is a vector.
Here is a suggestion to make it work (maybe not the most elegant but it seems to work):
CODE DELETED
Which, when called as in your question, gives the following plot
The results seem to be different from the ones reported in MATLAB though.
An alternative, if you don't want to modify your function, is to change the way you call it:
>> x = 1:1:40;
>> y = ones(size(x));
>> for k=1:length(x)
y(k) = rooo(x(k));
end
>> plot(x,y,'+')
This gives the same result as the above suggestion.
It's not working because you never enter the while loop with x starting at 1. Since
1 < n == 1 < x is false at the very beginning, the function returns.
However when you call rooo(3) or actually rooo(Anything > 1) it does work. With x = 1.1:1:40 the plot looks like this ( I made it with Matlab) :

correct function handle for integral2 in matlab

I created a function in matlab that returns a vector like
function w = W_1D(x,pos,h)
w=zeros(1,length(x));
if (h~=0)
xmpos = x-pos;
inds1 = (-h <= xmpos) & (xmpos < 0);
w(inds1) = xmpos(inds1)./h + 1;
inds2 = (0 <= xmpos) & (xmpos <= h);
w(inds2) = -xmpos(inds2)./h + 1;
else
error('h shouldn't be 0')
end
end
Thus, in the end, there is a vector w of size length(x).
Now i created a second function like
function f = W_2D(x,y,pos_1,pos_2,h)
w_x = W_1D(x,pos_1,h);
w_y = W_1D(y,pos_2,h);
f = w_x'*w_y;
end
where length(x)=length(y). Thus, the function W_2D obviously returns a matrix.
But when I now try to evaluate the integral over a rectangular domain like e.g.
V = integral2(#(x,y) W_2D(x,y,2,3,h),0,10,0,10);
matlab returns some errors:
Error using integral2Calc>integral2t/tensor (line 242)
Integrand output size does not match the input size.
Error in integral2Calc>integral2t (line 56)
[Qsub,esub] = tensor(thetaL,thetaR,phiB,phiT);
Error in integral2Calc (line 10)
[q,errbnd] = integral2t(fun,xmin,xmax,ymin,ymax,optionstruct);
Error in integral2 (line 107)
Q = integral2Calc(fun,xmin,xmax,yminfun,ymaxfun,opstruct);
I also tried to vary something in the W_2D-function: instead of f = w_x'*w_y;
I tried f = w_x.'*w_y;
or w_y = transpose(w_y); f = kron(w_x,w_y);, but there is always this error with the Integrand output size-stuff.
Can anyone explain, where my fault is?
EDIT: After Werner's hint with the keyboard debugging method, I can tell you the following.
The first step returns w_x of type <1x154 double>, w_y is <1x192 double>, x and y are both <14x14 double>. In the next step, f appears with a value of <154x192 double>. Then everything disappears, except x and y and the matlab-function integral2Calc.m appears in the editor and it jumps to the Function Call Stack integral2t/tensor and after some more steps, the error occurs here
Z = FUN(X,Y); NFE = NFE + 1;
if FIRSTFUNEVAL
if ~isfloat(Z)
error(message('MATLAB:integral2:UnsupportedClass',class(Z)));
end
% Check that FUN is properly vectorized. This is important here
% because we (otherwise) always pass in square matrices, which
% reduces the probability of the user generating an error by
% using matrix functions instead of elementwise functions.
Z1 = FUN(X(VTSTIDX),Y(VTSTIDX)); NFE = NFE + 1;
if ~isequal(size(Z),size(X)) || ~isequal(size(Z1),size(VTSTIDX))
% Example:
% integral2(#(x,y)1,0,1,0,1)
error(message('MATLAB:integral2:funSizeMismatch'));
end
Hope that information is detailed enough...I have no idea what happenes, because my example is exact as it is given on the mathworks site about integral2, isn't it?
Maybe I should precise a bit more, what I wanna do: since W_2D gives me a surface w(x,y) of a compactly supported 2-dimensional hat-function, stored in a matrix w, I want to calculate the volume between the (x,y)-plane and the surface z=w(x,y)...
EDIT2: I still do not understand how to handle the problem, that integral2 creates matrices as inputs for my W_1D-functions, which are called in W_2D and intended to have a <1xn double>-valued input and return a <1xn double> output, but at least I can simply use the following to solve the integration over the tensor product by using two one-dimensional integral-calls, that is
V = integral(#(x)integral(#(y)W_1D(y,3,h),0,10).*W_1D(x,2,h),0,10);
This first function is quite wrong. You are not indexing the array positions while you are doing w = x inside for.
Besides, if that would work, you are returning a line vector, that is, size 1xlength(x) and when you do w_x'*w_y you are doing length(x)x1 times 1xlength(y), which would give you a matrix length(x)*length(y).
Consider correcting your function:
function w = W_1D(x,pos)
w = zeros(length(x),1); % Allocate w as column vector, so that the product gives a scalar (as I suppose that it is what you want.
for ii=1:length(x) % Here, so that is indexes w and x elements as you need
w(ii)=x(ii) - pos; % I changed your code to something that makes sense, but I don't know if that is what you want to do, you have to adapt it to work correctly.
end
end
You may also want to debug your functions, consider adding keyboard before your operations and check what they are returning using dbstep. I.e:
function f = W_2D(x,y,pos_1,pos_2)
w_x = W_1D(x,pos_1);
w_y = W_1D(y,pos_2);
keyboard
f = w_x'*w_y;
end
Execution will stop at keyboard, then you can check w_x size, w_y size, and do dbstep to go after f = w_x'*w_y and see what it returned. After you finish debug, you can do dbcont so that it will continue execution.
This answer is a draft as it is quite difficult to help you with the information you have provided. But I think you can start working the things out with this. If you have more doubts feel free to ask.

nlfilter taking same values twice

I used nlfilter for a test function of mine as follows:
function funct
clear all;
clc;
I = rand(11,11);
ld = input('Enter the lag = ') % prompt for lag distance
A = nlfilter(I, [7 7], #dirvar);
% Subfunction
function [h] = dirvar(I)
c = (size(I)+1)/2
EW = I(c(1),c(2):end)
h = length(EW) - ld
end
end
The function works fine but it is expected that nlfilter progresses element by element, but in first two iterations the values of EW will be same 0.2089 0.4162 0.9398 0.1058. But then onwards for all iterations the next element is selected, for 3rd it is 0.4162 0.9398 0.1058 0.1920, for 4th it is 0.9398 0.1058 0.1920 0.5201 and so on. Why is it so?
This is nothing to worry about. It happens because nlfilter needs to evaluate your function to know what kind of output to create. So it uses feval once before starting to move across the image. The output from this feval call is what you see the first time.
From the nlfilter code:
% Find out what output type to make.
rows = 0:(nhood(1)-1);
cols = 0:(nhood(2)-1);
b = mkconstarray(class(feval(fun,aa(1+rows,1+cols),params{:})), 0, size(a));
% Apply fun to each neighborhood of a
f = waitbar(0,'Applying neighborhood operation...');
for i=1:ma,
for j=1:na,
x = aa(i+rows,j+cols);
b(i,j) = feval(fun,x,params{:});
end
waitbar(i/ma)
end
The 4th line call to eval is what you observe as the first output from EW, but it is not used to anything other than making the b matrix the right class. All the proper iterations happen in the for loop below. This means that the "duplicate" values you observe does not affect your final output matrix, and you need not worry.
I hope you know what the length function does? It does not give you the Euclidean length of a vector, but rather the largest dimension of a vector (so in your case, that should be 4). If you want the Euclidean length (or 2-norm), use the function norm instead. If your code does the right thing, you might want to use something like:
sz = size(I,2);
h = sz - (sz+1)/2 - ld;
In your example, this means that depending on the lag you provide, the output should be constant. Also note that you might want to put semicolons after each line in your subfunction and that using clear all as the first line of a function is useless since a function will always be executed in its own workspace (that will however clear persistent or global variables, but you don't use them in your code).