def test_errordef(): m = Minuit(lambda x: x ** 2, 0) m.errordef = 4 assert m.errordef == 4 m.migrad() m.hesse() assert_allclose(m.errors["x"], 2) m.errordef = 1 m.hesse() assert_allclose(m.errors["x"], 1) with pytest.raises(ValueError): m.errordef = 0
def test_parameter_at_limit(sign): m = Minuit(lambda x: (x - sign * 1.2) ** 2, x=0) m.errordef = 1 m.limits["x"] = (-1, 1) m.migrad() assert m.values["x"] == approx(sign * 1.0, abs=1e-3) assert m.fmin.has_parameters_at_limit is True m = Minuit(lambda x: (x - sign * 1.2) ** 2, x=0) m.errordef = 1 m.migrad() assert m.values["x"] == approx(sign * 1.2, abs=1e-3) assert m.fmin.has_parameters_at_limit is False
def test_hesse_without_migrad(): m = Minuit(lambda x: x ** 2 + x ** 4, x=0) m.errordef = 0.5 # second derivative: 12 x^2 + 2 m.hesse() assert m.errors["x"] == approx(0.5 ** 0.5, abs=1e-4) m.values["x"] = 1 m.hesse() assert m.errors["x"] == approx((1.0 / 14.0) ** 0.5, abs=1e-4) assert m.fmin is None m = Minuit(lambda x: 0, 0) m.errordef = 1 with pytest.raises(RuntimeError): m.hesse()
def test_params(): m = Minuit(func0, x=1, y=2) m.errordef = Minuit.LEAST_SQUARES m.errors = (3, 4) m.fixed["x"] = True m.limits["y"] = (None, 10) # these are the initial param states expected = ( Param(0, "x", 1.0, 3.0, None, False, True, False, False, False, None, None), Param(1, "y", 2.0, 4.0, None, False, False, True, False, True, None, 10), ) assert m.params == expected m.migrad() m.minos() assert m.init_params == expected expected = [ Namespace(number=0, name="x", value=1.0, error=3.0, merror=(-3.0, 3.0)), Namespace(number=1, name="y", value=5.0, error=1.0, merror=(-1.0, 1.0)), ] params = m.params for i, exp in enumerate(expected): p = params[i] assert p.number == exp.number assert p.name == exp.name assert p.value == approx(exp.value, rel=1e-2) assert p.error == approx(exp.error, rel=1e-2) assert p.error == approx(exp.error, rel=1e-2)
def fit(self, fit_params): """ Performs the fitting procedure. Parameters ---------- fit_params: array Parameters used to compute the likelihood but not fitted """ def f(*args): return -2 * self.log_likelihood(*args, fit_params=fit_params) print_level = 2 if self.verbose in [1, 2, 3] else 0 m = Minuit(f, name=self.names_parameters, *self.start_parameters.values()) for key, val in self.bound_parameters.items(): m.limits[key] = val m.print_level = print_level m.errordef = 0.5 m.simplex().migrad() self.end_parameters = m.values.to_dict() self.fcn = m.fval self.error_parameters = m.errors.to_dict()
def test_bad_functions_np(func, expected): m = Minuit(lambda x: 0, (1, 1), grad=func) m.errordef = 1 m.throw_nan = True with pytest.raises(type(expected)) as excinfo: m.migrad() assert str(expected) in str(excinfo.value)
def test_bad_functions(func, expected): m = Minuit(func, x=1) m.errordef = 1 m.throw_nan = True with pytest.raises(type(expected)) as excinfo: m.migrad() assert str(expected) in str(excinfo.value)
def test_mncontour_with_fixed_var(): m = Minuit(lambda x, y: 0, x=0, y=0) m.errordef = 1 m.fixed["x"] = True m.migrad() with pytest.raises(ValueError): m.mncontour("x", "y")
def MinForReplica(): global totalN,setDY,initialValues,initialErrors,searchLimits,parametersToMinimize def repchi_2(x): global totalN startT=time.time() harpy.setNPparameters(x) print('np set =',["{:8.3f}".format(i) for i in x], end =" ") ccDY2,cc2=DataProcessor.harpyInterface.ComputeChi2(repDataDY) if(usePenaltyTerm): ccDY2+=totalN*PenaltyTerm(x) cc=(ccDY2)/totalN endT=time.time() print(':->',cc,' t=',endT-startT) return ccDY2 repDataDY=setDY.GenerateReplica() localM = Minuit(repchi_2, initialValues) localM.errors=initialErrors localM.limits=searchLimits localM.fixed=parametersToMinimize localM.errordef=1 localM.tol=0.0001*totalN*10000 ### the last 0.0001 is to compensate MINUIT def localM.strategy=1 localM.migrad() ### [chi^2, NP-parameters] return [localM.fval,list(localM.values)]
def _curve_fit_wrapper( func: Callable[..., Any], xdata: np.typing.NDArray[Any], ydata: np.typing.NDArray[Any], yerr: np.typing.NDArray[Any], likelihood: bool = False, ) -> tuple[tuple[float, ...], np.typing.NDArray[Any]]: """ Wrapper around `scipy.optimize.curve_fit`. Initial parameters (`p0`) can be set in the function definition with defaults for kwargs (e.g., `func = lambda x,a=1.,b=2.: x+a+b`, will feed `p0 = [1.,2.]` to `curve_fit`) """ try: from scipy.optimize import curve_fit, minimize except ModuleNotFoundError: print(_PLT_MISSING_MSG, file=sys.stderr) raise params = list(inspect.signature(func).parameters.values()) p0 = [ 1 if arg.default is inspect.Parameter.empty else arg.default for arg in params[1:] ] mask = yerr != 0.0 popt, pcov = curve_fit( func, xdata[mask], ydata[mask], sigma=yerr[mask], absolute_sigma=True, p0=p0, ) if likelihood: try: from iminuit import Minuit except ModuleNotFoundError: print(_PLT_MISSING_MSG, file=sys.stderr) raise from scipy.special import gammaln def fnll(v: Iterable[np.typing.NDArray[Any]]) -> float: ypred = func(xdata, *v) if (ypred <= 0.0).any(): return 1e6 return ( # type: ignore[no-any-return] ypred.sum() - (ydata * np.log(ypred)).sum() + gammaln(ydata + 1).sum()) # Seed likelihood fit with chi2 fit parameters res = minimize(fnll, popt, method="BFGS") popt = res.x # Better hessian from hesse, seeded with scipy popt m = Minuit(fnll, popt) m.errordef = 0.5 m.hesse() pcov = np.array(m.covariance) return tuple(popt), pcov
def fit(least_squares): m = Minuit(least_squares, m1=1400, m2=300, m3=250, k=0, a=0, b=0, e=0, g=0) m.limits['m1'] = (1500, 1700) m.limits['m2'] = (300, 500) m.limits['m3'] = (250, 450) m.errordef = Minuit.LEAST_SQUARES m.migrad() return m
def test_inaccurate_fcn(iterate, valid): def f(x): return abs(x) ** 10 + 1e7 m = Minuit(f, x=2) m.errordef = 1 m.migrad(iterate=iterate) assert m.valid == valid
def test_function_with_maximum(): def func(a): return -(a ** 2) m = Minuit(func, a=0) m.errordef = 1 m.migrad() assert m.fmin.is_valid is False
def test_non_invertible(): m = Minuit(lambda x, y: 0, 1, 2) m.errordef = 1 m.strategy = 0 m.migrad() assert m.fmin.is_valid m.hesse() assert not m.fmin.is_valid assert m.covariance is None
def test_errordef(): m = Minuit(lambda x: x**2, pedantic=False, errordef=4) assert m.errordef == 4 m.migrad() m.hesse() assert_allclose(m.errors["x"], 2) m.errordef = 1 m.hesse() assert_allclose(m.errors["x"], 1)
def fit_minuit_v2(fcn, bounds_dict={}, hesse=True, minos=False, **kwargs): """ :param fcn: :param bounds_dict: :param hesse: :param minos: :return: """ from iminuit import Minuit var_args = {} var_names = fcn.vm.trainable_vars x0 = [] for i in var_names: x0.append(fcn.vm.get(i)) var_args[i] = fcn.vm.get(i) if i in bounds_dict: var_args["limit_{}".format(i)] = bounds_dict[i] # var_args["error_" + i] = 0.1 f_g = Cached_FG(fcn.nll_grad) m = Minuit( f_g.fun, np.array(x0), name=var_names, grad=f_g.grad, ) m.strategy = 0 for i in var_names: if i in bounds_dict: m.limits[i] = bounds_dict[i] m.errordef = 0.5 m.print_level = 2 print("########## begin MIGRAD") now = time.time() m.migrad() # (ncall=10000))#,precision=5e-7)) print("MIGRAD Time", time.time() - now) if hesse: print("########## begin HESSE") now = time.time() m.hesse() print("HESSE Time", time.time() - now) if minos: print("########## begin MINOS") now = time.time() m.minos() # (var="") print("MINOS Time", time.time() - now) ndf = len(var_names) ret = FitResult(dict(zip(var_names, m.values)), fcn, m.fval, ndf=ndf, success=m.valid) # print(m.errors) ret.set_error(dict(zip(var_names, m.errors))) return ret
def test_chi2_fit(): def chi2(x, y): return (x - 1) ** 2 + ((y - 2) / 3) ** 2 m = Minuit(chi2, x=0, y=0) m.errordef = 1 m.migrad() assert_allclose(m.values, (1, 2)) assert_allclose(m.errors, (1, 3))
def test_throw_nan(): m = Minuit(returning_nan, x=1) m.errordef = 1 assert not m.throw_nan m.migrad() m.throw_nan = True with pytest.raises(RuntimeError): m.migrad() assert m.throw_nan
def curve_fit_wrapper(func, xdata, ydata, sigma=None, absolute_sigma=True, likelihood=False, **kwargs): """ Wrapper around `scipy.optimize.curve_fit`. Initial parameters (`p0`) can be set in the function definition with defaults for kwargs (e.g., `func = lambda x,a=1.,b=2.: x+a+b`, will feed `p0 = [1.,2.]` to `curve_fit`) """ from scipy.optimize import minimize, curve_fit xdata = xdata.astype(np.float64) # need this for minuit hesse to converge if func.__defaults__ and len( func.__defaults__) + 1 == func.__code__.co_argcount: if "p0" not in kwargs: kwargs["p0"] = func.__defaults__ tomask = (ydata == 0.0) | (~np.isfinite(ydata)) if sigma is not None: tomask |= sigma == 0.0 popt, pcov = curve_fit( func, xdata[~tomask], ydata[~tomask], sigma=sigma[~tomask], absolute_sigma=absolute_sigma, **kwargs, ) if likelihood: from scipy.special import gammaln def fnll(v): ypred = func(xdata, *v) if (ypred <= 0.0).any(): return 1e6 return (ypred.sum() - (ydata * np.log(ypred)).sum() + gammaln(ydata + 1).sum()) res = minimize(fnll, popt, method="BFGS") popt = res.x pcov = res.hess_inv use_minuit = True if use_minuit: try: from iminuit import Minuit except ImportError: raise Exception( "For likelihood minimization, the 'iminuit' module must be installed (`pip install --user iminuit`)." ) m = Minuit(fnll, popt) m.errordef = 0.5 m.hesse() pcov = np.array(m.covariance) return popt, pcov
def test_matrix(): m = Minuit(lambda x, y: x**2 + (y / 2)**2 + 1, x=0, y=0) m.errordef = 1 m.migrad() assert (framed(tab.tabulate(*m.covariance.to_table())) == """ x y -- ------ ------ x 1 -0.643 y -0.643 4 """)
def test_html_minuit(): m = Minuit(lambda x, y: x**2 + 4 * y**2, x=0, y=0) m.errordef = 1 assert m._repr_html_() == m.params._repr_html_() m.migrad() assert (m._repr_html_() == m.fmin._repr_html_() + m.params._repr_html_() + m.covariance._repr_html_()) m.minos() assert (m._repr_html_() == m.fmin._repr_html_() + m.params._repr_html_() + m.merrors._repr_html_() + m.covariance._repr_html_())
def test_text_minuit(): m = Minuit(lambda x, y: x**2 + 4 * y**2, x=0, y=0) m.errordef = 1 assert str(m) == str(m.params) m.migrad() assert str(m) == str(m.fmin) + "\n" + str(m.params) + "\n" + str( m.covariance) m.minos() assert str(m) == str(m.fmin) + "\n" + str(m.params) + "\n" + str( m.merrors) + "\n" + str(m.covariance)
def test_perfect_correlation(): def func(a, b): return (a - b) ** 2 m = Minuit(func, a=1, b=2) m.errordef = 1 m.migrad() assert m.fmin.is_valid is True assert m.fmin.has_accurate_covar is False assert m.fmin.has_posdef_covar is False assert m.fmin.has_made_posdef_covar is True
def test_fixing_long_variable_name(grad): m = Minuit( func5, grad=grad, long_variable_name_really_long_why_does_it_has_to_be_this_long=2, x=0, z=0, ) m.errordef = 1 m.fixed["long_variable_name_really_long_why_does_it_has_to_be_this_long"] = True m.migrad() assert_allclose(m.values, [1, 2, -1], atol=1e-3)
def optimize_1pz(w_in, a_baseline_in, t_beg_in, t_end_in, p0_in, val0_out): """ Find the optimal, single pole-zero cancellation's parameter by minimizing the slope in the waveform's specified time range. Parameters ---------- w_in : array-like The input waveform a_baseline_in: float The resting baseline t_beg_in : int The lower bound's index for the time range over which to optimize the pole-zero cancellation t_end_in : int The upper bound's index for the time range over which to optimize the pole-zero cancellation p0_in : float The initial guess of the optimal time constant val0_out : float The output value of the best-fit time constant Processing Chain Example ------------------------ "tau0": { "function": "optimize_1pz", "module": "pygama.dsp.processors", "args": ["waveform", "baseline", "0", "20*us", "500*us", "tau0"], "prereqs": ["waveform", "baseline"], "unit": "us" } """ val0_out[0] = np.nan if np.isnan(w_in).any() or np.isnan(a_baseline_in) or np.isnan(t_beg_in) or np.isnan(t_end_in) or\ np.isnan(p0_in): return if not np.floor(t_beg_in) == t_beg_in or\ not np.floor(t_end_in) == t_end_in: raise DSPFatal('The waveform index is not an integer') if int(t_beg_in) < 0 or int(t_beg_in) > len(w_in) or\ int(t_end_in) < 0 or int(t_end_in) > len(w_in): raise DSPFatal('The waveform index is out of range') m = Minuit(Model(pole_zero, w_in, a_baseline_in, int(t_beg_in), int(t_end_in)), [p0_in]) m.print_level = -1 m.strategy = 1 m.errordef = Minuit.LEAST_SQUARES m.migrad() val0_out[0] = m.values[0]
def test_params(): m = Minuit(lambda x, y: x**2 + (y / 2)**2 + 1, x=0, y=0) m.errordef = 1 m.limits["y"] = (-1, 1) m.fixed["x"] = True m.migrad() m.minos() assert (framed(tab.tabulate(*m.params.to_table())) == """ pos name value error error- error+ limit- limit+ fixed ----- ------ ------- ------- -------- -------- -------- -------- ------- 0 x 0 0.1 yes 1 y 0 1.5 -1.0 1.0 -1.0 1.0 """)
def test_issue_424(): def lsq(x, y, z): return (x - 1) ** 2 + (y - 4) ** 2 / 2 + (z - 9) ** 2 / 3 m = Minuit(lsq, x=0.0, y=0.0, z=0.0) m.errordef = 1 m.migrad() m.fixed["x"] = True m.errors["x"] = 2 m.hesse() assert m.fixed["x"] is True assert m.errors["x"] == 2
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: m = Minuit( self._fcn, initial_param_values, name=self.params.names, ) m.errors = 0.05 * initial_param_values m.errordef = error_def m.limits = self._param_bounds for i in range(len(m.params)): m.fixed[i] = self._get_fixed_params()[i] m.print_level = 1 if verbose else 0 # perform minimization twice! fmin = m.migrad(ncall=100000, iterate=2).fmin self._fcn_min_val = m.fval self._params.values = np.array(m.values) self._params.errors = np.array(m.errors) fixed_params = tuple( ~np.array(self._get_fixed_params())) # type: Tuple[bool, ...] self._params.covariance = np.array( m.covariance)[fixed_params, :][:, fixed_params] self._params.correlation = np.array( m.covariance.correlation())[fixed_params, :][:, fixed_params] self._success = fmin.is_valid and fmin.has_valid_parameters and fmin.has_covariance if check_success and not self._success: raise RuntimeError(f"Minimization was not successful.\n" f"{fmin}\n") assert self._success is not None return MinimizeResult(fcn_min_val=m.fval, params=self._params, success=self._success)
def test_fmin(): m = Minuit(lambda x, s: (x * s) ** 2, x=1, s=1) m.fixed["s"] = True m.errordef = 1 m.migrad() fm1 = m.fmin assert fm1.is_valid m.values["s"] = 0 m.migrad() fm2 = m.fmin assert fm1.is_valid assert not fm2.is_valid
def taubin_circle_fit(x, y, mask): """ reference : Barcelona_Muons_TPA_final.pdf (slide 6) Parameters ---------- x: array-like or astropy quantity x coordinates of the points y: array-like or astropy quantity y coordinates of the points mask: array-like boolean true for pixels surviving the cleaning """ original_unit = x.unit x, y = all_to_value(x, y, unit=original_unit) x_masked = x[mask] y_masked = y[mask] R = x.max() # x.max() just happens to be identical with R in many cases. taubin_r_initial = R / 2 taubin_error = R * 0.1 xc = 0 yc = 0 # minimization method fit = Minuit(make_taubin_loss_function(x_masked, y_masked), xc=xc, yc=yc, r=taubin_r_initial) fit.errordef = Minuit.LEAST_SQUARES fit.errors["xc"] = taubin_error fit.errors["yc"] = taubin_error fit.errors["r"] = taubin_error fit.limits["xc"] = (-2 * R, 2 * R) fit.limits["yc"] = (-2 * R, 2 * R) fit.limits["r"] = (0, R) fit.migrad() radius = Quantity(fit.values["r"], original_unit) center_x = Quantity(fit.values["xc"], original_unit) center_y = Quantity(fit.values["yc"], original_unit) return radius, center_x, center_y