Creating a function handle to an overloaded `end` function - matlab

MATLAB allows overloading various operators for custom classes. One of the unlisted overloadable operators is end, as can be learned from \matlab\lang\end.m:
% END(A,K,N) is called for indexing expressions involving the object A
% when END is part of the K-th index out of N indices. For example,
% the expression A(end-1,:) calls A's END method with END(A,1,2).
An example of such a method is table.end (paste in the MATLAB command line and press "Open Selection" to go to its definition; it is defined in ...\matlab\datatypes\#tabular\end.m).
Unlike a normal method, one cannot simply write hEnd = #end, because this gives the error:
>> hEnd = #end;
hEnd = #end;
↑
Error: Illegal use of reserved keyword "end".
On the other hand, writing e = str2func('end'); works, but it links to the default end function (even when temporarily switching to the folder where the desired end.m is found).
Failed attempts include str2func('table>end');, str2func('table\end');, str2func('table.end'); and #(a,b,c)table.end(a,b,c);.
My question: How do I create a handle to the end function of a specific class?

Overloading — If the function you specify overloads a function in a class that is not a fundamental MATLAB class, the function is not associated with the function handle at the time it is constructed. Instead, MATLAB considers the input arguments and determines which implementation to call at the time of evaluation.
Function handles store their absolute path, so when you have a valid handle, you can invoke the function from any location. You do not have to specify the path to the function when creating the handle, only the function name.
so if your 'end' function is in matlab path , matlab consider it as a candidate for evaluation depending on the inputs,in your case if input object is of 'table' class type the feval(str2func('end'),i,j) evaluate the end function which is defined in the folder #table/end.m

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.

How do I get the value of a Simulink struct from the workspace within a MATLAB function?

I need to access the values of variables in MATLAB's workspace of type Simulink.parameter:
CAL_vars = dsdd('find','/path/CAL','ObjectKind','Variable','Property',{'name' 'Class' 'value' 'CAL'})
%gets ids of variables in data dictionary
i = 10
for i=1:length(CAL_vars)
var_name = dsdd('GetAttribute',CAL_vars(i),'name');
% gets names of variables in data dict
var_eval = eval(var_name); % this works in standalone script and it does exactly
% what I need, but once i put it in the function I need this for, it returns error
if (length(var_eval.Value) ==1)
if (var_eval.Value == true)
var_eval.Value = 1;
elseif (var_eval.Value == false)
var_eval.Value = 0;
else
end
end
% do something with the Value
if (errorCode ~= 0)
fprintf('\nSomething is wrong at %s\n', var_name)
end
end
The problem arises because the structs are of made by Simulink and give error, when I try to call eval(name_of_var): Undefined function 'eval' for input arguments of type 'Simulink.Parameter'.
Curiously, it seems to function properly in a stand-alone script but once I plug it into the larger function, it stops working and starts displaying error saying
Error using eval
Undefined function or variable 'name_of_var'.
The function is clearly in the workspace.
Curiously, it seems to function properly in a stand-alone script but
once I plug it into the larger function, it stops working
This is the expected behaviour. A function has its own workspace and can't directly access variables in the base workspace.
You could try using evalin instead of eval, and specify the base workspace:
evalin(ws, expression) executes expression, a character vector or
string scalar containing any valid MATLAB® expression using variables
in the workspace ws. ws can have a value of 'base' or 'caller' to
denote the MATLAB base workspace or the workspace of the caller
function.
In general though, there are lots of reasons for trying to avoid using eval if at all possible (see the MATLAB help for eval) and it would be best if you could find a different way of getting this data.

Matlab permutation

I have written a function to perform permutations of n obejects.
I have the variables a=[1],[2],[3];k=1 and n=4;a contains the objects which are 1,2 and 3 respectively.The following is the function code that i have written:
function [res]=perm(a,k,n,jj)
if k==n
res{jj}=a;
jj=jj+1;
else
for i=k:n
t=a{k};
a{k}=a{i};
a{i}=t;
perm(a,k+1,n,jj)
t=a{k};
a{k}=a{i};
a{i}=t;
end
end
end
However, when i call the function as:
jj=1;
[res]=perm(a,k,n,jj)
I am getting the following error displayed:
Error in ==> perm at 3
if k==n
??? Output argument "res" (and maybe others) not assigned during call to "J:\main
project\perm.m>perm".
Error in ==> mainp at 254
[res]=perm(a,k,n,jj)
The following is the code in the main program with regard to the permutation:
mr=4
for i=1:mr
a{i}=i;
end
n=mr;
%This assignment is for the ease to work with.
%just stored the indices till mr for the purpose of permutation
k=1;
%this is the k that the function perm has
jj=1;
[res]=perm(a,k,n,jj)
Can somebody please help me resolve this?Thanks in advance.
Your else block leaves res undefined.
I think you're assuming that res is a global variable and all invocations of perm will write into different parts of a single cell array. That isn't true. It is an output variable, local to the current call. There's no sharing during recursion, they all have independent cell arrays named res. The parameter jj is also not shared, so adding one is useless as well.
If you want to use this technique of building up the output, you'll need to make sure it is defined at a wider scope than the recursion. For example, use a local helper function:
function [res]=perm(a,k,n,jj)
res = {};
perm_impl(a,k);
function [] = perm_impl(a,k) // doesn't get its own local res, n, or jj
if k==n
res{jj}=a;
jj=jj+1;
else
for i=k:n
t=a{k};
a{k}=a{i};
a{i}=t;
perm_impl(a,k+1)
t=a{k};
a{k}=a{i};
a{i}=t;
end
end
end
end
Now all runs of perm_impl work on the same cell array res, because Matlab documentation says:
Variables within nested functions are accessible to more than just their immediate function. A variable, x, to which you assign a value or use within a nested function resides in the workspace of the outermost function that both contains the nested function and accesses x.
If you intentionally use a variable in this manner, it is not a problem. For examples, see the MATLAB Programming Demo on Nested Functions.
However, if you unintentionally use a variable in this manner, it can result in unexpected behavior. If the highlighting indicates that the scope of a variable spans multiple functions, and that was not your intent, consider:
Renaming the nested function variable so it does not match the outer function variable name.
Passing the variable into the function as an input argument instead of using the variable directly within the nested function
I can't tell whether a was supposed to be shared or not...

Declaring variables before declaring a function

Suppose I want to declare some variables then declare a function:
x = 2;
function y = function(x)
y = (x^2)+1;
end
y = function(x);
disp(y)
Matlab returns the error "Function keyword use is invalid here..."
Why can't I declare variables or write any text before declaring a function? Is there good reason or is it a quirk?
EDIT:
To clarify, I do know how to get around this problem (but thanks for the suggestions nonetheless) but I suppose I'm asking why the Matlab team made this decision. By making a function declaration the first line of a file, does it have implications for memory management, or something?
The REPL prompt of Scala can have a function defined after a variable. So this is a choice (a quirk if you want) from Matlab's inner internals.
If a function is defined in a file, there are two possibilities:
The main function of that file. Then the file must begin with the function declaration: in your example, function y = fun(x). I'm using fun as the function's name. I don't think function can be used as a function's name.
See here for more details.
A nested function. In this case, the function declaration and definition can be within another function of the preceding case.
See here for more details.
As you can see, in either case the file begins with a function declaration (namely that of the main function).
The function can also be defined as an anonymous function. Then no declaration is needed, and the function can be defined anywhere. But there's a restriction: the function can contain only a single statement (so it cannot define internal variables other than the output). Therefore this method can only be used for simple functions.
In your example, the function could be defined anonymously as fun = #(x) x^2+1.
See here for more details.
Others have given good info about nested functions and such.
But the reason for the error you get is that "function" is a reserved word in Matlab. You cannot have a function with this name.
function y = my_function(x)
y = (x^2)+1;
end
And stick it in another file called my_function.m

How to nest anonymous functions in Matlab?

I have a file funcs.m that stores anonymous functions. They must be usable by the files in the directory where it is. Currently, I use the anonymous functions so that I execute the file funcs.m in different files but I think this is a a wrong way of doing things. The other functions such as main.m and its nested function nest.m need to use the anonymous functions from funcs.m. I think paths won't solve this problem because the files are in the same folder. Basically I could solve this problem by copy-pasting the anonymous functions to every file but code-smell so:
Is there some way of reusing the funcs.m having the anon functions in Matlab?
Example
main.m
function main
funcs; % loads the anonymous functions
nest(par1,...,parN)
end
nest.m
function nest(par1,...,parN)
funcs; %ERRR: This fires err, why? Look: this was sourced already in main.m!
function neededOnlyHere(par100)
bq(q,A) %This needs the functions of the funcs
end
neededOnlyHere(somePar) %ERR to use the anon funcs from funcs
end
Functions main.m and nest.m use this function funcs.m having the anonymous funcs
bq=#(q,A) q*A; %Bolded q
I=#(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0);
AiNotj=zeros(1,Ncut);
...
ERROR
Attempt to add "bq" to a static workspace.
See MATLAB Programming, Restrictions on
Assigning to Variables for details.
Error in funcs (line 10)
bq=#(q,A) q*A;
%Bolded q
Why it's breaking
You get the error when calling it in nest.m because having a nested function makes its enclosing function's workspace a "static workspace"; that is, variable names cannot be added via eval(), assignin(), or other "dynamic" techniques; only variables that are explicitly assigned in that function's text are allowed. Evaluating a script to define local variables - which is what you're doing when calling funcs.m - is "dynamic", so prohibited in functions with nested functions. It works in main.m because main has no nested functions and is thus a "dynamic" workspace.
There are a couple ways you could change it to work with static workspaces and nested functions. The first thing to ask is whether you really need to make them anonymous functions?
Using package functions instead
If you don't need them to be anonymous functions per se, just break them out and put each one as a regular function in its own .m file; e.g. bg.m, I.m, AiNotj.m, and so on. Then they're all available to all other functions in that directory.
If that turns in to a mess of files, or if you want to scope them and maybe make them available only to the selected functions that really need them (that is, the functions currently calling funcs()), then you can stick them in a package. Create a subdirectory called +myfuncs and move all the little function files in there; e.g. +myfuncs/bq.m, +myfuncs/I.m, +myfuncs/AiNotj.m. (The + prefix tells Matlab the directory is a package.) Then you can pull all of them in to your function scope by doing import myfuncs.* as a direct replacement for where you're currently calling funcs().
function nest(par1,...,parN)
import myfuncs.*;
function neededOnlyHere(par100)
bq(q,A) % This will work, resolving to myfuncs.bq
end
You can do the import myfuncs.* from the command line to make them available interactively, too.
This is probably how Matlab itself wants you to organize clusters of related functions like this, and would be my first approach. It's the least "smelly" IMHO. If you really wanted to be able to edit them all in a single file like funcs.m for convenience, you could write a little code munger in Perl or whatever that parsed funcs.m and output them all as equivalent individual functions as a preprocessing step. (I think it's a bit of a bummer that you can't define multiple top-level functions in an M-file like this, but oh well.)
If you really need to work with anonymous functions, there are some workarounds.
Passing functions in a struct
You can change your funcs() function to actually return a struct of all those anonymous functions, using field names instead of local variable names.
function out = funcs
out.bq=#(q,A) q*A; %Bolded q
out.I=#(ii,jj,A) find(A(ii,:)==1 & A(jj,:)==0);
out.AiNotj=zeros(1,Ncut);
For this, you'd have to prefix all the function references with the struct name you're holding them in. Don't know how big a deal this is for you.
function nest(par1,...,parN)
fs = funcs;
function neededOnlyHere(par100)
fs.bq(q,A) %This needs the functions of the funcs
end
Preallocating variables
To get funcs() to work as-is, you can statically pre-allocate variables with all the function names you're going to use, so the Matlab parser recognizes them as statically assigned variables. Then when you call funcs(), it will re-assign the values of the existing variables, which is permissible in dynamic workspaces.
function nest(par1,...,parN)
[bq, I, AiNotj] = deal(); % Preallocate all names from funcs
funcs;
function neededOnlyHere(par100)
bq(q,A) %This needs the functions of the funcs
end
This would be a bit of a pain, because you'd have to re-edit every file that uses funcs whenever a new function name is added. You could at least write a little perl script to auto-generate that line of code by parsing funcs.m and outputting a "[bg, I, AiNotj,...] = deal();" with all the functions it finds, and you can just copy that in to your code.
Another way to do this would be to have funcs actually return all the functions in its output list. This would have the benefit of continuing to work even as you add new functions to funcs.m, as long as you don't remove or change the order of your existing anonymous functions.
function [bg,I,AiNotj] = funcs()
bg = ...
I = ...
% And then in the calling functions:
[bg,I,AiNotj] = funcs(); % which you can copy and paste from funcs.m's header
There are many ways of passing anonymous functions:
1) Pass the function itself:
function main
f = #(t) t^2 - 3;
param = randn(12,1);
g = test22(param,f);
disp (g)
end
function g = test22(param,f)
g = f(param(2));
disp(param(2))
end
2) Use globals (which usually should be avoided in complex code)
function main
global f
f = #(t) t^2 - 3;
param = randn(12,1);
g = test22(param);
disp (g)
end
function g = test22(param)
global f
g = f(param(2));
disp(param(2))
end