Access to methods and properties for classes with overloaded index reference - matlab

I want to overload the indexing via () and {} for one of my MATLAB classes. This is possible by implementing subsref for that class, and it works fine.
However, I also want to keep the default behaviour of indexing via . (i.e. access to methods and properties) for this class. I tried using the following code:
function x = subsref(this, S)
if strcmp(S(1).type, '{}')
% My own implementation here
elseif strcmp(S(1).type, '()')
% My own implementation here
elseif strcmp(S(1).type, '.')
x = builtin('subsref', this, S);
else
error('Unknown index variant.');
end
However, this does not work because I do not know a priori how many output arguments the call to builtin('subsref', this, S) will return. In particular, a method of my class might return a variable number of arguments, with the number of output arguments depending on the number and values of its input arguments. A MATLAB example for subsref (broken link) notes:
When you implement a subsref method for a class, you must implement all subscripted reference explicitly [...]
Is this really the only possible solution? For complex methods this basically means duplicating a lot of the logic. This is definitely not maintainable in my case (large classes with a lot of methods and properties).
Note: I know that this is all about syntactic sugar and that I can always use standard method calls instead of overloading () and {}.

For a partial fix, I think you can use nargout to defer to the caller, which will usually be in a position to know. Any function that's capturing multiple outputs must know at the time of the call how many it's capturing.
This won't let you display multiple argouts at the command line, but should work as long as you're as you're capturing the returned values, as in most code.
function varargout = subsref(this, S)
switch S(1).type
...
case '.'
varargout = cell(1, nargout);
if nargout == 0
builtin('subsref', this, S);
else
[varargout{:}] = builtin('subsref', this, S);
end
end
end
Caveat emptor: this code is not tested, and there's a bunch of finicky edge cases inside the subsref/subsasgn stuff.

Related

MATLAB forbid `end` as class method input

classdef Dog
methods
function out = bark(obj, text)
% disp(text)
out = 1;
end
function ind = end(~, ~, ~)
error("`end` forbidden")
end
end
end
d=Dog(), d(end) will error but d.bark(end) won't.
Uncommenting disp(text) instead errors as Not enough input arguments, but that's not same as forbidding end as input to bark.
d.bark(end, end) errors as Too many input arguments.
Can end be forbidden (or detected) as input to any method of d?
It looks like d.bark(end) calls d.bark first, obtaining the output array out, then calls end(out,1,1). This end is not your overloaded function, it is the version for whatever type out is, which in your case is double. So this is the built-in out. This end returns 1. Finally, it calls d.bark(1).
I think this is a strange behavior. MATLAB only does this for class methods, not for free functions. For example sqrt(end) or eps(end) give the error "The end operator must be used within an array index expression.".
I don't think there is a way around this, it is built-in MATLAB behavior, it would require changing the interpreter to override the behavior.

How to write an anonymous function with a variable number of output arguments?

Using deal we can write anonymous functions that have multiple output arguments, like for example
minmax = #(x)deal(min(x),max(x));
[u,v] = minmax([1,2,3,4]); % outputs u = 1, v = 4
But if you want to provide a function with its gradient to the optimization function fminunc this does not work. The function fminunc calls the input function sometimes with one and sometimes with two output arguments. (EDIT: This is not true, you just have to specify whether you actually want to use the gradient or not, using e.g. optimset('SpecifyObjectiveGradient',true). Then within one call it always asks for the same number of arguments.)
We have to provide something like
function [f,g] = myFun(x)
f = x^2; % function
g = 2*x; % gradient
which can be called with one or two output arguments.
So is there a way to do the same inline without using the function keyword?
Yes there is, it involves a technique used in this question about recursive anonymous functions. First we define a helper function
helper = #(c,n)deal(c{1:n});
which accepts a cell array c of the possible outputs as well as an integer n that says how many outputs we need. To write our actual function we just need to define the cell array and pass nargout (the number of expected output arguments) to helper:
myFun = #(x)helper({x^2,2*x,2},nargout);
This now works perfectly when calling fminunc:
x = fminunc(myFun,1);
The OP's solution is good in that it's concise and useful in many cases.
However, it has one main shortcoming, in that it's less scalable than otherwise possible. This claim is made because all functions ({x^2,2*x,2}) are evaluated, regardless of whether they're needed as outputs or not - which results in "wasted" computation time and memory consumption when less than 3 outputs are requested.
In the example of this question this is not an issue because the function and its derivatives are very easy to compute and the input x is a scalar, but under different circumstances, this can be a very real issue.
I'm providing a modified version, which although uglier, avoids the aforementioned problem and is somewhat more general:
funcs_to_apply = {#(x)x.^2, #(x)2*x, #(x)2};
unpacker = #(x)deal(x{:});
myFun = #(x)unpacker(cellfun(#(c)feval(c,x),...
funcs_to_apply(1:evalin('caller','nargout')),...
'UniformOutput',false)...
);
Notes:
The additional functions I use are cellfun, evalin and feval.
The 'UniformOutput' argument was only added so that the output of cellfun is a cell (and can be "unpacked" to a comma-separated list; we could've wrapped it in num2cell instead).
The evalin trick is required since in the myFun scope we don't know how many outputs were requested from unpacker.
While eval in its various forms (here: evalin) is usually discouraged, in this case we know exactly who the caller is and that this is a safe operation.

How to get the number of outputs from a handle to a method in Matlab?

You can call methods of an object using function handles. Example:
classdef foo
methods
function value=foofun(this)
value=1;
end
end
end
and then
fun=#foofun;
fun(foo);
The handle is just a string I guess, and it doesn't bother Matlab that it can't tell which function is intended before the handle is used. The same handle could even be used to call different methods if different type objects are used as the first parameter.
To capture the outputs of the function you can do this:
outputs=cell(numberOfOutputs,1);
[outputs{:}]=fun(foo);
However, if the function handle was a parameter in the code, then the number of outputs is a problem. For handles to normal functions nargout would solve that, but now nargout can't help because the handle doesn't determine on it's own which function will be called. nargout would need a second input, the type of the object that is going to be used.
It's a bit inelegant to need both the handle and the number of outputs as parameters. Is there another way to call methods indirectly and still capture all the outputs?
Use-case
Imagine a graph with nodes and edges between nodes. Each edge has a few data objects associated with that particular edge. I'm interested in doing various calculations on those data objects.
Examples
Take all the data objects associated with a specific edge and calculate spectra of those objects.
Use the prettiest data object from each edge and get the spectra from those objects.
Choose ten edges randomly, choose randomly one data object from each of those and then compare the objects with a specific, separate, object.
Design
The idea is to separate the selection of the objects and the calculations into different functions. This way the user can combine any calculation with any selection method. Each time a new method is added to the data objects, it can already be called with the existing object selection methods and each time a new selection method is added, it can be used with all the available calculation methods.
A simplified version of a function I'm currently using looks like this
function [ outs ] = callForEach(objects, fun, numberOfOutputs, extraArguments)
for ii=1:length(objects)
out=cell(1,numberOfOutputs);
[out{:}]=fun(objects{ii},extraArguments{ii,:});
outs(ii,:)=out;
end
end
I'd like to be able avoid the parameter numberOfOutputs. It's an inconvenience for the user and it's more error prone to do it like this.
I guess I could just force a same interface for every method: everybody returns a cell array if they need several outputs. I can then assign that cell array, or whatever it is that is returned, into a single cell. However all the built-in functions seem to prefer to use multiple outputs instead, so there's at least a stylistic difference. If I ever wanted to use one of the built-ins as the handle, I'd need to write a wrapper to make the built-in conform to the interface.
Check this class as foo.m. By running foo.main() you recover most of the addressed questions.
This is not the maximum elegance in OOP, but you have Matlab as is.
Remember the obj variable is MANDATORY, in and out. No obj, no dot fanciness.
The final calls, HAVE to include the f1. Putting a ~ lost not only the fanciness, but the object and its data.
Besides the obj treatment, nargin|nargout|varargin|varargout are valid inside a function body only, and is runtime dependent, as usually. One cannot in general know how much parameters you will throw, because is equivalent to the length of the varargout cell.
classdef foo
properties
value;
end
methods
function [obj,flag]=fun1(obj,this)
obj.value=this+1;
flag=1;
end
function [obj,flag]=fun2(obj,this)
obj.value=2*this;
flag=2;
end
function [obj,varargout]=fun3(obj,varargin)
for i=1:nargin-1
varargout{i}=varargin{i};
end
obj.value=0;
end
end
methods (Static)
function main()
if 0
%% Run this line
foo.main()
end
f1=foo();
[f1,flag]=f1.fun1(10);
flag
f1.value
f=#fun2;
%[f1,flag]=f1.f(10); % fails
flag
f1.value
[f1,flag]=f1.('fun2')(10);
flag
f1.value
[~,flag]=f1.fun2(10); % fails
flag
f1.value
[f1,a1,a2,a3,a4]=f1.fun3('x1',2,[],#(x)(x>1))
end
end
end

Equivalent of isnumeric(X) & ~isnan(X)?

I find myself writing stuff like this a lot:
if isnumeric(X) & ~isnan(X)
% etc etc
end
Before I clutter the namespace with my own test
function out = isanumber(X)
out = isnumeric(X) & ~isnan(X);
end
does MATLAB already have an equivalent test?
No, there isn't.
NaN is of a numeric class (double by default, conforming to IEEE754), which makes isnumeric evaluate to true when passed the NaN. I'll immediately admit that the seemingly trivial
isnumeric ( not a number )
actually gives true is somewhat counter-intuitive, but it makes perfect sense when you're reading large amounts of data from a file for instance, and some elements of the matrices read thusly are NaN (missing, misconverted or similar) -- in such cases, it would be pretty darn annoying if isnumeric(NaN) would then say false.
So as usual, it all depends on how you look at it. The MathWorks decided (quite possibly after a lot of research) that the cases in which it makes sense to return true are far more numerous than the opposite. So, you'll have to always manually test both cases I'm afraid.
By the way, you wouldn't be cluttering so much if you just make it a sub- or nested function:
% All in the same file:
function varargout = main(varargin)
% Delegate checking, parsing, etc. the input arguments
% to a subfunction
[varargin{1:nargin}] = parseInputArguments(varargin{:});
% ...So you can just go on and do all your main stuff here
% without all the usual clutter of parsing the arguments
end
% Main's argument parser
function varargout = parseInputArguments(varargin)
% ...parse all sorts of stuff here
% the readable test:
if isanumber(varargin{2})
varargout{2} = rand(5); end
% ...parse more stuff here
% nested helper function to aid readibility without
% polluting the main function namespace too much
function yn = isanumber(x)
yn = isnumeric(x) & ~isnan(x);
end
end
More than likely you want isfinite(X).
Admittedly it isn't exactly equivalent to isnumeric(X) & ~isnan(X), it's equivalent to isnumeric(X) & ~isnan(X) & ~isinf(X), but I'm guessing you don't want the other special cases (plus and minus infinity) either.

A command to catch the variable values from the workspace, inside a function

when I am doing a function in Matlab. Sometimes I have equations and every one of these have constants. Then, I have to declare these constants inside my function. I wonder if there is a way to call the values of that constants from outside of the function, if I have their values on the workspace.
I don't want to write this values as inputs of my function in the function declaration.
In addition to the solutions provided by Iterator, which are all great, I think you have some other options.
First of all, I would like to warn you about global variables (as Iterator also did): these introduce hidden dependencies and make it much more cumbersome to reuse and debug your code. If your only concern is ease of use when calling the functions, I would suggest you pass along a struct containing those constants. That has the advantage that you can easily save those constants together. Unless you know what you're doing, do yourself a favor and stay away from global variables (and functions such as eval, evalin and assignin).
Next to global, evalin and passing structs, there is another mechanism for global state: preferences. These are to be used when it concerns a nearly immutable setting of your code. These are unfit for passing around actual raw data.
If all you want is a more or less clean syntax for calling a certain function, this can be achieved in a few different ways:
You could use a variable number of parameters. This is the best option when your constants have a default value. I will explain by means of an example, e.g. a regular sine wave y = A*sin(2*pi*t/T) (A is the amplitude, T the period). In MATLAB one would implement this as:
function y = sinewave(t,A,T)
y = A*sin(2*pi*t/T);
When calling this function, we need to provide all parameters. If we extend this function to something like the following, we can omit the A and T parameters:
function y = sinewave(t,A,T)
if nargin < 3
T = 1; % default period is 1
if nargin < 2
A = 1; % default amplitude 1
end
end
y = A*sin(2*pi*t/T);
This uses the construct nargin, if you want to know more, it is worthwhile to consult the MATLAB help for nargin, varargin, varargout and nargout. However, do note that you have to provide a value for A when you want to provide the value of T. There is a more convenient way to get even better behavior:
function y = sinewave(t,A,T)
if ~exists('T','var') || isempty(T)
T = 1; % default period is 1
end
if ~exists('A','var') || isempty(A)
A = 1; % default amplitude 1
end
y = A*sin(2*pi*t/T);
This has the benefits that it is more clear what is happening and you could omit A but still specify T (the same can be done for the previous example, but that gets complicated quite easily when you have a lot of parameters). You can do such things by calling sinewave(1:10,[],4) where A will retain it's default value. If an empty input should be valid, you should use another invalid input (e.g. NaN, inf or a negative value for a parameter that is known to be positive, ...).
Using the function above, all the following calls are equivalent:
t = rand(1,10);
y1 = sinewave(t,1,1);
y2 = sinewave(t,1);
y3 = sinewave(t);
If the parameters don't have default values, you could wrap the function into a function handle which fills in those parameters. This is something you might need to do when you are using some toolboxes that impose constraints onto the functions that are to be used. This is the case in the Optimization Toolbox.
I will consider the sinewave function again, but this time I use the first definition (i.e. without a variable number of parameters). Then you could work with a function handle:
f = #(x)(sinewave(x,1,1));
You can work with f as you would with an other function:
e.g. f(10) will evaluate sinewave(10,1,1).
That way you can write a general function (i.e. sinewave that is as general and simple as possible) but you create a function (handle) on the fly with the constants substituted. This allows you to work with that function, but also prevents global storage of data.
You can of course combine different solutions: e.g. create function handle to a function with a variable number of parameters that sets a certain global variable.
The easiest way to address this is via global variable:
http://www.mathworks.com/help/techdoc/ref/global.html
You can also get the values in other workspaces, including the base or parent workspace, but this is ill-advised, as you do not necessarily know what wraps a given function.
If you want to go that route, take a look at the evalin function:
http://www.mathworks.com/help/techdoc/ref/evalin.html
Still, the standard method is to pass all of the variables you need. You can put these into a struct, if you wish, and only pass the one struct.