Looping a Function in Matlab - matlab

total newbie here. I'm having problems looping a function that I've created. I'm having some problems copying the code over but I'll give a general idea of it:
function[X]=Test(A,B,C,D)
other parts of the code
.
.
.
X = linsolve(K,L)
end
where K,L are other matrices I derived from the 4 variables A,B,C,D
The problem is whenever I execute the function Test(1,2,3,4), I can only get one answer out. I'm trying to loop this process for one variable, keep the other 3 variables constant.
For example, I want to get answers for A = 1:10, while B = 2, C = 3, D = 4
I've tried the following method and they did not work:
Function[X] = Test(A,B,C,D)
for A = 1:10
other parts of the code...
X=linsolve(K,L)
end
Whenever I keyed in the command Test(1,2,3,4), it only gave me the output of Test(10,2,3,4)
Then I read somewhere that you have to call the function from somewhere else, so I edited the Test function to be Function[X] = Test(B,C,D) and left A out where it can be assigned in another script eg:
global A
for A = 1:10
Test(A,2,3,4)
end
But this gives an error as well, as Test function requires A to be defined. As such I'm a little lost and can't seem to find any information on how can this be done. Would appreciate all the help I can get.
Cheers guys

I think this is what you're looking for:
A=1:10; B=2; C=3; D=4;
%Do pre-allocation for X according to the dimensions of your output
for iter = 1:length(A)
X(:,:,iter)= Test(A(iter),B,C,D);
end
X
where
function [X]=Test(A,B,C,D)
%other parts of the code
X = linsolve(K,L)
end

Try this:
function X = Test(A,B,C,D)
% allocate output (it is faster than changing the size in every loop)
X = {};
% loop for each position in A
for i = 1:numel(A);
%in the other parts you have to use A(i) instead of just A
... other parts of code
%overwrite the value in X at position i
X{i} = linsolve(K,L);
end
end
and run it with Test(1:10,2,3,4)
To answer what went wrong before:
When you loop with 'for A=1:10' you overwrite the A that was passed to the function (so the function will ignore the A that you passed it) and in each loop you overwrite the X calculated in the previous loop (that is why you can only see the answer for A=10).
The second try should work if you have created a file named Test.m with the function X = (A,B,C,D) as the first code in the file. Although the global assignment is unnecessary. In fact I would strongly recommend you not to use global variables as it gets very messy very fast.

Related

What does the code '[~, width ] = size(I);'mean?I can't undestand '~'especially [duplicate]

Is it possible to get the 'nth' return value from a function without having to create dummy variables for all n-1 return values before it?
Let's say, I have the following function in MATLAB:
function [a,b,c,d] = func()
a = 1;
b = 2;
c = 3;
d = 4;
Now suppose, I'm only interested in the third return value. This can be accomplished by creating one dummy variable:
[dummy, dummy, variableThatIWillUse, dummy] = func;
clear dummy;
But I think this is kind of ugly. I would think that you might be able to do something like one of the following things, but you can't:
[_, _, variableThatIWillUse, _] = func;
[, , variableThatIWillUse, ] = func;
variableThatIWillUse = func(3);
variableThatIWillUse = func()(3);
Are there any elegant ways to do this that do work?
So far, the best solution is to simply use the variableThatIWillUse as a dummy variable. This saves me from having to create a real dummy variable that pollutes the work-space (or that I would need to clear). In short: the solution is to use the variableThatIWillUse for every return value up until the interesting one. Return values after can simply be ignored:
[variableThatIWillUse, variableThatIWillUse, variableThatIWillUse] = func;
I still think this is very ugly code.
With MATLAB Version 7.9 (R2009b) you can use a ~, e.g.,
[~, ~, variableThatIWillUse] = myFunction();
Note that the , isn't optional. Just typing [~ ~ var] will not work, and will throw an error.
See the release notes for details.
This is somewhat of a hack, but it works:
First a quick example function:
Func3 = #() deal(1,2,3);
[a,b,c]=Func3();
% yields a=1, b=2, c=3
Now the key here is that if you use a variable twice on the left-hand side of a multiple-expression assignment, an earlier assignment is clobbered by the later assignment:
[b,b,c]=Func3();
% yields b=2, c=3
[c,c,c]=Func3();
% yields c=3
(Just to check, I also verified that this technique works with [mu,mu,mu]=polyfit(x,y,n) if all you care about from polyfit is the third argument.)
There's a better approach; see ManWithSleeve's answer instead.
If you wish to use a style where a variable will be left to fall into the bit bucket, then a reasonable alternative is
[ans, ans, variableThatIWillUse] = myfun(inputs);
ans is of course the default junk variable for MATLAB, getting overwritten often in the course of a session.
While I do like the new trick that MATLAB now allows, using a ~ to designate an ignored return variable, this is a problem for backwards compatibility, in that users of older releases will be unable to use your code.
I generally avoid using new things like that until at least a few MATLAB releases have been issued to ensure there will be very few users left in the lurch. For example, even now I find people are still using an old enough MATLAB release that they cannot use anonymous functions.
Here's another option you can use. First make a cell array to capture all the outputs (you can use the NARGOUT function to determine how many outputs a given function returns):
a = cell(1,3); % For capturing 3 outputs
% OR...
a = cell(1,nargout(#func)); % For capturing all outputs from "func"
Then call the function as follows:
[a{:}] = func();
Then simply remove the element from a that you want, and overwrite a:
a = a{3}; % Get the third output
I wrote a kth out function:
function kth = kthout(k, ffnc, varargin)
% kthout: take the kth varargout from a func call %FOLDUP
%
% kth = kthout(k, ffnc, varargin)
%
% input:
% k which varargout to get
% ffnc function to call;
% varargin passed to ffnc;
% output:
% kth the kth argout;
[outargs{1:k}] = feval(ffnc, varargin{:});
kth = outargs{k};
end %function
You can then call
val_i_want = kthout(3, #myfunc, func_input_1, func_input_2);
You could also wrap up the function like:
func_i_want = #(varargin)(kthout(3, #myfunc,varargin{:})); % Assuming you want the third output.
After which you use
val_i_want = func_i_want(func_input_1, func_input_2);
Note that there is overhead associated with using anonymous functions like this, and this is not something I would do in code that would be called thousands of times.
In MATLAB 2010a, I found a neat way of doing what you are asking for.
It is simply to use the character "~" (without the quotes of course) as your dummy variable (as many as you want when returning multiple parameters). This also works for input parameters to functions if the functions are designed to handle missing data.
I don't know if this existed in previous versions, but I just came across it recently.
You can make a function (or anonymous function) that only returns selected outputs, e.g.
select = #(a,b) a(b);
Then you can call your function like this:
select(func,2);
select(func,1:3);
Or you can assign the output to a variable:
output(1,2:4) = select(func,1:3);
I don't see any reason not to use ans(n). Like this:
size(rand([5 10 20 40]));
b = ans(2);
It gives b = 10, and this way would be compatible with all MATLAB versions. Note that size() here is just used to represent any function that has multiple return variables.
Furthermore, this works to get the second output argument when you don't know how many arguments there will be! Whereas, if you do this:
[~, b] = size(a);
Then b = 8000! (You need to end with ~, to catch more arguments!)

Continue ‘for’ loop with the existing variables in Matlab

I have a Matlab script including a for loop which loos like the following:
for k = 1:10
c = myfun(k,a,b);
result{k} = c;
end
Right now, the problem is that during the for loop, sometimes myfun() may have errors and stop. After fixing the error in myfun(), how can I continue to run with the existing value of variables? The reason is that myfun() will take a very long time to get the result and the previous results are right.
For example, if a error happens when k == 4, then I save all the variables in the current workspace. I set a breakpoint at c = myfun(k,a,b); and restore the saved variables, but I find that in the next loop, k will be 2 instead of 5 as I want. Matlab is not allowed to modify the value of k during the for loop I think. I have tested this for a few times.
How can I continue the for loop with some existing data?
You cannot change your for loop iterator programmatically inside of the loop.
For example:
for ii = 1:3
disp(ii)
ii = 3;
end
Prints:
1
2
3
If you're going to be modifying code based on errors received, dbstop if error is not going to be beneficial because it will not reflect changes in your code until the debugger is exited and your code executed again (unless you execute manually in the debugger). If you're not modifying code you could potentially use a try/except clause to catch fixable issues.
If you're loading data for a later index and then restarting, you can change where your for loop begins, or use a while loop (if appropriate).
For example:
% Load data here
for ii = 3:3
disp(ii)
end
Prints 3.
Where the while interpretation would be:
% Load data here
ii = 3
while ii <= 3
disp(ii)
ii = ii + 1;
end
For the same result.
On solution can be first catch the exception likes the following and pass from them:
bug = [];
for k = 1:10
try
c = myfun(k,a,b);
result{k} = c;
catch
warning('some bug for the following values:');
display([k a b]);
bug = [bug; k a b];
result{k} = NaN;
end
end
Then iterate over bug to compute missing information after debugging. This solution works when your algorithm is not dependent on the previous value of the result (or is not recursive).

Hide lines of code in MATLAB

I want to know If it's possible and how, to hide some parts of a line or whole lines of code from a script in MATLAB. For example:
if a=b
x=y+1; x=x^2;
end
And have the x=x^2 hidden, but still run the process. I mean:
if a=b
x=y+1;
end
(wringing hands with evil grin on face)
If you really want to mess with people like this, you're going to want to go down the operator overloading route. Come with me on a journey where you will almost certainly shoot yourself in the foot while trying to play a joke on someone else!
(lightning crackles over the laughter of a madman)
I've discussed this in a few other questions before (here and here). Basically, you can change the default behavior of built-in operators for MATLAB data types. In this case, we'll change how the plus operator works for variables of class double (the default variable type). Make a folder called #double on your MATLAB path, then create a file called plus.m and put the following code inside it:
function C = plus(A, B)
C = builtin('plus', A, B);
if strcmp(inputname(1), 'y')
C = C.^2;
end
end
Now, try it for yourself...
>> y=1; % Initialize y
>> x=y+1
x =
4 % Wait a minute...
>> x=1+1
x =
2 % OK
>> x=1+y
x =
2 % OK
>> x=y+1
x =
4 % What?!
>> x=y+2;
x =
9 % No!!
>> y=3;
>> x=y+1
x =
16 % Oh noes! I've been hax0red!!11!1!
How it works:
The new plus function shadows the built-in one, so it gets called when performing addition on doubles. It first invokes the built-in plus to do the actual addition using the builtin function. This is necessary, because if you wrote C=A+B; here it would call the phony plus again and cause infinite recursion. Then, it uses the inputname function to check what the variable name of the first input to the function is. If it's 'y', we square the result before returning it.
Have fun!!!
...and remember to remove it when you're done. ;)
if a==b
x = y+1;
for ind = 1
x = x^2;
end
end
Bit of a wacky way, but you can collapse loop/end blocks like for and while loops. Simply click the - sign in the editor:
So for two or less lines this doesn't help you, but if you want to hide e.g. 40 lines, it shortens it appreciably.
Another option is to simply chuck in a hundred or so spaces and make it obfuscated:
if a==b
x = y+1; x = x^2;
end
Thanks to excaza the most obfuscated way of all to write x=x^2;:
eval(cast((sscanf('240,122,240,188,100,118', '%d,')./2)', 'like', ''))

MATLAB: Saving While loop data

I'm running a while loop and I am running in to some problems.
I have the following piece of code:
Angle_int = 0.5; % Initial interpolation angle of attack
Clmax2d(1,1:length(Yle_wing)) = 3; % Dummy value
diff = 0; % Dummy value
while sum(diff < 0) > fix(tol*length(Yle_wing))
Angle_int = Angle_int + 0.5; % Interpolation angle increases with 0.5 with every iteration
for j = 1:length(Yle_wing)
CL3d = interp1(Angle,[cl_matrix(1,j) cl_matrix(2,j) cl_matrix(3,j)],Angle_int,'linear');
CL_3DD(:,j) = CL3d;
end
diff = (Clmax2d - CL_3DD); % Difference between Cl2d and Cl3d
Angle_stall = Angle_int;
CL_3D = CL_3DD;
end
For some reason, CL_3D = CL_3DD; and Angle_stall = Angle_int; seem to disappear when the while loop finishes. Hence, I cannot use their converged values ahead of the while loop since these variables are not recognized. I get the following error:
Undefined function or variable "CL_3D".
Hence, does someone knows what I am doing wrong? or any tips would be welcome as well.
Thanks in advance,
cheers
The error message:
Undefined function or variable "CL_3D".
is always because you're trying to use a variable or function that you haven't initialized yet. Often this happens in loops where you want to increment a counter, or compare values etc.
A common error is doing something like this without writing ii = 0 in front of the loop:
while ii < some_num
ii = ii + 1;
some_function();
end
With your dummy variables, you never enter the loop (unless tol < 0, which seems like an odd choice). You probably want to initialize diff = Inf or something like that. However, using diff as a variable name is not a good idea, since it's a builtin function.
You probably try to use CL_3D, when it's not yet initialized (somewhere else in your code, not in the part you posted). MATLAB tells you which line the error appears in, you should try using it!
Maybe initializing it like zeros(size(Clmax2d)); could work (it will definitely remove your error, but it might not give the desired behavior).
PS!
Using i and j as variables are not recommended as they represent the imaginary unit in MATLAB.

Matlab R2014a - defining a variable after a function is called

In a matlab script, is it possible to define a variable after the function is called?
(i.e. the script finds the function with the undefined variable, looks for the variable initialization and executes the function afterwards)
I need this because I have a large number of variables and functions and I don't want to order them in a sequential way but in the way that is appropriate for my problem.
E.g.
mean(x);
x = [1, 2, 3];
Thanks
Disclaimer: I think what you want to do is a really bad practice. If you find yourself in the need to do this, your code screams refactoring.
Yes, it is possible. There are two ways.
Using the try-catch statement:
try
x_mean = mean(x)
catch exception
if isequal(exception.identifier, 'MATLAB:UndefinedFunction')
x = [1,2,3];
x_mean = mean(x);
else
rethrow(exception);
end
end
The explanation: if the mean(x) fails, the code will enter in the catch branch. Then it verifies that the error is happening because a missing variable and if that's the case, the variable x is defined and the function re-run. There is a caveat: Matlab uses the same identifier for missing variable and for missing function.
Using the exist function:
if exist('x') == 1 %// the function have several return values
x_mean = mean(x);
else
x = [1, 2, 3];
x_mean = mean(x);
end
The explanation: the exist function will verify if a variable with the name x exists in the workspace. If it does exist, it will return 1 and you can execute your function. If it does not exist, then you can declare it first and then run mean. See documentation here.
My two cents: once again, this is a horrible way to achieve things. By going this way you will end up with pure spaghetti code. It will be a nightmare to debug. It will be a nightmare to maintain. There is a 99% chance that there are better ways to do what you want. It is just a matter of investing time and think a little bit. Even if it is a personal project or a quick script to solve a homework/task, you will learn much more by doing it the right way.
If I understand you question correctly, then yes it can be done by some ugly hacks.
The following class can be used:
classdef AdvancedFunctionHandle
properties(GetAccess = 'private', SetAccess = 'private')
handle
variables
end
methods
function obj = AdvancedFunctionHandle(fct, varargin)
if ~isa(fct,'function_handle')
error('The function must be a function handle!');
end
argins = numel(varargin);
variables = cell(1,argins);
for i = 1:argins
if ~ischar(varargin{i})
error('The variables must be represented by a string variabel name!');
end
if (~isvarname(varargin{i}) )
error('The variables must be a string representing a legal variabel name!');
end
variables{i} = varargin{i};
end
obj.handle = fct;
obj.variables = variables;
end
function val = subsindex(obj)
val = obj.calculate();
end
function val = calculate(obj)
try
vars = cell(1,numel(obj.variables));
for i = 1:numel(obj.variables)
v = evalin('base',obj.variables{i});
if isa(v,'AdvancedFunctionHandle')
vars{i} = v.calculate();
else
vars{i} = v;
end
end
val = obj.handle(vars{:});
catch
val = obj;
end
end
function display(obj)
disp([func2str(obj.handle),'(',strjoin(obj.variables,','),')']);
end
end
end
I made a small test script for it too:
clear
m = AdvancedFunctionHandle(#mean,'x');
s = AdvancedFunctionHandle(#(n)sum(1:n),'m');
m.calculate
x = [1,2,3];
s.calculate
I hope this solves your problem.
Notice that since the class refers to the base workspace, it will not work when run from a function, or if the script it is run from is run from a function.
I don't understand what you are trying to achieve, but if you want to define things after they are used, I think they have to be functions.
Example file:
function myfun()
mean(getX)
function X = getX
X = [1 2 3]
So though it is technically possible to define variables after they are used, you would really not want to do that.