input parser and function handle - matlab

I am using the Matlab input parser and want to parse a function handle using this code:
p = inputParser;
p.addOptional('progresscallback', 0, #(x) isa(x,'function_handle') );
p.parse(varargin{:});
This works well for a given function handle, but fails for no handle with
Argument 'progresscallback' failed validation #(x)isa(x,'function_handle').
Now I wonder how to contruct the testing function or the default value to make it work.

If you just want to accept either empty or function handle inputs, you can modify the testing function like this:
#(x) isempty(x) || isa(x,'function_handle')
The short-circuit OR (||) won't evaluate the second half of the test if the first one is already true. BTW, you may also want to set your default value to [].

Related

How to test arguments for a figure or axis object in MATLAB 2022?

A function receives a figure or axis object object as parameter.
I want to test this as shown in the FIXME line.
Which test should be used here in order to allow all valid objects for exportgraphics?
% myexportgraphics.m
function myexportgraphics(f)
arguments
f (1,1) {}; % FIXME add a test here
end
exportgraphics(f,...);
end
This full list of validation functions is documented here:
https://uk.mathworks.com/help/matlab/matlab_prog/argument-validation-functions.html
The only relevant one for checking the input type (other than ones for specific types like "double") is mustBeUnderlyingType
You can check which types are valid using underlyingType on example objects you want to accept.
underlyingType( figure() ); % 'matlab.ui.Figure'
underlyingType( axes() ); % 'matlab.graphics.axis.Axes'
So this would check for figures
function myexportgraphics(f)
arguments
f (1,1) {mustBeUnderlyingType(f,'matlab.ui.Figure')};
end
end
However, that doesn't allow multiple variable types, so per the docs you probably want to make your own validation function
function myexportgraphics(f)
arguments
f (1,1) {mustBeExportGraphicsType(f)};
end
end
function mustBeExportGraphicsType(g)
if ~ismember( class(g), {'matlab.ui.Figure','matlab.graphics.axis.Axes'} )
eidType = 'mustBeExportGraphicsType:notExportGraphicsType';
msgType = 'Input must be a figure or axes object';
throwAsCaller(MException(eidType,msgType));
end
end
These are the requirements for a custom validation function, emphasis mine:
Functions used for validation have these design elements:
Validation functions do not return outputs or modify program state. The only purpose is to check the validity of the input value.
Validation functions must accept the value being validated as an input argument. If the function accepts more than one input argument, the first input is the value to be validated.
Validation functions rely only on the inputs. No other values are available to the function.
Validation functions throw an error if the validation fails. Using throwAsCaller to throw exceptions avoids showing the validation function itself in the displayed error message.
Creating your own validation function is useful when you want to provide specific validation that is not available using the MATLAB validation functions. You can create a validation function as a local function within the function file or place it on the MATLAB path.
As an aside, you could use ishghandle within the custom validation function which returns true for figure and axes inputs. If you didn't use the arguments validation syntax, you could instead use ishghandle with the slightly older inputParser approach to input validation, or a simple assert near the start of your function, but that's probably beyond the scope of this question.

Passing names of functions to another function with parameters as input in MATLAB

Problem Statement: I am trying to write MATLAB code for a main caller function (like run_experiment below) to specify which computations I want to execute where computations are made sequentially using other MATLAB functions. Those other functions are to be evaluated based on parameters passed with the main caller function. The said functions used in computations are to be specified with name of the scripts they are written in.
Example Desired Code Behavior: For example, a command like the following should run the preprocess_data, initialise_model and train_model scripts.
>> run_experiment('dataset_1_options', '|preprocess_data|initialise_model|train_model|');
And this command should run only the train_model script but also evaluates its performance:
>> run_experiment('dataset_1_options', '|train_model|evaluate_model|');
In the above examples "|" is used as a delimiter to specify separate function names to be evaluated. Those functions use the options specified with dataset_1_options. Please do not focus on how to separate that part of the input into meaningful function names; I know how to do it with strsplit.
Constraints and Specifications: The function names to be passed as input to the main caller function are NOT anonymous functions. The purpose is to be able to pass such multiple function names as input AND to evaluate them with the options like the above example. They return output to be evaluated in other parts of the research code (i.e. passing data matrices to other functions within the research code as results of the computations carried out within them.)
Question: Given the desired behavior and constraints mentioned above, can anybody help in how to pass the separate function names from another caller function along with options/parameter to those functions? How should the main caller function evaluate the function names passed in as input with the options specified during the call?
Thank you in advance.
You can pass functions to functions in matlab. You just need to use the # sign when you pass it. In your case it would be run_experiment('dataset_1_options', #train_model) inside a script. You could keep your options in a cell array or something. The run_experiment function would just be a regular function,
function [output] = run_experiment(options, train_model, ...);
train_model(options{1}, ...)
.
.
.
end
What you need to do this is create a cell array with your function names and another array with the corresponding options as below
% Function name array
fn_array = {#fn_1, #fn_2, ...};
% Option array
option_array = {{fn1_opt1, fn2opt2, ...}; {fn2_opt1, fn2_opt2, ...};, ...};
These two need to be passed to your run_experiment function which will evaluate them as below
function run_experiment(fn_array, option_array)
num_fn = length(fn_array); %Finds number of functions to evaluate
for ii = 1:num_fn %Evaluates each function
fn_array{ii}(option_array{ii}{:});
end

MATLAB Beginner recursive functions

Just having a little difficulty with the syntax of matlab functions;
function f = fact(x)
if x == 1
return
else
f = 1 - x*(fact(x-1))
end
end
When calling this function in the command window with the argument 10 I receive the error
Undefined function 'fact' for input arguments of type 'double'.
Error in recursion (line 6)
f = 1 - x*(fact(x-1))
I've had a look around and solutions for the first revolve around the pathing of the m-file which doesn't seem to be a problem as other files in the same directory run fine,
The second I'm not sure why the error in line 6 occurs, my guess is it has something to do with the variable and function names.
As a side question, are both these end statements necessary?
Thanks!
The most obvious error is your function filename. You have a function called fact defined in your code but you named your file recursion. Make sure that both your function name and the filename are both called fact.
If you were to name your file as recursion, then make the function name defined in your code as fact, this is what would happen if you tried calling your code:
>> f = recursion(10);
Undefined function 'fact' for input arguments of type 'double'.
Error in recursion (line 6)
f = 1 - x*(fact(x-1));
... look familiar?
As such make sure your filename and your function name are named the same. In fact, in the MATLAB editor, it should automatically give you an error saying that both of these are not the same.
There is also another error in your code. The base case is not defined properly. Always remember when you are writing recursive algorithms is that eventually the function is going to return... and that's when you hit the base case. We can see here that it is when x = 1. When x = 1, you're supposed to assign something to f which is the output. You are simply exiting the function, and so when x becomes 1, your code will spit out an error saying that f was not assigned when the function finishes. As such, you need to figure out what your base case is. I'm going to assume that your base case (when x = 1) is going to equal 0. You will obviously need to change this as I don't know what your code is actually computing. Basically, you need to do this:
function f = fact(x)
if x == 1
f = 0; %// Base case needs to change according to your specs
else
f = 1 - x*(fact(x-1))
end
end
When I do this, I get the following output when x = 10
>> f = fact(10);
f =
1334961
I don't get an error when I run this code now. Also, check to see if you have any variables named fact in your workspace. When this happens, you are in fact shadowing over your function with a variable, so it is actually trying to access the variable called fact instead. As such, try clearing your workspace by doing clear all;, then try this code again.
One warning
If you were to specify x to be 0 or negative, this function will never stop. As such, you need to provide some check and perform the proper action when this happens. Also, you need to make sure that you specify what type of inputs are accepted for x. Judging from the context, x are positive integers only. As what #Glen_b has noted, should you provide any number that isn't a positive integer, this function will never stop as x will never equal 1 down the recursion pipeline.
To answer your optional question
The first end statement is required to end the if statement. The second end statement isn't required, but it's good practice anyway. However, if you have multiple functions defined inside your function file, then yes it is most definitely required to properly signify that the end of that function is defined there. However, you don't need it if you're only writing one function per file, but I would recommend keeping it there as it's good practice.

Picking out the fourth value of a function using an anonymous function [duplicate]

I have a function that returns two values, like so:
[a b] = myfunc(x)
Is there a way to get the second return value without using a temporary variable, and without altering the function?
What I'm looking for is something like this:
abs(secondreturnvalue(myfunc(x)))
not that i know of. subsref doesn't seem to work in this case, possibly because the second variable isn't even returned from the function.
since matlab 2009b it is possible to use the notation
[~, b] = function(x)
if you don't need the first argument, but this still uses a temporary variable for b.
Unless there is some pressing need to do this, I would probably advise against it. The clarity of your code will suffer. Storing the outputs in temporary variables and then passing these variables to another function will make your code cleaner, and the different ways you could do this are outlined here: How to elegantly ignore some return values of a MATLAB function?.
However, if you really want or need to do this, the only feasible way I can think of would be to create your own function secondreturnvalue. Here's a more general example called nth_output:
function value = nth_output(N,fcn,varargin)
[value{1:N}] = fcn(varargin{:});
value = value{N};
end
And you would call it by passing as inputs 1) the output argument number you want, 2) a function handle to myfunc, and 3) whatever input arguments you need to pass to myfunc:
abs(nth_output(2,#myfunc,x))

Anonymous functions calling functions with multiple output forms

I'm trying to define an anonymous function that calls a version of a function that returns multiple outputs.
For example, the function find has two possible output forms:
[row,col] = find(X);
and
[ind] = find(X);
Say I would like to choose the first form inside of an anonymous function.
I have tried
1)
get_columns = #(x) x(2);
and 2)
get_columns = #(x,y) y;
But when I call:
get_columns(find(x))
The first version of get_columns thinks I am calling find as [ind] = find(X) and not as [row,col] = find(X);, while the second one complains with "Not enough input arguments".
Is there a way to trigger a specific output form of a function inside an anonymous function?
Directly, no. Unfortunately, there are a number of features which are inaccessible via anonymous functions, and accessing multiple output arguments is one of them. (The other one I frequently find is that you cannot define an if statement inside an anonymous function. This appears to be a limitation of Matlab syntax more than anything else.
However, a pretty simple helper function can make this possible.
function varargout = get_outputs(fn, ixsOutputs)
output_cell = cell(1,max(ixsOutputs));
[output_cell{:}] = (fn());
varargout = output_cell(ixsOutputs);
This function takes a function handle plus an array of output indexes, and returns the indexed outputs.
If you create this file (hopefully better commented) and put it on your path, then you can access the second output of the find function as by defining the following function
find_2nd = #(x)get_outputs(#()find(x),2)
And now you can find the find the indexes of an array which equal 1 as
>> find_2nd([4 3 2 1]==1)
ans =
4
And now you should be able to access alternative output arguments at-will from within anonymous functions.
This get_outputs function above could be widely useful for brief anonymous functions. Very nice.
Also, regarding the comment that an "if" can't be used in MATLAB, this is only partially true. Identical behavior can easily be implemented anonymously. For instance, here's an anonymous if:
anonymous_if = #(varargin) varargin{2*find([varargin{1:2:end}], 1, 'first')}();
Use:
out = anonymous_if(condition1, action1, condition2, action2, ...);
The action corresponding to the first true condition is executed. For instance, this prints 'hello'.
anonymous_if(false, #() disp('hi'), ... % if false, print 'hi'
true, #() disp('hello')) % else if true, print 'hello'
Granted, it's a bit complicated at first sight, but I keep something like this on my path so I can use an "if" in an anonymous function. Much more complex anonymous functions can be built in this way.