Interface for Matlab
The following section contains the documentation for using the Python interface that allows to set up, run studies and analyze their results.
Overview of Matlab classes
The interface consists of the following Python classes
Class |
Purpose |
---|---|
Class for for starting and stopping the optimization server. |
|
Class for connecting to server, creating studies, and creating benchmarks. |
|
Class for configuring, running and analyzing results of a study |
|
Container for observations to be sent to the server. |
|
Suggestion retrieved by a study to be evaluated. |
|
Interface to driver-specific methods. |
|
Class for benchmarking different studies against each other |
Documentation
Benchmark
- class Benchmark(host, verbose, id, num_average)
This class provides methods for benchmarking different optimization studies against each other Example:
benchmark = Benchmark('num_average',6); benchmark.add_study(study1); benchmark.add_study(study2); studies = benchmark.studies(); for i_study = 1:length(studies) study = studies{i_study}; while(not(study.is_done)) suggestion = study.get_suggestion(); observation = evaluate(suggestion.sample); study.add_observation(observation,suggestion.id); end benchmark.add_study_results(study); end data = benchmark.get_data('x_type','num_evaluations','y_type','objective',... 'average_type','mean'); plots = []; for ii=1:length(data.names) X = data.X(ii,:); Y = data.Y(ii,:); plots(end+1) = plot(X,Y,'LineWidth',1.5); end legend(plots, data.names{:});
add_study
add_study_results
get_data
- Benchmark.get_data(varargin)
Get benchmark data. Example:
data = benchmark.get_data('x_type','num_evaluations','y_type','objective',... 'average_type','mean'); plots = []; for ii=1:length(data.names) X = data.X(ii,:); Y = data.Y(ii,:); plots(end+1) = plot(X,Y,'LineWidth',1.5); end legend(plots, data.names{:});
- Parameters:
x_type (
str
) – Data on x-axis. Can be either ‘num_evaluations’ or ‘time’. The time data is given in units of seconds. Options are ‘num_evaluations’, ‘time’. Default is ‘num_evaluations’.y_type (
str
) – Data type on y-axis. Options are ‘objective’, ‘distance’, (i.e. accumulated minimum distance off all samples to overall minimum), or ‘min_distance’ (i.e. distance of current minimum to overall minimum). Default is ‘objective’.average_type (
str
) – Type of averaging over study runs. Options are ‘mean’ w.r.t. x-axis data or ‘median’ w.r.t. y-axis data. Default is ‘mean’.invert (
logical
) – If true, the objective is multiplied by -1. (Parameter not available for distance average types). Defaults to false.log_scale (
logical
) – If true, the output of Y and stdev are determined as mean and standard deviations of the natural logarithm of the considered y_type. Defaults to false.minimum (
array
) – Vector with minimum position. (Only available for distance average types)scales (
array
) – Vector with positive weights for scaling distance in different directions. (Only available for distance average types)norm (
int
) – Order of distance norm as defined in numpy.linalg.norm. (Only available for distance average types) Defaults to 2.num_samples (
int
) – Number of samples on y-axis. (Only available for median average type or time on x-axis). Defaults to 100.
run
- Benchmark.run()
Run the benchmark after the evaluator has been set (see
Benchmark.set_evaluator()
). Example:benchmark.set_evaluator(evaluate); benchmark.run()
set_evaluator
- Benchmark.set_evaluator(evaluator)
Set the function that maps design parameters to an
Observation
. Example:function observation = evaluate(study, sample) observation = study.new_observation(); observation.add(sample.x1^2 + sample.x2^2); benchmark.set_evaluator(evaluate); benchmark.run();Note
Call this function only after all studies have been added to the benchmark.
- Parameters:
evaluator (
function_handle
) – Function handle for a function of the variable parameters that returns a correspondingObservation
object. The function must accept a"study"
argument as well as a struct argument which maps each design parameter and fixed environment parameter to its value.
studies
- Benchmark.studies()
Returns: cell: A list of studies to be run for the benchmark.
Client
- class Client(host, verbose, check)
This class provides methods for creating new optimization studies. Example:
client = Client("http://localhost:4554") design_space = {... struct('name', 'x1', 'type', 'continuous', 'domain', [-1.5, 1.5]), ... struct('name', 'x2', 'type', 'continuous', 'domain', [-1.5, 1.5]) ... }; study = client.create_study('design_space', design_space, 'name', 'basic example');
- Parameters:
host (
string
) – The host name under which the optimization server can be contacted. For example,'http://localhost:4554'
verbose (
logical
) – If true, messages from the optimization server are printed out.check (
logical
) – If true, check if the optimization server can be contacted via the given host name.
check_server
- Client.check_server()
Checks if the optimization server is running. Example:
>> client.check_server() Polling server at http://localhost:4554 Optimization server is running
create_benchmark
- Client.create_benchmark(varargin)
Creates a new
Benchmark
object for benchmarking different optimization studies against each other. Example:benchmark = client.create_benchmark('num_average', 6);
- Parameters:
benchmark_id (
string
) – A unique identifier of the benchmark.num_average (
int
) – Number of study runs to determine average study performance. Default is 6.remove_completed_studies (
logical
) – If true, studies that are completed (i.e. some stopping criterion was met) are removed from the server as long as no other client holds a handle to the study. Default is false.
create_study
- Client.create_study(varargin)
Creates a new
Study
instance. Example:study = client.create_study( ... 'design_space', design_space, ... 'name', 'example', ... 'study_id', 'example_01' ... );
- Parameters:
design_space (
cell
) –List of domain definitions for each parameter. A design space definition consists of a list of dictionary with the entries
- name:
Name of the parameter. E.g.
'x1'
. The name should contain no spaces and must not be equal to function names or mathematical constants like'sin'
,'cos'
,'exp'
,'pi'
etc.- type:
Type of the parameter. Either
'continuous'
,'discrete'
, or'categorial'
.- domain:
The domain of the parameter. For continuous parameters this is a tuple (min, max). For discrete parameters this is a list of values, e.g.
[1.0,2.5,3.0]
. For categorial inputs it is a list of strings, e.g.["cat1","cat2","cat3"]
. Note, that categorial values are internally mapped to integer representations, which are allowed to have a correlation. The categorial values should therefore be ordered according to their similarity. For fixed parameters the domain is a single parameter value.Example:
design_space = { ... struct('name', 'x1', 'type', 'continuous', 'domain', [-2.0,2.0]), ... struct('name', 'x2', 'type', 'continuous', 'domain', [-2.0,2.0]), ... struct('name', 'x3', 'type', 'discrete', 'domain', [-1.0,0.0,1.0]), ... struct('name', 'x4', 'type', 'categorial', 'domain', ["a", "b"]) ... };If not specified, the design space configuration from the study history is used. If no historic information exists, an error is raised.
environment (
cell
) –Environment parameters are those which influence the behavior of the system, but are not design parameters. Examples are uncontrollable environment parameters (e.g. temperature, time) or parameters that are scanned in each evaluation (e.g. wavelength, angle) for each run of the system can be described by environment parameters. Alternatively, scans can be described by surrogates that are trained on multiple inputs (one for each scan value). The environment definition consists of a list of dictionary with the entries:
- name:
Name of the parameter. E.g.
'x1'
. The name should contain no spaces and must not be equal to function names or mathematical constants like'sin'
,'cos'
,'exp'
,'pi'
etc.- type:
Type of the parameter. Either
'variable'
or'fixed'
. Fixed parameters can be used in the constraint functions or other expressions.- domain:
The domain of the parameter. For fixed parameters, this is a single value, for variable parameters this can be a tuple (min, max). If no bounds are specified for variable parameters, the environment is considered to be unconstrained. In this case the scale has to be set.
- scale:
The scale at which environment parameter changes affect the system. If the environment parameter describes unknown drifts and aging effects, the length scale is equal to the timescale at which the system behavior changes due to drifts or aging.
Example:
environment = { ... struct('name', 'wavelength', 'type', 'continuous', 'domain', [300, 600]), ... struct('name', 'time', 'type', 'continuous', 'scale', 0.1), ... struct('name', 'radius', 'type', 'fixed', 'domain', 1.5) ... };If not specified, the environment configuration from the study history is used. If no historic information exists, the environment is assumed to be empty (
environment = {}
).constraints (
cell
) –List of constraints on the design space. Each list element is a dictionary with the entries
- name:
Name of the constraint.
- constraint:
A string defining an inequality constraint in the for a <= b or a >= b. The following operations and functions may be for example used: +,-,*,/,^,sqrt,sin,cos,tan,exp,log,log10,abs,round,sign,trunc. E.g.
'x1^2 + x2^2 <= sin(x1+x2)'
. For a more complete list of supported functions, see the expression variable reference.Example:
constraints = { ... struct('name', 'circle', 'expression', 'x1^2 + x2^2 <= radius^2'), ... struct('name', 'triangle', 'expression', 'x1 >= x2') ... };If not specified, the constraints configuration from the study history is used. If no historic information exists, the list of constraints is assumed to be empty (
constraints = {}
).study_id (
string
) – A unique identifier of the study. All relevant information on the study are saved in a file named study_id+’.jcmo’ If the study already exists, thedesign_space
,environment
, andconstraints
do not need to be provided. If not set, the study_id is set to a random unique string.name (
string
) – The name of the study that will be shown in the dashboard.save_dir (
string
) – The path to a directory, where the study file (jcmo-file) is saved. Default is a directory in the system’s temporary directory.driver (
string
) – Driver used for the study. Default is ‘ActiveLearning’. For a list of drivers, see the driver reference.output_precision (
double
) –Precision level for output of parameters.
Note
Rounding the output can potentially lead to a slight breaking of constraints.
dashboard (
logical
) – If true, a dashboard will be served for the study. Default is true.open_browser (
logical
) – If true, a browser window with the dashboard is started. Default is true.
shutdown_server
- Client.shutdown_server(force)
Shuts down the optimization server. Example:
client.shutdown_server(true)
- Parameters:
force (
logical
) – If true, the optimization server is closed even if a study is not yet finished. Defaults to false.
Driver
- class Driver(host, verbose, study_id)
This class provides methods for retrieving and setting driver-specific information of the study. Depending on the chosen driver of
Client.create_study()
the driver provides specific methods. More details for each driver are available in the driver reference. Example:driver = study.driver; min_objective_values = driver.historic_parameter_values( ... "acquisition_function.min_objective");
The constructor should not be used directly since it does not create a driver on the server side. Instead, one should use
Study.driver
.
describe
- Driver.describe()
Get description of all modules and their parameters that are used by the driver. Example:
description = driver.describe(); fprintf(description.members.surrogates{1});
- Returns:
- A nested struct with description of submodules consisting
of a name and a descriptive text. If the entry describes a module, it has an additional
"members"
entry with struct describing submodules and parameters.- Return type:
struct
get_state
- Driver.get_state(path)
Get state of the driver. Example:
best_sample = driver.get_state("best_sample");
- Parameters:
path (
str
) – A dot-separated path to a submodule or parameter. If none, the full state is returned.- Returns:
If path is None, a struct with information of driver state.
- Return type:
struct
Note
A description of the meaning of each entry in the state can be retrieved by
describe()
.
historic_parameter_values
- Driver.historic_parameter_values(path)
Get the values of an internal parameter for each iteration of the study. Example:
min_objective_values = driver.historic_parameter_values(... "acquisition_function.min_objective");
- Parameters:
path (
str
) – A dot-separated path to the parameter.- Returns:
Array of parameter values
- Return type:
array
Note
A description of the meaning of each parameter can be retrieved by
describe()
.
Observation
- class Observation
This class provides a container to collect data to be sent to the optimizer. This includes scalar or vectorial inputs for the objective or surrogate models of an active learning-based driver.
add
- Observation.add(value, varargin)
Add data to observation. Example:
obs.add(val); obs.add(dval_dx1, 'derivative', 'x1'); obs.add(dval_dx2, 'derivative', 'x2');
- Parameters:
value (
double
) – Numerical value or list of values.derivative (
str
) – If the values are derivatives w.r.t. a design or environment parameter, this should be the name of the parameter.uncertainty (
double
) – The uncertainty of the provided values, i.e. the estimated standard deviation of multiple observations for same parameter.model_name (
str
) – Name of the surrogate model that is trained on the data. Can be omitted for drivers that do not support multiple models.environment_value (
cell
) – Cell array of environment value for all entries of the environment of the study. Optionally, entries for different environment values can be added consecutively, such that also scans of environment values can be collected into one observation.
Server
- class Server(varargin)
This class provides methods for starting and stopping a self-hosted optimization server on the local computer. Example:
server = Server(); client = Client(server.host); study = client.create_study(...);
- Parameters:
jcm_optimizer_path (
str
) – The path of the JCMoptimizer installation. If not specified, is is assumed that the Matlab file is that of the JCMoptimizer installation.port (
int
) – The port that the optimization server is listening to. If not specified, the port is chosen automatically.persistent (
logical
) –If true, the server continues to run even after the Python script has finished. To shutdown a local server later on, one can reconnect to it:
client = Client(host="http://localhost:4554"); client.shutdown_server();
- host
The host name of the server.
- Type:
str
- pid
The process id of the server.
- Type:
str
- port
The port that the server is listening on.
- Type:
str
shutdown
- Server.shutdown(force)
Shuts down the optimization server. Example:
server.shutdown(true);
- Parameters:
force (
logical
) – If true, the optimization server is closed even if a study is not yet finished. Defaults to false.
Study
- class Study(host, verbose, id, driver_name)
This class provides methods for controlling a numerical optimization study. Example:
study.configure('max_iter', 80); function observation = evaluate(study, sample) observation = study.new_observation(); observation.add(sample.x1^2 + sample.x2^2); %Start the optimization loop study.set_evaluator(@evaluate) study.run() %Alternatively, one can explicitly define an optimization loop while(not(study.is_done)) sug = study.get_suggestion(); obs = evaluate(study, sug.sample); study.add_observation(obs, sug.id); end
add_many
- Study.add_many(observations, design_values, varargin)
Adds many observations to the study. Example:
study.add_many(observations, design_values, ... 'acquisition_times', acquisition_times);
- Parameters:
observations (
cell
) – List ofObservation
objects for each sample (seenew_observation()
)design_values (
cell
) – List of design values. E.g.{{0.1, 1.0, 'cat1'}; {0.2, 2.0, 'cat2'}}
environment_values (
cell
) – Optional list of environment values. If not specified, the last known environment values are taken. E.g.{{1.0, 2.0}; {1.1, 2.3}}
acquisition_times (
cell
) – Optional list of times required to acquire each observation. E.g.{0.11, 0.12}
check (
logical
) – If true, the validity of the observation is checkedWarning
The purpose of this function is to speed up the process of adding many observations to the study. To this end, the intermediate driver states are not computed. This means that all driver-specific historic data (any path of
historic_parameter_values()
starting with driver…) is incorrect. The same holds for most of the data shown on the dashboard. To avoid this, one has to add the observations one by one usingadd_observation()
.
add_observation
- Study.add_observation(observation, suggestion_id, varargin)
Adds an observation to the study. Example:
% Add an observation for a given suggestion study.add_observation(observation, suggestion.id); % Add an observation for a given design value study.add_observation(observation, NaN, 'design_value', {1.0, 2.0});
- Parameters:
observation (
Observation
) –Observation
object with added values (seenew_observation()
)suggestion_id (
int
) – Id of the corresponding suggestion if it exists, otherwiseNaN
.design_value (
cell
) – If the observation does not belong to an open suggestion, the corresponding design value must be provided as a list of floats for continuous and discrete parameters or string for categorial parameters. E.g.{0.1, 2.0, 'cat1'}
.environment_value (
cell
) – If an environment parameters are specified, this specifies the value of variable environment parameters as a list of floats that is valid for all values added to the observation. E.g.{1.0, 2.0}
. Alternatively, one can also set different environment values for each entry of the observation (seeadd()
).acquisition_time (
double
) – If the observation does not belong to an open suggestion, it is possible to specify the time it took to retrieve the observation (e.g. the computation time). This information can be used to adapt the effort of computing the next suggestions.check (
logical
) – If true, the validity of the observation is checked
add_observation_data
- Study.add_observation_data(data)
Add data from another study to the study. Example:
obs_data = study.get_observation_data(); other_study.add_observation_data(obs_data);
- Parameters:
data (
struct
) – Struct with observation data. Seeget_observation_data()
for the details.
clear_all_suggestions
- Study.clear_all_suggestions()
Clear all open suggestions. Example:
study.clear_all_suggestions();Note
The study only creates
num_parallel
suggestions (seeconfigure()
) until it waits for an observation to be added (seeadd_observation()
) or a suggestion to be cleared.
clear_suggestion
- Study.clear_suggestion(sug_id, msg)
If the evaluation for a certain suggestion fails, the suggestion can be cleared from the study. Example:
study.clear_suggestion(suggestion.id, 'Computation failed');Note
The study only creates
num_parallel
suggestions (seeconfigure()
) until it waits for an observation to be added (seeadd_observation()
) or a suggestion to be cleared.
- Parameters:
suggestion_id (
int
) – Id of the suggestion to be cleared.message (
str
) – An optional message that is printed out.
configuration
- Study.configuration()
Return the current configuration for the driver. Example:
config = study.configuration(); study2.configure(config{:});
- Returns:
Nested struct with configuration.
- Return type:
struct
configure
- Study.configure(varargin)
Configures the study for its run. Example:
study.configure('max_iter', 100);
- Parameters:
max_iter (
int
) – Maximum number of evaluations of the evaluator 2 function (default:inf
).max_time (
double
) – Maximum optimization time in seconds (default:inf
).num_parallel (
int
) – Number of parallel observations of the evaluator function (default:1
).Note
The full list of parameters depends on the chosen driver. For a parameter description, see the corresponding driver in the driver reference.
describe
- Study.describe()
Get description of all modules and their parameters that are used by the study. Example:
description = study.describe(); fprintf(description.observation.acquisition_time); fprintf(description.driver.members.surrogates{1});
- Returns:
A nested struct with the root field names:
- driver:
Nested struct with description of submodules consisting of a name and a descriptive text. If the entry describes a module, it has an additional
"members"
entry with structs describing submodules and parameters.- observation:
Struct with a description of the parameters of an observation.
- suggestion:
Struct with a description of the parameters of a suggestion of the driver.
- Return type:
struct
get_observation_data
- Study.get_observation_data()
Get table with data of the observations. This can be used to copy the data manually to another study. Example:
obs_data = study.get_observation_data(); other_study.add_observation_data(obs_data);
- Returns:
- Struct where each entry holds an equally long cell array of observation data.
The field names of the struct are:
- value:
Observed value of black-box function
- derivative:
Name of derivative parameter or None for non-derivative observation
- uncertainty:
Uncertainty of observed value or None if no uncertainty
- model_name:
Name of the surrogate model that is trained on the data or None
- design_value:
Value of design parameters
- environment_value:
Value of environment parameters or None if no environment is specified
- Return type:
struct
get_state
- Study.get_state(path)
Get state of the study. Example:
acquisition_time = study.get_state('observation.acquisition_time');
- Parameters:
path (
str
) – A dot-separated path to a submodule or parameter. If none, the full state is returned.- Returns:
- If path is None, a dictionary with the following entries
is returned:
- driver:
Dictionary with information of driver state.
- observation:
Dictionary with information of the latest observation.
- suggestion:
Dictionary with information about the suggestion that corresponds to the last observation
- Return type:
struct
Note
A description of the meaning of each entry in the state can be retrieved by
describe()
.
get_suggestion
- Study.get_suggestion(environment_value)
Get a new suggestion to be evaluated by the user. Example:
sug = study.get_suggestion(); val = objective(sug.sample.x1, sug.sample.x2); obs = study.new_observation(); obs = obs.add(val); study.add_observation(obs, sug.id);
- Parameters:
environment_value (
array
) – If an environment is specified, this optional argument specifies the list of variable environment parameter values, for which a suggestion should be computed. E.g.[0.1, 1.2]
. If an environment exists and no values are specified, the last known environment values are used.Warning
The function has to wait until the number of open suggestions is smaller than
num_parallel
before receiving a new suggestion. This can cause a deadlock if no observation is added by an independent thread.
historic_parameter_values
- Study.historic_parameter_values(path)
Get the values of an internal parameter for each iteration of the study. Example:
acquisition_times = study.historic_parameter_values(... 'observation.acquisition_time');
- Parameters:
path (
str
) – A dot-separated path to the parameter.Note
A description of the meaning of each parameter can be retrieved by
describe()
.
is_done
- Study.is_done()
Checks if the study has finished. Example:
if study.is_done(): break; end;
- Returns:
True if some stopping criterion set by
configure()
was met.- Return type:
logical
Note
Before returning true, the function call waits until all open suggestions have been added to the study.
new_observation
- Study.new_observation()
Create a new
Observation
object that allows to add data viaadd()
. Example:observation = study.new_observation(); observation.add(1.2); observation.add(0.1, 'derivative', 'x1')
run
- Study.run()
Run the acquisition loop after the evaluator has been set (see
set_evaluator()
). The acquisition loop stops after a stopping criterion has been met (seeconfigure()
). Example:study.run();Warning
The automatic study run is only supported for
num_parallel = 1
. For parallel evaluations of the evaluator, a custom acquisition loop has to be implemented.
set_evaluator
- Study.set_evaluator(evaluator)
Set the function that maps design parameters to an
Observation
. Example:function observation = evaluate(study, sample) observation = study.new_observation(); observation.add(sample.x1^2 + sample.x2^2); study.set_evaluator(@evaluate)
- Parameters:
evaluator (
function_handle
) – Function handle for a function of the variable parameters that returns a correspondingObservation
object. The function must accept a"study"
argument as well as a struct argument which maps each design parameter and fixed environment parameter to its value.
start_clock
- Study.start_clock()
The optimization stops after the time
max_time
(seeconfigure()
). This function resets the clock to zero. Example:study.start_clock();Note
The clock is also set to zero by calling
configure()
.
open_jobs
- Study.open_jobs(job_ids, suggestion)
Collects all ids of open jobs belonging to a suggestion. Example:
study.open_jobs(job_ids, suggestion);
- Parameters:
job_ids (
array
) – List of job ids as returned from jcmwave_solve in daemon mode.suggestion (
Suggestion
) – ASuggestion
object.
gather_results
- Study.gather_results()
Waits for open jobs to finish until all the jobs from one of the open suggestion are completed. Example:
[sug_results, sug_id] = study.gather_results(); val = objective(sug_results); obs = study.new_observation(); obs.add(val); study.add_observation(obs, sug_id);
- Returns:
Cell array of results from the corresponding jobs. sug_id (int): Id of the corresponding suggestion. sug_logs (cell): Cell array of logging messages from the corresponding jobs
- Return type:
sug_results (cell)
Suggestion
- class Suggestion(id_, sample_)
This class provides the sample to be evaluated and the id which is required to identify results for this suggestion. Example:
sug = study.get_suggestion(); val = objective(sug.sample.x1, sug.sample.x2); obs = study.new_observation(); obs.add(val); study.add_observation(obs, sug.id);
The constructor should not be used directly. Instead, one creates suggestions using
Study.get_suggestion()
.- id
The id of the suggestion.
- Type:
int
- sample
Struct which maps names of design parameters to their values for which an observation is suggested.
- Type:
struct