Sensor Placement Routines#
A unified interface for OED for sensor placement applications is provided by the
module pyoed.oed.sensor_placement.sensor_placement_bayesian_oed.
Sensor placement OED problems are specialized to the case of finding
optimal observation configurations.
The main speciality of this class is that it define the effect of the experimental
design
as:
update the design of the observation operator (binary)
update the design of the observation error model (binary or relaxed).
Thus, one needs to choose the appropriate noise and observation models to suite the desired OED formulation. Solving an OED problem (sensor placement or not) requires choosing an optimizer. Thus, in the configurations an optimizer is set, and one can register desire optimizer which itself defines whether to solve binary or relaxed OED optimization problem.
OED for Sensor Plcement#
Approaches for solving the sensor placement OED problem for Bayesian inversion. Implementations provided here are general enough to be adopted for more general formulations, and documentations will be updated accordingly.
- class SensorPlacementBayesianInversionOEDConfigs(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', name=None, design=None, optimizer=<class 'pyoed.optimization.binary_optimization.stochastic_binary_optimization.BinaryReinforceOptimizer'>, optimizer_configs=None, criterion='Bayesian A-opt', inverse_problem=None, problem_is_linear=None, penalty_function=None, penalty_function_gradient=None, penalty_weight=0.0, random_seed=None)[source]#
Bases:
SensorPlacementInversionOEDConfigs
Configurations class for the
SensorPlacementBayesianInversionOED
class. This class inherits functionality fromSensorPlacementInversionOEDConfigs
and only adds the class-level variables below which can be updated as needed:- Parameters:
verbose (bool) – a boolean flag to control verbosity of the object.
debug (bool) – a boolean flag that enables adding extra functionlity in a debug mode
output_dir (str | Path) – the base directory where the output files will be saved.
name (str | None) – name of the OED approach/method.
inverse_problem (InverseProblem | None) –
an instance of an inverse problem
InverseProblem
. This can be a filter or a smoother object with access to underlying properties/methods/attributes of the inverse problems:prior
posterior
solve_inverse_problem()
observation_operator
observation_error_model
problem_is_linear (bool | None) –
a flag that defines how to regard the inverse problem, and consequently the OED problem. The following values are accepted:
If not set (None is passed), it will be detected by testing the linearity of the inverse problem upon instantiation.
If set to True, the underlying forward problem (both simulation model and observation operator) are linear. In this case, the posterior is Gaussian, and the posterior uncertainties (covariances) are independent from the data. Thus, the inverse problem is solved once to find the MAP point (posterior mean/mode), and the posterior covariance is defined/constructed. Note that finding the MAP point is not necessary since posterior covariances are independent from it.
If ‘False’, either the simulation model, the observation operator or both are nonlinear; In this case, the posterior is non-Gaussian, and the posterior uncertainties (covariances) are dependent on the data (through the MAP estimate). To deal with this situation, we follow one of two approaches:
The inverse problem is solved to find the MAP point (posterior mean/mode), approximate the posterior covariance (assuming a Gaussian) around the MAP, find an optimal design, and repeat.
Use KL-divergence between prior and posterior using MC estimate of KL.
criterion (None | str | Criterion) –
The optimality criterion to be optimized when solving the OED problem. This overrides the criterion in the base OED class with additional type. Specifically, this can be:
None; in this case, no criterion will be associated with the inversion OED instance (the object) upon instantiation. Thus, OED criterion association is lazy, and the user is allowed to assign the criterion after creating the inversion OED object by calling
register_optimality_criterion()
.an instance of
Criterion
which provides access to an evaluate method which evaluates the value of the optimality criterion.a string holding the name of the optimality criterion (if widely popular and implemented by PyOED). For more about passing string representation of the criterion, check the documentation of
register_optimality_criterion()
penalty_function (None | Callable) – function to evaluate the regularization/sparsification penalty (soft constraint) in the popular regularized OED optimization formulation.
penalty_function_gradient (None | Callable) – gradient/derivative of the penalty_function with respect to the design. For example, this is used for the relaxation approach where a binary design is allowed to take values in the continuous interval
[0, 1]
.penalty_weight (None | float) –
scalar penalty/regularization parameter multiplied by the penalty_function in the objective function.
Note
The OED optimization objective function is defined as the sum of optimality criterion plus a regularization term. The regularization term is the product of a penalty function with a pnalty weight.
optimizer (str | Optimizer | Type[Optimizer]) –
the optimization routine (optimizer) to register. This can be one of the following:
An optimizer instance (object that inherits :py:class`Optimizer`). In this case, the optimizer is registered as is and is updated with the passed configurations if available.
The class (subclass of
Optimizer
) to be used to instantiate the optimizer. To see available built-in optimization routines, see/callshow_supported_optimizers()
.The name of the optimizer (str). This has to match the name of one of the available optimization routine. To see available built-in optimization routines, see/call
show_supported_optimizers()
.
optimizer_configs (None | dict | OptimizerConfigs | Type[OptimizerConfigs]) –
the configurations of the optimization routine. This can be one of the following:
None, in this case configurations are discarded, and whatever default configurations of the selected/passed optimizer are employed.
A dict holding full/partial configurations of the selected optimizer. These are either used to instantiate or update the optimizer configurations based on the type of the passed optimizer.
A class providing implementations of the configurations (this must be a subclass of
OptimizerConfigs
.An instance of a subclass of
OptimizerConfigs
which is to set/udpate optimizer configurations.
random_seed (int | None) – random seed to be used to globally set seeds of the underlying random number generators. This affects both the optimizer and the uncertain parameter sampler (if accepting random seed configuration).
- random_seed: int | None#
- __init__(*, debug=False, verbose=False, output_dir='./_PYOED_RESULTS_', name=None, design=None, optimizer=<class 'pyoed.optimization.binary_optimization.stochastic_binary_optimization.BinaryReinforceOptimizer'>, optimizer_configs=None, criterion='Bayesian A-opt', inverse_problem=None, problem_is_linear=None, penalty_function=None, penalty_function_gradient=None, penalty_weight=0.0, random_seed=None)#
- class SensorPlacementBayesianInversionOED(configs=None)[source]#
Bases:
SensorPlacementInversionOED
,RandomNumberGenerationMixin
This class provides a general implementation for sensor-placement OED in Bayesian inverse problems. The two main components those must be set (in the configurations) or by calling the proper registeration method, are the optimality criterion and the optimizer. Default values are set in the default configurations passed to the constructor __init__, but the user can pass others, or change either of them later.
Note
The implementation here is independent from the choise of the optimality criterion and/or the optimizer. Thus, both relaxation, and binary optimization methods apply.
- validate_configurations(configs, raise_for_invalid=True)[source]#
Validate passed configurations.
- Parameters:
configs (dict | SensorPlacementBayesianInversionOEDConfigs) – configurations to validate. If a
SensorPlacementBayesianInversionOEDConfigs
object is passed, validation is performed on the entire set of configurations. However, if a dictionary is passed, validation is performed only on the configurations corresponding to the keys in the dictionary.
- update_configurations(**kwargs)[source]#
Take any set of keyword arguments, and lookup each in the configurations, and update as nessesary/possible/valid
- Raises:
TypeError – if any of the passed keys in kwargs is invalid/unrecognized
- Remarks:
Generally, we don’t want actual implementations in abstract classes, however, this one is provided as good guidance. Derived classes can rewrite it and/or provide additional updates.
- register_optimizer(optimizer='BinaryReinforceOptimizer', optimizer_configs=None)[source]#
Register (and return) an optimization routine, and make sure the objective function in the optimization routine is set to the objctive function of this objective
objective_function_value()
. The objective function of the optimizer (and its derivatives) are set to the objective function and derivatives implemented here unless the objective function is passed explicitly in the configurations. This method sets a reference to the optimizer and update the underlying configurations accordingly.Note
If the optimizer passed is an instance of (derived from)
Optimizer
, and valid configurations optimizer_configs is passed, the optimizer is updated with the passed configurations by calling optimizer.update_configurations(optimizer_configs).Warning
If the optimizer passed is an instance of (derived from)
Optimizer
, the responsibility is on the developer/user to validate the contents of the optimizer.- Parameters:
optimizer (str | Optimizer | Type[Optimizer]) –
the optimization routine (optimizer) to register. This can be one of the following:
An optimizer instance (object that inherits :py:class`Optimizer`). In this case, the optimizer is registered as is and is updated with the passed configurations if available.
The class (subclass of
Optimizer
) to be used to instantiate the optimizer. To see available built-in optimization routines, see/callshow_supported_optimizers()
.The name of the optimizer (str). This has to match the name of one of the available optimization routine. To see available built-in optimization routines, see/call
show_supported_optimizers()
.
optimizer_configs (None | dict | OptimizerConfigs | Type[OptimizerConfigs]) –
the configurations of the optimization routine. This can be one of the following:
None, in this case configurations are discarded, and whatever default configurations of the selected/passed optimizer are employed.
A dict holding full/partial configurations of the selected optimizer. These are either used to instantiate or update the optimizer configurations based on the type of the passed optimizer.
A class providing implementations of the configurations (this must be a subclass of
OptimizerConfigs
.An instance of a subclass of
OptimizerConfigs
which is to set/udpate optimizer configurations.
- Returns:
the registered optimizer.
- Raises:
TypeError – if the type of passed optimizer and/or configurations are/is not supported
- Return type:
- update_design(design)[source]#
Update the components of the OED (and inverse) problem with the passed design. This method updates both observation operator and observation error model of the underlying inverse problem with the passed design.
Note
This method need to be replaced with design-specific impelentation for any design different from observational experimental design.
- Parameters:
design – an observational design vector conformable with the observation operator and the observation error covariance matrix operator.
- update_random_number_generators(random_seed)[source]#
Update random seeds of underlying random number gnerators (both local and optimizer if supported)
- register_optimality_criterion(criterion=None)[source]#
Validate and set the OED Bayesian optimality criterion as described by criterion, update the configurations object with the criterion, and return the new criterion.
Note
This method only creates a valid criterion (instance of :py:class`Criterion` if a string is passed (name of the criterion)), and then calls super class (parent) to set the criterion. For additional details see e.g.,
pyoed.oed.InversionOED.register_optimality_criterion
- objective_function_value(design)[source]#
Evaluate the value of the OED objective function (regularized utility function) given the passed design.
SensorPlacementInversionOED.objective_function_value()
. updated first, then the objective is calculated, and then the uncertain parameter is reset to the original if needed- Parameters:
design – an observational design vector conformable with the observation operator and the observation error covariance matrix operator. This method accepts a design that is either
binary
orrelaxed
(over the interval [0, 1]), and uses the design to properly relax the OED optimization objective (with the right limits at the boundary).uncertain_parameter_val – value of the uncertain parameter; this must match the registered uncertain parameter and sampler.
reset_parameter_val (bool) – if True, the current values of the uncertain parameter are restored after evaluating the objective function value
- Returns:
value of the registered OED optimality criterion
- Raises:
TypeError
is raised if no uncertain_parameter is registered.- Raises:
TypeError
is raised if no uncertain_parameter_sampler is registered with a valid type. Only instances ofParameterSampler
are accepted.- Raises:
TypeError
is raised if no optimality criterion has been registered yet- Raises:
TypeError
is raised if the either the uncertain parameter or the associated sampler is missing.
- objective_function_grad_design(design)[source]#
Derivative of the objective function (that is the regularized utility/criterion, e.g., trace of FIM for A-opt) with respect to the relaxed design. This is used when the OED optimization problem is solved with relaxation of the design allowing the design to take any value in the interval [0, 1] and thus following a gradient descent/ascent direction for optimization over the design. The gradient is thus \(\nabla_{d} \mathcal{J(d)}\) where \(d\) is the design, and \(\mathcal{J}\) is the OED objective/criterion (A-opt etc.) evaluated by
objective_function_value()
.- Parameters:
design – an observational design vector conformable with the observation operator and the observation error covariance matrix operator. This is intended to be a relaxed design (over the interval [0, 1]),
- Returns:
gradient of the the function defined by
objective_function_value()
- Raises:
:py:class`TypeError` is raised if penalty function/term is not properly set.
- Raises:
:py:class`TypeError` is raised if no valid optimality criterion object is set in the configurations dictionary.
- Raises:
:py:class`TypeError` is raised if a criterion is registerd but it does not provide a :py:meth:grad_design` function.
- objective_function_gradient(design)#
Derivative of the objective function (that is the regularized utility/criterion, e.g., trace of FIM for A-opt) with respect to the relaxed design. This is used when the OED optimization problem is solved with relaxation of the design allowing the design to take any value in the interval [0, 1] and thus following a gradient descent/ascent direction for optimization over the design. The gradient is thus \(\nabla_{d} \mathcal{J(d)}\) where \(d\) is the design, and \(\mathcal{J}\) is the OED objective/criterion (A-opt etc.) evaluated by
objective_function_value()
.- Parameters:
design – an observational design vector conformable with the observation operator and the observation error covariance matrix operator. This is intended to be a relaxed design (over the interval [0, 1]),
- Returns:
gradient of the the function defined by
objective_function_value()
- Raises:
:py:class`TypeError` is raised if penalty function/term is not properly set.
- Raises:
:py:class`TypeError` is raised if no valid optimality criterion object is set in the configurations dictionary.
- Raises:
:py:class`TypeError` is raised if a criterion is registerd but it does not provide a :py:meth:grad_design` function.
- solve(init_guess=None)[source]#
Solve the OED optimization problem by using the registered optimization procedure.
- Parameters:
init_guess – initial guess (e.g., initial design, initial policy parameters)
- Returns:
an instance of
SensorPlacementBayesianInversionOEDResults
holding results obtianed by solving the OED optimization problem.- Raises:
TypeError – if no valid optimizer is registered
- static show_supported_optimizers()[source]#
Print out optimization routines available to choose from. In addition to those shown here, the user can register fully instantiated optimizer (instance of
Optimizer
) by callingregister_optimizer()
.- Returns:
a list of supported optimization routines names
- static show_supported_uncertain_parameters()[source]#
Print out uncertain parameters available to choose from.
- property objective_function_offset#
Numeric offset added to the value of the objective (shifting)
- property objective_function_scaling_factor#
A scaling factor of (to be multiplied by) the objective function self.objective_function
- property supported_optimizers#
- class SensorPlacementBayesianInversionOEDResults(*, oed_problem=None, optimization_results=None)[source]#
Bases:
SensorPlacementInversionOEDResults
Base class for objects holding results of
- Parameters:
optimization_results (Type[OptimizerResults] | None) – the results object returned from calling the optimizer.
oed_problem (Type[InversionOED] | None) – instance of a class derived from
OED
, such asInversionOED
- __init__(*, oed_problem=None, optimization_results=None)#
- create_sensor_placement_binary_oed_problem(inverse_problem)[source]#
Given an inverse problem, create an OED problem with binary or relaxed sensor placment capability. This requires the observation error model to allow relaxed design. Also the optimizer is set to one suitable for non-binary optimization.