Call a function with several properties of an object - matlab

For (MEX) function calls it would be really nice to pass several properties of one object at once. Instead of foo(myObj.propA, myObj.propB) I want something like foo(myObj.[propA,propB].
Is this even possible?
With structs it is possible to use the getfield() function to get the data from more than one field, e.g.:
getfield(myStruct, {index}, {'fieldA', 'fieldB'})
But unfortunately, the following attempt to get more than one property from an object results in an error (Index exceeds matrix dimensions):
getfield(myObj, {index}, {'propA', 'propB'})
Maybe the only possibility is to write a function which returns several output arguments:
[varargout] = getProps(object,propnames)
for p=1:numel(propnames)
varargout{p} = object.(propnames{p});
end
But if I call another function with that function as input, e.g. sum(getProps(myObj,propnames)) only the first output argument of getProps is passed and I fall into despair. Is there any other way?

For an object, you'd use get, not getfield (or dynamic access in a loop like you showed).
>> h = figure;
>> get(h,{'Position','Renderer'})
ans =
[1x4 double] 'opengl'
This doesn't work for all objects, but for MATLAB graphics objects it does work. To deal with any class, you can use your function, but with a custom cell output instead of varargout:
function C = getProps(object,propnames)
for p = 1:numel(propnames),
C{p} = object.(propnames{p});
end
Then inside whatever function you write, you can get a comma-separated list of all properties with C{:}, which will be suitable for a function that expects each property name input as a separate argument (e.g. C = getProps(myObj,propnames); x = myFun(h,C{:}).

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.

When can I pass a function handle?

I have a function for cached evaluation. As one of the arguments, it takes a function handle. Under some circumstances, the function handle is unaccessible, and I don't quite understand why. The example below shows what got me stumped:
>> A.a = #plus; feval(#A.a, 1, 1)
ans =
2
>> clear A
>> A.a.a = #plus; feval(#A.a.a, 1, 1)
Error using feval
Undefined function 'A.a.a' for input arguments of type 'double'.
So, if I have a function handle stored as a structure member, I can pass it along fine if it's one level deep, but not if it's two levels deep. In my real use case, I have a structure D that holds many (117) instances of various classes, so I actually have stct.obj.meth, where stct is a structure, obj is a class instance/object, and meth is a method. Passing #stct.obj.meth fails, but if I assign A = stct.obj, then passing #A.meth succeeds.
Under what conditions can I pass a function handle as an argument, so that it's still accessible down the stack?
Edit: Although in the use case above, I could simply remove the # because #plus is already a function handle. However, consider the situation here:
>> type cltest.m
classdef cltest < handle
methods
function C = mymeth(self, a, b)
C = a + b;
end
end
end
>> A.a = cltest();
>> feval(#A.a.mymeth, 1, 1)
Error using feval
Undefined function 'A.a.mymeth' for input arguments of type 'double'.
>> b = A.a;
>> feval(#b.mymeth, 1, 1)
ans =
2
In this case, I need the # before A.a.mymeth...
Introducing classes was a big deal for MATLAB. So big, in fact, that they still do not work properly today. Your example shows that structure access and class method access conflict, because they had to overload the the meaning of dot '.' and didn't get it to work seamlessly. It all more or less works fine when you are calling class methods explicitly by their name on the MATLAB console, e.g. in your example >> A.a.mymeth(1,1). But when you have any type of indirection, it soon breaks.
You tried getting the function handle by >> #A.a.mymeth, which MATLAB cannot make sense of, probably because it gets confused by the mixed structure/class thing. Trying to work around using str2func doesn't work either. It works, again, only for explicit name access, as shown here. It breaks for your example, e.g. >> str2func('b.mymeth'). It does not even work inside the class. Try other indirections and watch them fail.
Additionally, MATLAB does not like giving you a class method's handles. There's no function for it. There's no way to get all function handles in one go, or even dynamically by a name string.
I see three options here. First, try changing your program, if possible. Do these functions need to sit in a classdef?
Second, follow your or nispio's workaround. They both create a temporary variable to hold a reference to the class instance in order to create a non-mixed access to its member methods. The problem is, they both require explicitly naming the function. You have to explicitly put this code for every function involved. No way to abstract that out.
Third, cheat by giving out your class' method handles from the inside. You can give them out in a structure.
classdef cltest < handle
methods
function C = mymeth(self, a, b)
C = a + b;
end
function hs = funhandles(self)
hs = struct('mymeth', #self.mymeth, ...
'mymeth2', #self.mymeth2);
end
end
end
You can then access the handles by name, even dynamically.
>> A.a = cltest;
>> feval(A.a.funhandles.mymeth, 1, 1);
>> feval(A.a.funhandles.('mymeth'), 1, 1)
ans =
2
But be careful, by using this you can access Access=private methods from outside.
Try this:
feval(#(varargin)A.a.mymeth(varargin{:}),1,1);
It is a little kludgy, but it should work.
EDIT:
The way it works is by creating an Anonymous Function that takes a variable number of arguments, and dumps those arguments into the method A.a.mymeth(). So you are not actually passing a pointer to the function A.a.mymeth, you are passing a pointer to a function that calls A.a.mymeth.
An alternative way of achieving the same thing without using varargin would be:
feval(#(x,y)A.a.mymeth(x,y),1,1);
This creates an anonymous function that accepts two arguments, and passes them along to A.a.mymeth.
<speculation> I think that it must be inherent in the way that the unary function handle operator # works. The Matlab parser probably looks at #token and decides whether token is a valid function. In the case of a.mymeth it is smart enough to decide that mymeth is a member of a, and then return the appropriate handle. However, when it sees A.a.mymeth it may discover that A is not a class, nor does A have a member named a.mymeth and therefore no valid function is found. This seems to be supported by the fact that this works:
A.a.a = #plus; feval(A.a.a,1,1)
and this doesn't:
A.a.a = #plus; feval(#A.a.a,1,1)
</speculation>
You can get around it by introducing a separate function that corrects what # operator is not doing:
function h=g(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
h = evalin('caller', ['#(varargin)' x.function '(varargin{:})']);
else
h = f;
end
end
Now for your example:
>> feval(g(#A.a.mymeth), 1, 1)
ans =
2
>> feval(g(#b.mymeth), 1, 1)
ans =
2
I think this will have the smallest impact on your code. You can make it a bit more elegant but less robust and/or readable. The uplus method is not defined for function_handle class so you can create uplus.m in folder #function_handle somewhere in your path with this content:
function h=uplus(f)
x = functions(f);
if ~strcmp(x.type, 'anonymous')
h = evalin('caller', ['#(varargin)' x.function '(varargin{:})']);
else
h = f;
end
end
Now you just need to use +# instead of #. For your examples:
>> feval(+#A.a.mymeth, 1, 1)
ans =
2
>> feval(+#b.mymeth, 1, 1)
ans =
2

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')