Functions with a flexible list of ordered/unordered and labeled/unlabeled inputs in MATLAB - matlab

A lot of MATLAB functions have an input structure such as:
output = function MyFun(a,b,c,'-setting1',s1,'-setting2',s2,'-setting3',s3)
I am wondering how I should implement this kind of functionality in my own functions. To be precise, I would like to find out how I can create a function such that:
The function has a variable number of inputs N + M
The first N inputs are ordered and unlabeled. In the example above, N = 3. The first input is always a, second input is always b, third input is always c. The function input is variable in that users do not necessarily need to send b, c; when they do not then these can take on default (hardcoded) values. As far as I know, this type of functionality is generally handled via varargin.
The remaining M inputs are unordered, but labeled. In the example above, M = 3, the variables are s1,s2,s3 and their labels are setting1,setting2 and setting3 respectively, I would like for users to be able to specify these variables in whatever order they want. If users choose not to specify one of these inputs (i.e. setting1), then I would like my function to assign default values for s1.
One example of such a function is the dlmwrite function.
Ideally, I am looking for an approach that is typically used by MATLAB developers so that my code is easy to understand.

The InputParser class addresses all of these issues. You can specify any number of:
Required parameters (ordered, unlabeled)
Optional parameters (ordered, unlabeled)
String parameter-value pairs in any order (unordered, labeled)
A very clear tutorial with examples is provided by MathWorks. For a function defined as function printPhoto(filename,varargin), the example boils down to the following.
Create the inputParser:
p = inputParser;
Specify defaults and define validation criteria:
defaultFinish = 'glossy';
validFinishes = {'glossy','matte'};
checkFinish = #(x) any(validatestring(x,validFinishes));
defaultColor = 'RGB';
validColors = {'RGB','CMYK'};
checkColor = #(x) any(validatestring(x,validColors));
defaultWidth = 6;
defaultHeight = 4;
Define required/optional/parameter input names, set their default values and validation functions:
addRequired(p,'filename',#ischar);
addOptional(p,'finish',defaultFinish,checkFinish);
addOptional(p,'color',defaultColor,checkColor);
addParameter(p,'width',defaultWidth,#isnumeric);
addParameter(p,'height',defaultHeight,#isnumeric);
Parse the inputs into a struct:
parse(p,filename,varargin{:});
Then you have the input arguments and their values in p.Results.
The InputParser class is used throughout newer MathWorks functions, so don't be afraid to use it yourself!

Related

How to pass Optional-Positional arguments to a function in matlab

I am trying to understand the usage of positional arguments in MATLAB and I was referring to this page.
Let's say I have a MATLAB function defined as follows:
function printPhoto(filename,varargin)
p = inputParser;
defaultFinish = 'glossy';
validFinishes = {'glossy','matte', 'colorful'};
checkFinish = #(x) any(validatestring(x,validFinishes));
defaultColor = 'RGB';
validColors = {'RGB','CMYK','colorful'};
checkColor = #(x) any(validatestring(x,validColors));
defaultWidth = 6;
defaultHeight = 4;
addRequired(p,'filename',#ischar);
addOptional(p,'finish',defaultFinish,checkFinish);
addOptional(p,'color',defaultColor,checkColor);
addParameter(p,'width',defaultWidth,#isnumeric);
addParameter(p,'height',defaultHeight,#isnumeric);
parse(p,filename,varargin{:});
end
When I call the above function as follows: printphoto('myFile.img', 'colorful'), is it possible to make this second argument to correspond to the second optional positional argument in the function definition i.e. color='colorful' and not finish='colorful'?
This is what you get when mixing optional-positional arguments and parameters. IMHO, you should use one or the other, but not both.
When you define an argument as positional, you're telling MATLAB that this input will always appear in that specific place, if it does appear. If you want to play around with the order of the inputs, that's exactly what a parameter-type argument is for.
Just think about it, the following syntaxes aren't that different:
printphoto('myFile.img','color','colorful')
printphoto('myFile.img', color='colorful' )
So I would suggest sticking with parameter-type arguments, but if you insist on having them positional, make sure that you assign a default value to the input if the user wants to "skip" it (by supplying some agreed-upon "null" value such as "" or []).

Call a function with several properties of an object

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{:}).

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

How to declare a function with an argument which is an array?

I need to declare a function that has 32 arguments, so it would be handy to put an unique argument: an array of 32 elements.
I don't find the syntax to do that, I've tried everythinh like:
function x=myfunction(str(32)) (etc...)
But without success.
Unlike other languages, MATLAB can accept matrices as a single argument; so you could just check that the input argument is a vector of length 32:
function x = myfunction(arg)
if length(arg) ~= 32
error('Must supply 32 arguments!');
end
%# your code here
end
If it's a variable number of arguments, check out varargin:
function x = myfunction(varargin)
But for 32 arguments, consider using an input structure:
function x = myfunction(argStruct)
if length(fieldnames(argStruct)) ~= 32
error('not enough arguments!');
end
Supply arguments in the structure, then pass the structure:
>> myArgs = struct();
>> myArgs.arg1 = 5;
>> myArgs.arg2 = 7;
>> %#(etc)
>> x = myfunction(myArgs);
Then in the function, you could either call argStruct.arg1, etc, directly; or unpack it into 32 different variables inside the function. I would give the fields descriptive names so you don't refer to them as arg1, etc inside your function. For that many input arguments, people using the function probably won't remember the order in which your function requires them to pass inputs to. Doing it with a struct lets users pass in arguments without needing to think about what order those inputs are defined.
To add to #strictlyrude27's awesome answer, it looks like you may misunderstand how function declarations work in Matlab. You wrote:
function x=myfunction(str(32))
However, you don't need to declare the type of input in matlab. Just give it a name, and then use it. So, the proper syntax for a declaration would be:
function x = myfunction(myInput)

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