def test_template_add_cov_mat(self): template = Template("test", self.var, self.num_bins, self.limits, self.df) stat_cov_mat = np.diag(self.x_errors**2) cov_mat = np.array([[2, 1, 0], [1, 3, 0], [0, 0, 1]]) expected_cov_mat = stat_cov_mat + cov_mat template.add_covariance_matrix(cov_mat) new_x_errors = np.sqrt(np.diag(expected_cov_mat)) np.testing.assert_array_equal(template._relative_errors, new_x_errors / self.x_hist) np.testing.assert_array_almost_equal(template._cov, expected_cov_mat) np.testing.assert_array_almost_equal(template._corr, cov2corr(expected_cov_mat)) np.testing.assert_array_almost_equal( template._inv_corr, np.linalg.inv(cov2corr(expected_cov_mat)))
def _add_cov_mat(self, cov_mat): """Helper function. Calculates a covariance matrix from given histogram up and down variations. """ self._cov_mats.append(np.copy(cov_mat)) self._cov += cov_mat self._corr = cov2corr(self._cov) self._inv_corr = np.linalg.inv(self._corr) self._relative_errors = np.divide( np.sqrt(np.diag(self._cov)), self._flat_bin_counts, out=np.full(self._num_bins, 1e-7), where=self._flat_bin_counts != 0, )
def add_covariance_matrix(self, covariance_matrix): """Add a covariance matrix for a systematic error to this template. This updates the total covariance matrix, the correlation matrix and the relative bin errors. Parameters ---------- covariance_matrix : numpy.ndarray A covariance matrix. It is not checked if the matrix is valid (symmetric, positive semi-definite. Shape is (`num_bins`, `num_bins`). """ self._cov += covariance_matrix self._corr = cov2corr(self._cov) self._inv_corr = np.linalg.inv(self._corr) self._relative_errors = np.divide( np.sqrt(np.diag(self._cov)), self._hist.bin_counts, out=np.full(self.num_bins, 1e-7), where=self._hist.bin_counts != 0, )
def minimize(self, initial_param_values: np.ndarray, verbose: bool = False, additional_args: Tuple[Any] = (), get_hesse: bool = True) -> MinimizeResult: """ Performs minimization of given objective function. Parameters ---------- initial_param_values : np.ndarray or list of floats Initial values for the parameters used as starting values. Shape is (`num_params`,). additional_args : tuple Tuple of additional arguments for the objective function. get_hesse : bool If True, the Hesse matrix is estimated at the minimum of the objective function. This allows the calculation of parameter errors. Default is True. verbose: bool If True, a convergence message is printed. Default is False. Returns ------- MinimizeResult """ constraints = self._create_constraints(initial_param_values) opt_result = minimize( fun=self._fcn, x0=initial_param_values, args=additional_args, method="SLSQP", bounds=self._param_bounds, constraints=constraints, options={"disp": verbose}, ) self._success = opt_result.success self._status = opt_result.status self._message = opt_result.message if not opt_result.success: raise RuntimeError(f"Minimization was not successful.\n" f"Status: {opt_result.status}\n" f"Message: {opt_result.message}") self._params.values = opt_result.x self._fcn_min_val = opt_result.fun if get_hesse: hesse = ndt.Hessian(self._fcn)(self._params.values, *additional_args) self._params.covariance = np.linalg.inv(hesse) self._params.correlation = cov2corr(self._params.covariance) self._params.errors = np.sqrt(np.diag(self._params.covariance)) if verbose: print(self._params) result = MinimizeResult(opt_result.fun, self._params, self._success) return result
def minimize( self, initial_param_values: np.ndarray, verbose: bool = False, error_def: float = 0.5, additional_args: Optional[Tuple[Any, ...]] = None, get_hesse: bool = True, check_success: bool = True, ) -> MinimizeResult: """ Performs minimization of given objective function. Parameters ---------- initial_param_values : np.ndarray or list of floats Initial values for the parameters used as starting values. Shape is (`num_params`,). error_def : Not used for this implementation additional_args : tuple Tuple of additional arguments for the objective function. get_hesse : bool If True, the Hesse matrix is estimated at the minimum of the objective function. This allows the calculation of parameter errors. Default is True. verbose: bool If True, a convergence message is printed. Default is False. check_success: bool Check if fit was successful and raise if not! Default: True Returns ------- MinimizeResult """ constraints = self._create_constraints(initial_param_values) _additional_args = tuple([]) # type: Tuple[Any, ...] if additional_args is not None: _additional_args = additional_args logging.info( f"Starting SciPy minimization with {sum(~np.array(self.params.fixed_params))} floating and {sum(self.params.fixed_params)} fixed parameters." ) opt_result = scipy_minimize( fun=self._fcn, x0=initial_param_values, args=additional_args, method="SLSQP", bounds=self._param_bounds, constraints=constraints, # type: ignore options={"disp": verbose}, ) logging.info( f"Finished SciPy minimization with success = {opt_result.success}, status {opt_result.status} and message {opt_result.message}." ) self._success = opt_result.success self._status = opt_result.status self._message = opt_result.message if not opt_result.success: raise RuntimeError( "Minimization was not successful.\n", f"Status: {opt_result.status}\n", f"Message: {opt_result.message}", ) self._params.values = opt_result.x self._fcn_min_val = opt_result.fun if get_hesse: logging.info("Calculating Hesse Matrix for SciPy minimization.") hesse = ndt.Hessian(self._fcn)(self._params.values, *_additional_args) self._params.covariance = np.linalg.inv(hesse) self._params.correlation = cov2corr(self._params.covariance) self._params.errors = np.sqrt(np.diag(self._params.covariance)) logging.info( "Finished calculation of Hesse Matrix for SciPy minimization.") if verbose: print(self._params) if check_success: pass # TODO assert self._success is not None result = MinimizeResult(fcn_min_val=opt_result.fun, params=self._params, success=self._success) return result
def bin_correlation_matrix(self) -> np.ndarray: if self._bin_correlation_matrix is not None: return self._bin_correlation_matrix self._bin_correlation_matrix = cov2corr(self.bin_covariance_matrix) return self._bin_correlation_matrix