Source code for qopt.optimization_data

# -*- coding: utf-8 -*-
# =============================================================================
#     qopt
#     Copyright (C) 2020 Julian Teske, Forschungszentrum Juelich
#
#     This program is free software: you can redistribute it and/or modify
#     it under the terms of the GNU General Public License as published by
#     the Free Software Foundation, either version 3 of the License, or
#     (at your option) any later version.
#
#     This program is distributed in the hope that it will be useful,
#     but WITHOUT ANY WARRANTY; without even the implied warranty of
#     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#     GNU General Public License for more details.
#
#     You should have received a copy of the GNU General Public License
#     along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#     Contact email: j.teske@fz-juelich.de
# =============================================================================
"""This module stores information about the optimization and its result.

The `OptimizationResult` is generated with the final properties and initial
optimization parameter values of each optimization run. The
`OptimizationSummary` is only created when requested and stores the properties
of each step in the optimization algorithm. This information is valuable for
the choice of the best optimization algorithm.

Classes
-------
:class:`OptimizationResult`
    Describes the information gained by an optimization run.

:class:`OptimizationSummary`
    Describes the whole information gained during an optimization run.

Notes
-----
The implementation was inspired by the optimal control package of QuTiP [1]_
(Quantum Toolbox in Python)

References
----------
.. [1] J. R. Johansson, P. D. Nation, and F. Nori: "QuTiP 2: A Python framework
    for the dynamics of open quantum systems.", Comp. Phys. Comm. 184, 1234
    (2013) [DOI: 10.1016/j.cpc.2012.11.019].

"""

from typing import Dict, List


[docs]class OptimizationResult(object): """ Resulting data of the optimization. An instance of this class is returned by the `Optimizer` after the optimization has terminated. It holds the results of the optimization and can also contain an instance of `OptimizationSummary` to describe the optimization run itself, for example its convergence. The parameters of the initialization method are all optional. This class is intended to be initialized empty or loaded from a dictionary by the class method :meth:`from_dict`. Attributes ---------- termination_reason : string Reason for the termination as string. status : None or int The termination_reason as integer. Like in scipy.OptimizeResult None if the optimization has not started. -1: improper input parameters status 0: the maximum number of function evaluations is exceeded. 1: gradient norm termination condition is satisfied. 2: cost function termination condition is satisfied. 3: minimal step size termination condition is satisfied. 4: Both 2 and 3 termination conditions are satisfied. final_cost : float Value of the cost functions after the optimization. final_grad_norm : float Norm of the gradient after the optimization. num_iter : integer Number of iterations in the optimization algorithm. init_parameters : array, shape: (n_t, n_par) The amplitudes at the start of the optimisation, where n_t is the number of time steps simulated and n_par the number of optimization parameters. final_parameters : array, shape: (n_t, n_par) The optimization parameters at the end of the optimisation, where n_t is the number of time steps simulated and n_par the number of optimization parameters. optimizer : `Optimizer` Instance of the `Optimizer` used to generate the result optim_summary : `OptimizationSummary` None if no intermediary results are saved. Otherwise the infidelity during the optimization. """ def __init__(self, final_cost=None, indices=None, final_parameters=None, final_grad_norm=None, init_parameters=None, num_iter=None, termination_reason="not started yet", status=None, optimization_stats=None, optimizer=None, optim_summary=None): self.final_cost = final_cost self.indices = indices self.final_parameters = final_parameters self.final_grad_norm = final_grad_norm self.init_parameters = init_parameters self.num_iter = num_iter self.termination_reason = termination_reason self.status = status self.optimizer = optimizer self.optimization_stats = optimization_stats self.optim_summary = optim_summary
[docs] def to_dict(self): """Writes the information held by this instance to a dictionary. Returns ------- dictionary: dict The information stored in a class instance as dictionary. """ return {'final_cost': self.final_cost, 'indices': self.indices, 'final_parameters': self.final_parameters, 'final_grad_norm': self.final_grad_norm, 'init_parameters': self.init_parameters, 'num_iter': self.num_iter, 'termination_reason': self.termination_reason, 'optimizer': self.optimizer, 'optimization_stats': self.optimization_stats, 'optim_summary': self.optim_summary }
[docs] @classmethod def from_dict(cls, data_dict: Dict): """Initialize the class with the information held in a dictionary. Parameters ---------- data_dict: dict Class information. Returns ------- optim_result: OptimizationResult Class instance. """ return cls(**data_dict)
[docs]class OptimizationSummary(object): """A summary of an optimization run. This class saves the state of the optimization for each iteration. All parameters for the initialization are optimal. The class is intended to be either initialized empty. Attributes ---------- iter_num : int Number of iterations stored. Serves as checksum to verify that full data has been stored. costs : List[float] Evaluation results of the cost functions. The dictionary is sorted by cost function indices. The lists hold one entry for each evaluation. indices : List[str] The indices of the cost functions. gradients : List[array] Gradients of the cost functions. The dictionary is again sorted by cost function indices and the lists hold one entry per evaluation. parameters : List[array] Optimization parameters during the optimization. """ def __init__(self, indices=None, iter_num=0, costs=None, gradients=None, parameters=None): self.indices = indices self.iter_num = iter_num if costs is None: self.costs = [] else: self.costs = costs if gradients is None: self.gradients = [] else: self.gradients = gradients if parameters is None: self.parameters = [] else: self.parameters = parameters