Passing names of functions to another function with parameters as input in MATLAB
Show older comments
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: 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. And 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.
Answers (4)
You could use a cell of function handles:
run_experiment(Opts, Fcns)
for iFcn = 1:numel(Fcns)
Data = Fcns{iFcn}(Opts);
end
Then call this like:
run_experiment('dataset_1_options', {@train_model, @evaluate_model})
Note that this is not necessarily an efficient way to create a program, because you are building a kind of interpreter. Matlab itself is an interpreter already such that this programming method inserts an indriection. Creating a dedicated function might be much easier:
function run_experiment1(Opts)
Data = preprocess_data(Opts);
Data = initialise_model(Data, Opts);
Data = train_model(Daat, Opts);
end
And then create a function for each kind of experiments.
This is less flexible, but simple. Sometimes simple methods solve the problem with less effort.
3 Comments
Mert Turkol
on 10 May 2017
I already have the second functionality implemented in my existing code. However, what I am looking for is to provide flexibility in a sense that certain parts of code can be evaluated based on the functionality desired. This is part of a big scientific computing code, that's why I want to introduced segmented functionality within the code so that I can evoke them with specified functions related to them.
Stephen23
on 10 May 2017
@Mert Turkol: it sounds like you should really be writing object oriented code rather than using fucntions. OO would likely make this a simpler task.
Jan
on 10 May 2017
Another option is using flags:
flags = {'preprocess_data', 'initialise_model', 'train_model'};
run_experiment(Opts, flags)
function run_experiment(Opts, Flags)
for iFlag = 1:numel(Flags)
switch lower(Flags{iFlag})
case 'preprocess_data'
Data = preprocess_data(Data, Opt);
...
end
end
If you say you know how to retrieve the function names using strsplit, executing the functions given just the name should be a simple matter of using FEVAL. Your description doesn't make it clear how function arguments are passed, but as long as you already know how to parse that, too, feval should still be applicable.
I'm with Stephen. OOP would be the way to go. It's the way I've written my processing pipelines in the past. You can defined abstract base classes for similar processing function objects so you're guaranteed they have the same signature. Depending on your requirement, the chaining can be implemented as a simple array of object, i.e.:
pipeline = [functionobject1(opt1, opt2), functionobject2(opt1), functionobject3(opt1, opt2, opt3)];
pipeline.Procees(dataset1);
or something more complex if the pipeline has vastly different steps.
There are many benefit to that:
- Each step of the pipeline can have its own option stored as property of the function object, rather than as property of the pipeline or option arguments of the processing itself.
- All validation of the configuration of each processing step is only carried out once, at creation of the function object. You can then process as many data sets as you want with the same options without having to revalidate the optional parameters.
- Because the pipeline is just one variable, it's easy to save the pipeline, with its entire configuration to disk for reuse later.
- You can also save that pipeline variable together with the result of the processing, so in 6 months time when you're writing a paper/report and find an anomaly in the result, you can easily check what processing options you used. It also ensures traceability.
- Easy versioning. The version can just be stored as an immutable property of the function objects.
Well, apart from using Object Oriented code, the other obvious method would be to turn those strings into function handles using str2func. Then you can call the function very simply:
fun = str2func(str);
[out,...] = fun(inp,...);
It would even be possible to call them in a loop, as long as the number of input and output arguments is the same:
C = {'sin','acos','sqrt'};
data = pi/3;
for k = 1:numel(C)
fun = str2func(C{k});
data = fun(data);
end
gives
data = 0.72360
and checking:
>> sqrt(acos(sin(pi/3)))
ans = 0.72360
Categories
Find more on Entering Commands in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!