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.
Related
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!)
Consider the following matlab program:
function results = prog()
opts.x = 1;
if ~isfield(opts, 'y'); opts.y = 1; end
'asdf'
return
I am able to run this program successfully in matlab however when I try to use coder to convert it to C I get the following error:
This structure does not have a field 'y'; new fields cannot be added when structure has been read or used.
I would like to know if there is a way to convert to C using coder (or possible some other tool) that does not use a stricter compiler as seems to be the case with coder as I am using it. I am using matlab version R2019B.
Please note that this is just one of many examples of how coder is using a stricter compiler than normal matlab. I have a fairly large program that I would like to convert to C and I don't want to have to go through each error (there are over 100).
Like Daniel mentioned, optional fields of structs don't exist in C, which is why MATLAB Coder errors on that code.
To make this code work with MATLAB Coder, opts could always have property y, but make it variable-sized and initialized to empty:
function results = prog()
opts.x = 1;
opts.y = [];
coder.varsize('opts.y');
if isempty(opts.y); opts.y = 1; end
'asdf'
end
Or you could create another options variable optsWithY that will have field y, even if opts doesn't:
function results = prog()
opts.x = 1;
optsWithY = opts;
if ~isfield(opts, 'y'); optsWithY.y = 1; end
'asdf'
end
This could even be moved into a helper function and assigned back to opts:
function results = prog()
opts.x = 1;
opts = addOpt(opts, 'y', 1);
'asdf'
end
function newOpts = addOpt(opts, field, defaultValue)
newOpts = opts;
if ~isfield(opts, field)
newOpts.(field) = defaultValue;
end
end
The difference between this and the original code is partial assignment opts.y = ... vs complete assignment opts = ....
Or like Cris mentioned, MATLAB Compiler will be a lot closer to MATLAB (though you won't get C code)
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.
I am trying to make my program work. It is for prime numbers.
Below is my function then my main program
I believe this is the right formatting, (obviously I'm probably wrong cause its not working) and I have been trying to fix it to no avail. Any help will be most appreciated and an explanation of what I am doing wrong (I am pretty sure it has to do with subtle formatting) would be great too.
function [answer,primefactors ] = primey1 (N)
for i=2:(N-1)
A(i-1)=rem(N,i);
end
A;
if(all(A)==1)
answer=['Yes']
primefactors=[1,N]
elseif(all(A)==0)
answer=['No']
fac=[]
for i=2:N
q=0;
while N/i==floor(N/i)
N=N/i;
q=q+1;
end
if q>0
fac=[fac,i]
if N==1
break
primefactors=[fac]
end
end
end
end
endfunction
As noted by Magla, MATLAB comes with the primes and factor functions, which you can at least use to compare your implementation with and/or check your outcomes.
Anyway, as for your code, try this:
function [answer, primefactors] = primey1(N)
% Use vectorization for simple cases such as these:
A = rem(N,2:N-1);
if all(A)
answer = 'Yes';
primefactors = [1,N];
% Re-wrote this entire section. There were a bunch of things wrong with it:
% the order of commands was wrong, variables were not assigned for some N,
% etc. Just compare the two implementations
else
answer = 'No';
primefactors = [];
for ii = 2:N
q = 0;
while N/ii == floor(N/ii)
N = N/ii;
q = q+1;
end
if q > 0
primefactors = [primefactors,ii]; %#ok<AGROW>
if N==1
break;
end
end
end
end
end
Matlab has a factor function that does what your code is trying to do
p = factor(10)
returns 2, 5
and
p = factor(11)
returns 11.
All you have is to test for length
if length(p) == 1
is true for prime numbers.
The solution as offered by #Rody should do the job, in theory even more efficient than this, however to illustrate the concept of initialization, I would recommend you to initialize the output variables of your function right after the function start. In your case this would mean that I recommend starting the code like this:
function [answer, primefactors] = primey1(N)
% Function to determine whether a number is prime and which prime factors it has
% Assign default values
answer = 'No';
primefactors = [];
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!)