Breaking out of recursive function calls in matlab - matlab

The following is only a simple example to generalize and illustrate the problem I am having.
If I have a function like the following:
function newtraph(initialguess,funct,dfunct)
ht = funct(initialguess);
if abs(ht) < 10^(-6)
disp(initialguess); return
elseif abs(ht) > 10^6
disp('Fix Guess'); return
end
newtraph(initialguess-(ht/dfunct(initialguess)), funct, dfunct);
The only way (that I am aware of) to exit out is through the use of those return statements. But, I want to assign output from functions of this variety to variables in the base workspace. I want to do some thing like:
function out = newtraph(initialguess,funct,dfunct)
ht = funct(initialguess);
if abs(ht) < 10^(-6)
out = initialguess; return
elseif abs(ht) > 10^6
disp('Fix Guess'); return
end
newtraph(initialguess-(ht/dfunct(initialguess)), funct, dfunct);
This doesn't work, the return prevents out from being assigned.
Output argument "out" (and maybe others) not assigned
Some ideas I have for a solution are using globals or evalin. But is there some simpler way that I am missing. I just want pass the output from functions of this style back to the base workspace?
A test case, just in case:
funct=#(x) -x-cos(x); dfunct=#(x) sin(x)-1; initialguess=1;
Thanks for your time.
Well, I am an idiot. It was simply a case of forgetting the final assignment:
function out = newtraph(initialguess,funct,dfunct)
ht = funct(initialguess);
if abs(ht) < 10^(-6) %Tolerance
out = initialguess; return
elseif abs(ht) > 10^6
out=0; return
end
out = newtraph(initialguess-(ht/dfunct(initialguess)), funct, dfunct);
Thanks for the quick help!

Your example function that doesn't work is almost there. You just need to assign
out = newtraph(...)
on the last line so you can capture the output.
You probably also need to assign out = 0 or some dummy value when you report "fix guess" so that branch of the code will also return a value.

Just a guess here: aren't you missing the assignment in the last line? And also don't you need to initialize out in your elseif in case out wasn't assigned before? I.e.
ht = funct(initialguess);
if abs(ht) < 10^(-6)
out = initialguess;
return
elseif abs(ht) > 10^6
disp('Fix Guess');
if ~exist('out')
out=1; % you need some default value if you ever reach this code without ever initializing out
end
return
end
out = newtraph(initialguess-(ht/dfunct(initialguess)), funct, dfunct);

This answer may be a little late, but I think that it is important enough to deserve to be pointed out here. To make the recursion clearer I do recommend another approach here.
function out = newtraph(initialguess,funct,dfunct,counter)
maxCount = % yourValue;
ht = funct(initialguess);
if abs(ht) > 10^(-6) || abs(ht) < 10^6 || counter<maxCount % Break out after x tries
counter = counter+1;
out = newtraph(initialguess-(ht/dfunct(initialguess)), funct, dfunct,counter);
elseif abs(ht) < 10^(-6) %Tolerance
out = initialguess;
else
warning('Convergence were not reached!');
out=0;
end
The preffered structure may be personal, but this way it is clear that you keep going until you hit a stop criterion, namely the function converged or were divergent.
Also, recursive functions are dangerous due to that the only way to stop them is to fulfill the exit criterion or when the program crashes. Matlab have a limit of how many times a recursion can go on and then throws an error. You will most likely want to handle the error by yourself (like you have done already by setting out=0;). Also matlabs limit is 500 recursive calls and you do most likely want to terminate the function earlier, maybe at 8-20 calls, depending on your algorithm.

Related

Insert a number before a given number in a linked list

I'm doing an introduction course in programing in matlab and python and I have only been coding for a short time, so I'm still on the basics.
In the problem that I'm trying to solve, we have been given a code that creates a linked list by the teacher.
classdef Elem < handle
%Elem A class realising a linked list.
properties
data
next = Elem.empty
end
methods
function node = Elem(value)
if (nargin > 0)
node.data = value;
end
end
function obj = insert(obj, value)
if(isempty(obj.next))
obj.next = Elem(value);
else
obj.next.insert(value);
end
end
% More methods go here
end
end
One of the questions is then to make a code that can insert a number before a number in the linked list.
To do this I have made this code.
function newlist=InsertBefore(list,newdata,dataBefore)
if ~isempty(list)
if list.data==dataBefore
newlist = Elem(newdata);
newlist.next = list;
elseif list.next.data==dataBefore
newlist=list;
newelem = Elem(newdata);
newelem.next = list.next;
newlist.next = newelem;
else
InsertBefore(list.next,newdata,dataBefore)
end
end
end
If I then write
linkedlist2=InsertBefore(LinkedList,4,12)
the function makes a new list with 4 in front of the 12 which is the first number in the list. so the "If" part of the code works fine. if I try doing the same thing with a number in the middle of the list it says.
Output argument "newlist" (and maybe others) not assigned during call to "InsertBefore".
I have tried many things but nothing has really worked perfect yet, so your help is much appreciated
Thanks
Lasse
SOLVED
Had to have
else
newlist = InsertBefore(list.next,newdata,dataBefore)

Finding occurences of a digit in a number by recursion in Matlab

This recursive function takes two input arguments, The first (A) is a number and the second (n) is a digit, checks the occurrence of n in A. (A is updated by removing its last digit in each recursion). it seems like the recursion is infinite and the base case (A == 0) is not valid but why.
function counts = countn(A,n)
if (A == 0)
counts= 0;
end
if (n == mod(A,10))
disp(A);
disp(floor(A/10));
disp(mod(A,10));
B = floor(A/10);
counts = countn(B,n) + 1;
else
B = floor(A/10);
countn(B,n);
end
end
It does not stop because it first evaluates the first if statement if( A == 0) and afterward the if (n == mod(A,10)) where it jumps in the else branch and recursively calls the function again. So it does not stop in the first if statement as you likely expected it to do.
something like this should work:
function counts = countn(A,n)
if (A == 0)
counts = 0;
elseif (n == mod(A,10))
disp(A);
disp(floor(A/10));
disp(mod(A,10));
B = floor(A/10);
counts = countn(B,n) + 1;
else
B = floor(A/10);
counts = countn(B,n);
end
end
You also have to update count counts variable in the else branch to avoid the uninitialized use of variables.
Have a look at how to use a debugger manual. Simply click on the line number inside your function and run your code. Use the F10 and F11 keys to evaluate your code line by line. This helps you understand what your program does.

Function with different return variables

Is there a way to have one function that can return two different variables, but only one at a time AND knowing which one is returned in the function call?
example:
I have the following function in which only one of the outputs is valid (the other one would be [])
function [a,b] = AlternatingOutput (input)
if input == 1
return ONLY A
else
return ONLY B
end
end
and i call it in a script
[a,b] = AlternatingOutput (input)
i want a way to say the following (pseudocode):
if (function outputs a)
[a,~] = AlternatingOutput(input)
elseif (function outputs b)
[~,b] = AlternatingOutput(input)
end
the script is run in a loop, and later i need the newest Valid values for a and b, so i cannot overwrite one of the two with []
I do understand that I could just write a function that checks which variable will be output, but I was wondering if there is a more elegant way.
I hope I have made my question clear, and I hope someone can answer me :)
There is no way to tell if an output argument is actually used. You may check the number of output arguments using nargout and it would allow to distinguish between [a] = AlternatingOutput(input) and [~,b] = AlternatingOutput(input)
I don't know the full context of your problem, but maybe you can put all your variables into a struct? Simply pass this struct everytime you call the function and let it decide which variables to manipulate. (This might be slow in some programming languages, but not in matlab).
How about retuning a cell?
function [ ab ] = testfun( input )
if input
ab={'ax'};
else
ab={2};
end
end
No worries about what is in the cell.
thb you could return what ever you want, Matlab does not check the type anyways
If only one of the outputs from the function AlternatingOutput is valid, then you only need to return one output:
function [X] = AlternatingOutput(input)
if input == 1
X = A;
else
X = B;
end
end
To allocate the retured value to either a or b in the loop, put them into a cell:
C = {AlternatingOutput(1), AlternatingOutput(2)};
and then use input to determine which value is change. If input is either 1 or 2 you can just do
for counter = ...
input = mod(input,2)+1;
C{input}=AlternatingOutput(input);
end
If your function doesn't mind accepting more input variables, why not pass a and b as input:
function [a,b] = AlternatingOutput(a,b,input)
if input == 1
a = new_value_for_a;
% b retains its former value
else
% a retains its former value
b = new_value_for_b;
end
end
Then it can be easily called from your script in a loop:
for i= ...
[a,b] = AlternatingOutput(a,b,input);
...
...
end

If and elseif, only the first line work?

L=1; Nx=51; PeriodicFlag=1; T=15; Nt=51;
spacedef='Pade6FirstDeriv'; casedef='LinearAdvection';
if (spacedef == 'Pade6FirstDeriv')
D1 = sparse(Pade6(Nx,dx,PeriodicFlag));
elseif (spacedef == 'Upwind3FirstDeriv')
D1 = sparse(Upwind3(Nx,dx,PeriodicFlag));
elseif (spacedef == 'Central4FirstDeriv')
D1 = sparse(Central4(Nx,dx,PeriodicFlag));
elseif (spacedef == 'Central2FirstDeriv')
D1 = sparse(Central2(Nx,dx,PeriodicFlag));
else
error(sprintf('Unknown spacedef = %s',spacedef));
end
In the above code, the if section is a small segment from a function I've constructed. I'm trying to get the function to know which methods to use based on my input (spacedef). Central2, Central4, Upwind3, and Pade6 are other functions I've written. The weird thing is that when spacedef =/= to 'Pade6FirstDeriv', I would get an error stating Error using ==, Matrix dimensions must agree. I've tried swapping the order of the if loop (by placing Central4, Central2, Pade6, and Upwind3 in the first line of the loop), and it seems like only the top line of the loop will work (the elseifs are not working). I'd greatly appreciate it if anybody can help me out. Thanks!
As has been noted in the comments, this is a common error when people first start comparing strings in MATLAB, and strcmp or strcmpi is generally the solution.
However, one solution the questions links in the comments don't present, and a solution I think looks much nicer, is the switch statement:
switch (spacedef)
case('Pade6FirstDeriv')
D1 = sparse(Pade6(Nx,dx,PeriodicFlag));
case('Upwind3FirstDeriv')
D1 = sparse(Upwind3(Nx,dx,PeriodicFlag));
case('Central4FirstDeriv')
D1 = sparse(Central4(Nx,dx,PeriodicFlag));
case('Central2FirstDeriv')
D1 = sparse(Central2(Nx,dx,PeriodicFlag));
otherwise
error(sprintf('Unknown spacedef = %s',spacedef));
end
Note: if I expect others to use my code with string comparisons, I usually lower the input such that the comparison is case-insensitive, although I have not done that here.

How to make a loop which display the output for my program automatically

In my program , suppose I fix no. of users N=6 .
Threshold value of SIR SIRo=6; Output generated is SIRmean=10 (suppose).
I want to make a loop so that
if SIRmean < SIRo
disp N=6
else
decrease the counter till SIRmean> SIRo
and display the value of N for which this condition holds true.
end
You can use simple for loop with downcounter and break on condition:
N=6;
for k=N:-1:0
SIRmean = calc_SIR_mean(N);
if SIRmean < SIRo
disp(['N=' k])
break;
end
end
Function calc_SIR_mean should return mean value based on number of users (it is not clear from your question how you receive this value).