Designing Function to Reduce Return Variables in Matlab - matlab

This is NOT a question where I need to know how to add A+B in MATLAB. This is more of a code design question.
I have few function files that return a numeric matrix and index info on the matrix. For example
function [Mat1, IdxID, IdxDate, IdxVal, IdxMarker, IdxOpen, ...] = First ()
....
.... % where IdxId = 1 ; IdxDate = 2 ; ...
end
function [Mat1, IdxUid, IdxName, IdxVal, Mat2, IdxUid2, IdxSalary2, ...] = Second ()
....
.... % where IdxUid= 1 ; IdxName= 2 ; ...
end
As you can see the code becomes clunky and when I call these functions, I have to declare an equal number of outputs to catch all the indices. The advantage is if I suddenly swap ID & Date columns, the calling functions do not change as I simply make ID=2, Date=1. I also have the advantage of renaming these variables inside the function.
Is there a better way to do this? I'm testing whether struct or cell can be used for indices. I can't use datasets or cell for returning numeric matrix. Too much time is lost in translating it into numbers. Thanks.

Yes, you can return arrays/cells/structs instead. For instance, id can be a struct with multiple variables. Your function definition could be as follows.
function [Mat, Id] = Second ()
...
end
In your function, have the following set:
Id.Name
Id.Val
Id.Salary
...
If you find that you have multiple structs with the same exact structure, you can even consider objects.
Please clarify with more details on the structure if you want a more detailed answer.

Related

MATLAB: Using get in cellfun for a cell array of objects

I've been stuck with this for a while and I couldn't find something similar asked previously (or I have failed in doing so)
My situation is fairly simple: I have a cell array of objects. They are all the same object and I have a get function for this kind of object which is: get (obj, attr), where obj is the object in question and attr is a integer from 1-6. Depending on the number the get function returns the corresponding attribute.
I would like to obtain all of my "position" attributes from all my objects which are in the corresponding cell array (this would be attr = 2). I know that cellfun performs a function on all cells, but the question is, how do I use my get function here for all my objects, taking into account that the function is get (obj, attr) ?
Thanks in advance
Firstly, by using get as a custom function you are shadowing the built-in get function - this is bad practise!
With this in mind, and to avoid confusion with the built-in get function which has similar syntax, I'm going to use getattr as a stand-in for your custom function which accpets an object and an integer 1 to 6.
pos = cellfun( #(obj) getattr( obj, 2 ), myCellOfObjects, 'uni', 0 );
By specifying 'uni', 0, the output doesn't have to be scalar and will be put into a cell array. This is useful when, for example, you have a multi-element array for your position.
This is equivalent to the following loop:
pos = cell( numel(myCellOfObjects), 1 );
for ii = 1:numel(pos)
pos{ii} = getattr( myCellOfObjects{ii}, 2 );
end
If ever in doubt about cellfun or arrayfun, just write a loop first - they are essentially the same but more concise.
There is a trick to this some are unaware of: you can pass multiple arguments to cellfun like this:
cellfun(#(obj,attr) get(obj,attr), {obj1,obj2},{attr1,attr2},'uni',0)
if you want to get one attribute of the cellarray (instead of providing an attribute for every object in the cellarray), then you can simply use this
cellfun(#(x) getattr(x,attr),obj,'uni',0)
put into anonymous function for convenience:
get_attr = #(obj,attr) cellfun(#(x) getattr(x,attr),obj,'uni',0)
%use:
get_attr(obj_in_cellarray,'myattribute')
%returns cell array of object attributes
I haven't run any of these functions since you didn't provide any example data / code. Please test and feedback.

MATLAB: Pass part of structure field name to function

I need to pass a part of a structure's name into a function.
Examples of a available structs:
systems.system1.stats.equityCurve.relative.exFee
systems.system1.stats.equityCurve.relative.inFee
systems.system2.stats.equityCurve.relative.exFee
systems.system2.stats.equityCurve.relative.inFee
systems.system1.returns.aggregated.exFee
systems.system1.returns.aggregated.inFee
systems.system2.returns.aggregated.exFee
systems.system2.returns.aggregated.inFee
... This goes on...
Within a function, I loop through the structure as follows:
function mat = test(fNames)
feeString = {'exFee', 'inFee'};
sysNames = {'system1', 'system2'};
for n = 1 : 2
mat{n} = systems.(sysNames{n}).stats.equityCurve.relative.(feeString{n});
end
end
What I like to handle in a flexible way within the loop is the middle part, i.e. the part after systems.(sysNames{n}) and before .(feeString{n}) (compare examples).
I am now looking for a way to pass the middle part as an input argument fNames into the function. The loop should than contain something like
mat{n} = systems.(sysNames{n}).(fName).(feeString{n});
How about using a helper function such as
function rec_stru = recSA(stru, field_names)
if numel(field_names) == 1
rec_stru = stru.(field_names{1});
else
rec_stru = recSA(stru.(field_names{1}), field_names(2:end));
end
This function takes the intermediate field names as a cell array.
This would turn this statement:
mat{n} = systems.(sysNames{n}).stats.equityCurve.relative.(feeString{n});
into
mat{n} = recSA(systems.(sysNames{n}), {'stats', 'equityCurve', 'relative', feeString{n}});
The first part of the cell array could then be passed as an argument to the function.
This is one of those cases where matlab is a bit unhelpful in the documentation. There is a way to use the fieldnames function in matlab to get the list of all the fields and iterate over that using dynamic fields.
systems.system1.stats.equityCurve.relative.exFee='T'
systems.system1.stats.equityCurve.relative.inFee='E'
systems.system2.stats.equityCurve.relative.exFee='S'
systems.system2.stats.equityCurve.relative.inFee='T'
systems.system1.returns.aggregated.exFee='D'
systems.system1.returns.aggregated.inFee='A'
systems.system2.returns.aggregated.exFee='T'
systems.system2.returns.aggregated.inFee='A'
dynamicvariable=fieldnames(systems.system1)
This will return a cell matrix of the field names which you can use to iterate over.
systems.system1.(dynamicvariable{1})
ans =
equityCurve: [1x1 struct]
Ideally you would have your data structure fixed in such a way that you know how many levels of depth are in your data structure.

Print the name of a variable on upon a plot/figure

Is it possible to refer back to/access the names of variables (say nx1 arrays) that make up a matrix? I wish to access them to insert there names into a plot or figure (as a text) that I have created. Here is an example:
A = [supdamp, clgvlv,redamp,extfanstat,htgvlv,occupied,supfanspd]
%lots of code here but not changing A, just using A(:,:)'s
%drawn figure
text(1,1,'supdamp')
...
text(1,n,'supfanspd')
I have failed in an attempt create a string named a with their names in so that I could loop through a(i,1), then use something like text(1,n,'a(i,1)')
Depending on your problem, it might make sense to use structures with dynamical field names.
Especially if your data in the array have some meaning other than just entries of a matrix in linear algebra sense.
# name your variables so that your grandma could understand what they store
A.('supdamp') = supdamp
A.('clgvlv') = clgvlv
...
fieldsOfA = fieldnames(a)
for n = 1 : numel(fieldsOfA )
text(1, n, fieldsOfA{n})
end

Provide variable argument list

I have a function which accepts a variable number of input variables. The problem is, the number of input arguments I'm going to provide varies. As such, I store all the arguments in a structure:
function grandAvg(datafiles)
% Load up all averaged datafiles
avgs = struct();
for n=1:length(datafiles)
avgs(n).avg = load(datafiles{n});
end
My question is, is there a way to expand this argument for the function? I need a way to convert this:
% DOES NOT WORK
avg = ft_timelockgrandaverage(cfg, avgs);
to this:
% WOULD WORK, BUT DO NOT WANT TO TYPE IT OUT
avg = ft_timelockgrandaverage(cfg, avgs(1).avg, ..., avgs(n).avg);
EDIT TO ADD: So apparently my question wasn't clear. I know how to construct the function using varargin. My question was, if I am trying to use a build-in function which I don't want to or can't modify, how can I provide arguments in a variable manner? I.e., I don't know ahead of time how many argument's I'll be providing, so when I call the function, I'll have to call it with X number of arguments. In effect, I'm looking for a way to turn this:
someVar <1xN struct>
into this:
someVar1 <1x1 struct>
someVar2 <1x1 struct>
...
someVarN <1x1 struct>
in a programmatic manner. Thanks!
An alternative to using a structure array to store your data would be to use a cell array. For example:
nFiles = numel(datafiles); %# Number of files
avgs = cell(1,nFiles); %# Initialize an empty cell array
for iFile = 1:nFiles %# Loop over the files
avgs{iFile} = load(datafiles{iFile}); %# Load the data into each cell
end
avg = ft_timelockgrandaverage(cfg, avgs{:}); %# Pass the contents to a function
The syntax avgs{:} dumps the contents of the cell array into what's called a comma-separated list. It is equivalent to typing avgs{1}, avgs{2}, ... , avgs{end}. The syntax foo(:).bar from the answer you found also creates a comma-separated list, but I find that using cell arrays for such a purpose is generally cleaner than using a structure array.
yes you can use variable length input argument list
varargin
http://www.mathworks.com/help/techdoc/ref/varargin.html
So, after playing around, I've got it. Using the example from above:
Given an 1xN struct named foo, where each foo(n) contains the field bar, I would call the function as:
function(foo(:).bar);
This is the same as typing
function(foo(1).bar, foo(2).bar, ..., foo(N).bar);
In this way, I can dynamically expand or shrink foo and still have no problem calling the function.
You can surely do such a thing, by means of the varargin construct in MATLAB. This will be something like:
avg = ft_timelockgrandaverage(cfg, avgs.avg);
And for the function ft_timelockgrandaverage
function output = ft_timelockgrandaverage(config, varargin)
% your code here
varargin will be a cell array: {avgs(1).avg, avgs(2).avg, ..., avgs(3).avg} which you can process.

MATLAB- passing a function handle parameter into another function as a handle

Working on an assignment involving Genetic Algorithms (loads of headaches, loads of fun). I need to be able to test differing crossover methods and differing mutation methods, to compare their results (part of the paper I have to write for the course). As such, I want to just pass the function names into the Repopulate method, as function handles.
function newpop = Repopulate(population, crossOverMethod, mutationMethod)
...
child = crossOverMethod(parent1, parent2, #mutationMethod);
...
function child = crossOverMethod(parent1, parent2, mutationMethod)
...
if (mutateThisChild == true)
child = mutationMethod(child);
end
...
The key point here is like 3, parameter 3: how do I pass mutationMethod down another level? If I use the # symbol, I get told:
"mutationMethod" was previously used as a variable,
conflicting with its use here as the name of a function or command.
If I don't use the # symbol, then mutationMethod gets called, with no parameters, and is quite unhappy.
While I am aware that yes, I could just rewrite my code to make it work differently, I'm now curious as to how to make it actually work.
Any help is greatly appreciated.
Actually just dont use the # symbol, use it when you call the Repopulate function instead.
Example:
function x = fun1(a,m)
x = fun2(a,m);
end
function y = fun2(b,n)
y = n(b);
end
which we call as:
> fun1([1 2 3], #sum)
6
Refer to the documentation for Passing Function Handle Arguments
Note you can check if the argument is a function handle by: isa(m,'function_handle'). Therefore you can make your function Repopulate more flexible by accepting both a function handle and a function name as a string:
function x = fun(a,m)
if ischar(m)
f = str2func(m);
elseif isa(m,'function_handle')
f = m;
else
error('expecting a function')
end
x = fun2(a,f);
end
which now can be called both ways:
fun1([1 2 3], #sum)
fun1([1 2 3], 'sum')