I am new to Matlab and I have the following problem:
A function expects an input parameter of an array of function-handles
handleArray = #( param ) [ ...
#calcSumOfParam ; ... % and so on..
#calcSumOfParam ];
solution = calculateFunc( handleArray );
However, calcSumOfParam() actually needs more/additional input parameters (not only param) and is kind of heavy-structured (only an example here)
function [ sumOfParam ] = calcSumOfParam( param , maxIter , startIter )
sumOfParam = 0;
for iter = startIter : maxIter
sumOfParam = sumOfParam + param( iter );
end
end
Is there a way to do this?
I cannot use anonymous functions as I need to use loops and conditions. Also multiple functions won't work either, as I do not know the size of the handleArray and so the amount of functions (get it through user input).
Related
Lets say we have a custom extractor function
[features,featureMetrics] = exampleBagOfFeaturesExtractor(img,param1, param2)
I want to call bagOfFeatures function and pass custom extractor function:
extractorFcn = #exampleBagOfFeaturesExtractor;
bag = bagOfFeatures(imgSets,'CustomExtractor',extractorFcn)
In exampleBagOfFeaturesExtractor function I want to use different local descriptors extractor depending on param1.
How do I pass param1 to exampleBagOfFeaturesExtractor?
What is the best way to use different local descriptors in my custom extractor function?
Thank you for your help!
Edit
This is the custom extractor function I am currently using:
function [features,featureMetrics] = exampleBagOfFeaturesExtractor(img,param1,param2)
keypoint_detector = cv.FeatureDetector(param1);
descriptor_extractor = cv.DescriptorExtractor(param2);
kpts = keypoint_detector.detect(img);
[ features, kpts ] = descriptor_extractor.compute(img, kpts);
featureMetrics=ones(1,size(features,1))/size(features,1);
end
The expected kind of functions that the bagOfFeatures function requires can only be a single input, namely the input image. Therefore, if you want to create a custom feature extractor where you can vary the parameters, you will need to first create the parameters, then create an anonymous function that captures these parameters via lexical closure. This means that when you create the anonymous function, make sure the parameters are created so that when you reference them in your anonymous function, they capture the most up to date version of the parameters prior to creating the function.
Therefore, assuming param1 and param2 already exist in your workspace, create a function like so:
% Create param1 and param2 here
param1 = ...;
param2 = ...;
extractorFcn = #(img) exampleBagOfFeaturesExtractor(img, param1, param2);
This creates an anonymous function that takes in a single input - your image. param1 and param2 are thus captured in your function, so the state of the variables is recorded and are made available within the anonymous function. Also note that the function doesn't take in additional inputs, only the input image. You can then call bagOfFeatures as normal. However, should you want to change param1 or param2, not only will you have to change these parameters, but you must re-declare the anonymous function again so that the latest stage of the variables is recaptured.
As a quick example, suppose I've created an anonymous function like so:
x = 5;
y = #(t) t + x;
This function y takes the current state of x and adds it with a variable t. For now, this acts like how we expect it:
>> x = 5;
>> y = #(t) t + x;
>> y(6)
ans =
11
We put in the value 6 and we get 11. If we try and change x then call y, it will not change this in the function as it captured the state of the variable before you created the function:
>> x = 10;
>> y(6)
ans =
11
Therefore, if you want to change the parameters, you must also re-declare the function again before calling bagOfFeatures, so:
param1 = ...; % Change this to something new
param2 = ...; % Change this if you like as well
extractorFcn = #(img) exampleBagOfFeaturesExtractor(img, param1, param2);
In MATLAB terms, these variables persist in the anonymous function. You can read more about it here: https://www.mathworks.com/help/matlab/matlab_prog/anonymous-functions.html#f4-71621
I need to implement a function that does some image processing on a specific number of images (nFrames) that are located in a folder (folder1). The function would look something like:
function imgProc( nFrames,path )
Let's say I have several folders with different numbers of images in each one. What I need to have is optional input arguments, meaning that if the user wants, he can do the image processing for the first 10 images, for example, but if he does not specify the number, the function should perform the task on all the images. And the same for the folders, there should be a default folder in case the user does not specify from which folder he wants to take the images. It also could be interesting that the user could call the function with 0, 1 or 2 input arguments.
I have thought of using the exist function like this:
function imgProc( nFrames,path )
if exist( path,'var' ) == 0
path = 'img/record_space';
end
if exist( nFrames,'var' ) == 0
d = dir([ path,'\*.png' ]);
nFrames = length( d( not([ d.isdir ]) ) );
end
end
But if I call the function with no input arguments it gives an error saying there's not enough input arguments.
Is it possible to create a function that can have all of its arguments optional and moreover allow you to input 0, 1 or 2 according to your needs, taking into account that one is a number and the other one a string?
To fix the problem in your code:
function imgProc( nFrames,path )
if exist( 'path','var' ) == 0
path = 'img/record_space';
end
if exist( 'nFrames','var' ) == 0
d = dir([ path,'\*.png' ]);
nFrames = length( d( not([ d.isdir ]) ) );
end
end
exists expects the variable name, not the variable itself. You can pass a variable containing a string, but then it would check if that string exists:
x='y'
exist(x,'var') % checks if y exists
exist('x','var') %checks if x exists
What I recommend to have a flexible interface is using the inputParser
function imgProc( varargin )
p = inputParser;
addOptional(p,'frames',inf,#isnumeric);
addOptional(p,'path',pwd,#(x)exist(x,'dir'));
parse(p,varargin{:});
%lower frames if required to the maximum possible value
frames=min(p.Results.frames,numel(dir(fullfile(p.Results.path,'*.png'))));
%if frame was previously a number (not inf) and is lowered, print a warning.
if frames<p.Results.frames&&p.Results.frames~=inf
warning('parameter frames exceeded number of images present. Frames set to %d',frames);
end
disp(p.Results);
end
Possible ways to call the function:
>> imgProc
frames: Inf
path: 'D:\Documents\MATLAB'
>> imgProc('frames',1)
frames: 1
path: 'D:\Documents\MATLAB'
>> imgProc('path','foo')
frames: Inf
path: 'foo'
>> imgProc('path','bar','frames',9)
frames: 9
path: 'bar'
In newer versions on Matlab, you can also call the function using this syntax, e.g.:
imgProc()
imgProc( frames=1 )
imgProc( path="foo" )
imgProc( path="bar", frames=9 )
The result will be the same as Daniel's answer above, but it makes the function calling more intuitive (in my opinion).
As said in the title, I have a recursive function and I am trying to build a tree data structure out of it to save my results. Every node consists in just one single number. The problem is that when I input the tree to the next call of the function, it seems that only the value of the tree is passed along, not the actual tree. Does anyone know how to pass a reference to the tree instead?
Initial Call:
tree = struct('left', 'empty','right', 'empty','feature','empty');
decisiontree_train(AttributeSet, LabelSet, 50, tree, 'node');
Recursive Function:
function decisiontree_train( data, labels, before_split_purity_percentage, tree, branch )
% a1 is 0, a2 is 1
[ a1_split_data, a2_split_data, a1_split_labels, a2_split_labels, ...
split_feature ] = decisiontree_split( data, labels );
new_tree = struct('left', 'empty','right', 'empty','feature','empty');
if strcmp(branch, 'left')
tree.left = new_tree;
new_tree.feature = split_feature;
elseif strcmp(branch, 'right')
tree.right = new_tree;
new_tree.feature = split_feature;
elseif strcmp(branch, 'node')
tree.feature = split_feature;
new_tree = tree;
end
[ after_split_purity_percentage ] = decisiontree_classcount( a1_split_labels );
if after_split_purity_percentage < 100 && ...
after_split_purity_percentage > before_split_purity_percentage
decisiontree_train(a1_split_data, a1_split_labels, ...
after_split_purity_percentage, new_tree, 'left');
end
[ after_split_purity_percentage ] = decisiontree_classcount( a2_split_labels );
if after_split_purity_percentage < 100 && ...
after_split_purity_percentage > before_split_purity_percentage
decisiontree_train(a2_split_data, a2_split_labels, ...
after_split_purity_percentage, new_tree, 'right');
end
% add variable to workspace
% assignin('base', 'a1_split_data', a1_split_data)
end
Unless you use object oriented matlab, there is no pass by reference. While asking a different question, the answers somehow apply to your case as well. If you are using Matlab 2015b or newer, use Matlab OOP and implement your tree using a handle class. If performance isn't a big concern, do the same.
For the likely reason that both isn't true, you have to work around the issue. Matlab uses copy-on-wrote. Thus changing your functions to take your tree structure as a first input argument and returning the modified it isn't a bad idea. In typical cases only very little data is really copied.
Let's say I have func1, func2 and func3. Is there any way to call them with a known argument having defined their names? (Or their pointers? handlers?)
Something like:
toBeRunned = [ 'func1'; 'func2'; 'func3' ];
// .. foreach entry of toBeRunned call the function with VAR params ..
This is what function handles are meant for.
toBeRun = {#func1, #func2, #func3};
for ix = 1:length(toBeRun)
fnArguments = {1, 2, 3, 'four'};
fnTmp = toBeRun{ix};
fnTmp(fnArguments{:});
end
A little more explanation on what we're doing here:
toBeRun is a cell array of function handles, just an arbitrary list. For a function written as an M-file, added the # is all the is required to create a function handle.
In order to evaluate the function, it needs to be removed from the cell array (into fnTmp in this case.) This is a syntax limitation of Matlab. You can also use fneval, but I usually do it this way.
Any arguments can be added as needed, in the usual way (e.g. fnTmp(1,2,3,'four')). But if you need this much abstraction, you may also need to use an arbitrary number of input arguments. The fnArguments cell is a pretty flexible way of accomplishing this.
Function feval:
for i = 1 : size(toBeRunned, 1)
feval(toBeRunned(i, :), argument);
end
Another way to accomplish it...
toBeRunned = { 'func1', 'func2', 'func3' };
% arguments to be provided to functions
VAR = { arg1, arg2, arg3, arg4 };
% preallocate space for results
results = cell(1, 3);
for i = 1 : length(toBeRunned)
% KEY part ...
toRun = eval( [ '#' boBeRunned{i} ] );
results{i} = toRun( VAR{:} );
end
Explanation of the key part of the code:
[] concatenates strings,
eval evaluates string as Matlab code. In the first iteration of the loop, line with eval equals to:
toRun = #func1;
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')