Concatinating multiple function outputs

8 views (last 30 days)
I have a few functions that each returns 3 output values, within a for loop using i as a counter. Is there a nice way to assign values, in the sense that i am currently using:
for i=1:n
[TestValues(i,1), assymp(1), names{1}] = ftesttype1(I(:,i),p,sign);
[TestValues(i,2), assymp(2), names{2}] = ftesttype2(I(:,i),p,sign);
...
end
As you can see i have manually labelled them 1 and 2 for their places. Is there a way such taht the output will automatically move to the right spot ? - Ie. after ftesttype1 has returned its values ftesttype2 will put them in the right place without me needing to specify that spot 2 is to be used in the vectors TestValues, assymp and names.
The thing is i have meaby 50 such functions and how many changes sort of often. So i have to manually retype some 150 numbers alot (and check that i have done so correctly).
Thanks ALOT in advance!
  4 Comments
Star Strider
Star Strider on 21 Apr 2014
Tough indeed!
You appear to be fluent with MATLAB, so I assume you have done everything you can to optimise this. I’m a bit confused by your statement about ‘ftesttype2 putting the values returned by ftesttype1 in the right place’. The loop subscripts in the array assignments should do this. Are you passing the outputs of testtype1 to testtype2? It doesn’t seem so from the argument list, but I’m confused.
Thor
Thor on 21 Apr 2014
What I meant to communicate was that after the first function has placed its output, I need the second function to place its own output correctly.
In total I have meaby 50 function calls, each returning 3 output variables. And it all happens within the loop. What I need is Basically a way to recode this in such a way that I avoid manually retyping the test number (1,...,50) for each function called.
The reason I have to do so is partly to work faster, but also because I may need to publish some of the code and I am therefore trying to make it "nice" and flexible.
Thanks for taking an interest !

Sign in to comment.

Accepted Answer

Sean de Wolski
Sean de Wolski on 21 Apr 2014
Edited: Sean de Wolski on 21 Apr 2014
If you have a cell array containing your function handles, you could perhaps use cellfun to do the work for you:
Very simple example:
clear C % important for dynamic preallocation
funs = {@sin,@cos}; % function handles
vals = rand(1,50)*2*pi; % example values to loop over
for ii = numel(vals):-1:1
% Build anonymous function for each value and evaluate all functions at that value storing the result in the iith row of C
C(ii,:) = cellfun(@(x)x(vals(ii)),funs,'UniformOutput',false);
end
note 1 This also gives you the advantage of not necessarily having to input each function name. You could perhaps use dir to scrape a "functions to use" directory and then str2func to build the cell array automatically.
note 2 You don't need to use cellfun, but could use a loop instead. The key takeway here is the cell array containing the functions.
  3 Comments
Sean de Wolski
Sean de Wolski on 22 Apr 2014
I feel kinda icky writing code to do this since it seems like there must be a better global approach to your publishing goals. But it works :)
%%Example setup
funs = {@sin, @cos, @max, @(x,y,z)(x+y+z)}; % function handles
vals = rand(1,50)*2*pi; % example values to loop over
extra_inputs = {{[]};{[]};{2};{2, 10}}; % each row contains extras, empty rows for functions that don't have them
idXtra = ~cellfun(@(x)isempty(x{1}),extra_inputs(:,1)); % which have extras?
%%Some useful info
nVals = numel(vals);
nFuns = numel(funs);
C = cell(nVals,nFuns);
%%Engine
for ii = 1:nVals
% Loop over values
% Build anonymous function for each value and evaluate all functions at that value storing the result in the iith row of C
for jj = 1:nFuns
% Extract function jj
fjj = funs{jj};
% Decide what to do
if idXtra(jj)
% Append extra inputs (jjth row)
foo = @(x)feval(fjj,x,extra_inputs{jj}{:});
else
% No extras
foo = fjj;
end
% Call foo, save output to cell
C(ii,jj) = {foo(vals(ii))};
end
end
Now the reason I'm using feval like that is because I assume you're going to want to be able to change the extra inputs. If you aren't, you could build the anonymous functions to always accept only one input, x, and pass the rest in based on their value at creation. This would greatly simplify the process but would not be flexible to updating the extra inputs during run time.
For example:
@(x)(x+y+z)
Now y and z are static snapshots of whatever they are when you create this. Once again, it's a little cleaner but doesn't scale well at all.
Thor
Thor on 23 Apr 2014
Thanks a bunch it is working! :)

Sign in to comment.

More Answers (1)

Walter Roberson
Walter Roberson on 20 Apr 2014
There is nothing in MATLAB similar to "use the above as an example".
Are all of the functions called the same way? If so then you can use
for K = 1 : 50 %build table of function handles
funtab{K} = str2fun(sprintf('ftesttype%d', K));
end
for i = 1 : n
for K = 1 : 50
TestValues(i, K), assymp(K), names{K}] = funtab{K}(I(:,i), p, sign);
end
end
  2 Comments
Thor
Thor on 21 Apr 2014
Unfurtunately they arent named in such a way, they are named quite different and some of them are sometimes called multiple times but with different parameter inputs.
ps. good suggestion using funtab{k}(input), had never thought of something like that. But in this case i dont think it will work.
Walter Roberson
Walter Roberson on 21 Apr 2014
Using a function table can account for calling the same function multiple times: just have multiple entries with the same handle.
Likewise you can use a cell array to hold all of the different inputs. You can do part of the breaking up of I(:,i) automatically by using mat2cell()
It might possibly be more convenient to reorder the calls so all of the ones with the same structure are done together. If the output order makes a difference for the remainder of your code, you could reorganize the outputs after the call loop.
Categorize and parameterize the calls as much as feasible. You can, for example, have a table which looks something like
output_number call_variety function_index parameter1_index
where call_variety is an index that tells you which variety of call it is, in the sense of which variables need to be passed.
I have, for example, written table-driven decompilers that mapped machine code byte into an "instruction format" code that knew (e.g.) that the instruction was a immediate-to-register instruction with specific offset and bit length encoding the destination register and specific offset and bit length encoding the "immediate" value; other instruction formats coded for register-to-register or condition-code bits and so on. The "variety" in the table encoded which kind of situation the entry should be treated as.

Sign in to comment.

Categories

Find more on Function Creation in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!