def test_simultaneous_fit_basic(logging_mixin: Any, setup_simultaneous_fit_data: Any) -> None: """ Test basic Simultaneous fit functionality. """ # Setup h, h_shifted, _, _ = setup_simultaneous_fit_data # Check with cost functions cost_func1 = cost_function.ChiSquared(func_1, data=h) cost_func2 = cost_function.ChiSquared(func_2, data=h_shifted) s2 = cost_function.SimultaneousFit(cost_func1, cost_func2) assert s2.func_code == fit_base.FuncCode(["a", "b", "c", "d"]) # Check with manually added functions s3 = cost_func1 + cost_func2 assert s3.func_code == fit_base.FuncCode(["a", "b", "c", "d"]) assert s3 == s2
def test_nested_simultaneous_fit_objects( logging_mixin: Any, setup_simultaneous_fit_data: Any) -> None: """ Test for unraveling nested simultaneous fit objects. """ # Setup h, h_shifted, _, _ = setup_simultaneous_fit_data # Check with cost functions cost_func1 = cost_function.ChiSquared(func_1, data=h) cost_func2 = cost_function.ChiSquared(func_2, data=h_shifted) cost_func3 = cost_function.ChiSquared(lambda x, e, f: x + e + f, data=h) s = cost_func1 + cost_func2 s2 = s + cost_func3 assert s2.func_code == fit_base.FuncCode(["a", "b", "c", "d", "e", "f"]) # Test out using sum s3 = sum([cost_func1, cost_func2, cost_func3]) # Help out mypy... assert isinstance(s3, cost_function.SimultaneousFit) assert s3.func_code == fit_base.FuncCode(["a", "b", "c", "d", "e", "f"])
def __init__(self, *functions: Callable[..., float], prefixes: Optional[Sequence[str]] = None, skip_prefixes: Optional[Sequence[str]] = None) -> None: # Store the functions self.functions = list(functions) # Determine the arguments for the functions. merged_args, argument_positions = fit_base.merge_func_codes( self.functions, prefixes = prefixes, skip_prefixes = skip_prefixes ) logger.debug(f"merged_args: {merged_args}") self.func_code = fit_base.FuncCode(merged_args) self.argument_positions = argument_positions
def __init__( self, f: Callable[..., float], data: Union[npt.NDArray[Any], histogram.Histogram1D], **additional_call_options: Any, ): # If using numba, we would need to JIT the function to be able to pass it to the cost function. self.f = f # We need to drop the leading x argument self.func_code = fit_base.FuncCode(iminuit.util.describe(self.f)[1:]) self.data = data self._additional_call_options: Dict[str, Any] = additional_call_options
def test_func_code(logging_mixin: Any, simple_test_functions: Any) -> None: """ Test creating function codes with FuncCode. """ # Setup func_1, func_2 = simple_test_functions # Define the func code and check the properties func_code = fit_base.FuncCode(iminuit.util.describe(func_1)) assert func_code.co_varnames == ["x", "a", "b"] assert func_code.co_argcount == 3 # Alternatively create via static method func_code_2 = fit_base.FuncCode.from_function(func_1) assert func_code == func_code_2
def __init__(self, *cost_functions: Union[T_CostFunction, "SimultaneousFit"]): # Validation # Ensure that we unravel any SimultaneousFit objects to their base cost functions. funcs = list(unravel_simultaneous_fits(list(cost_functions))) self.cost_functions = funcs logger.debug("Simultaneous Fit") merged_args, argument_positions = fit_base.merge_func_codes( self.cost_functions) # We don't drop any of the arguments here because the cost functions already did it. self.func_code = fit_base.FuncCode(merged_args) self.argument_positions = argument_positions
def test_simultaneous_fit(logging_mixin: Any, setup_simultaneous_fit_data: Any) -> None: """ Test Simultaneous Fit functionality vs probfit with an integration test. """ # Setup h, h_shifted, _, _ = setup_simultaneous_fit_data cost_func1 = cost_function.ChiSquared(parabola, data=h) cost_func2 = cost_function.ChiSquared(parabola, data=h_shifted) minuit_args: Dict[str, Union[float, Tuple[float, float]]] = { "scale": 1.5, "error_scale": 0.15, "limit_scale": (-1000, 1000), } # Setup the probfit version probfit = pytest.importorskip("probfit") s_probfit = probfit.SimultaneousFit(*[cost_func1, cost_func2]) # Setup the comparison version s = cost_func1 + cost_func2 # First, basic checks logger.debug( f"func_code: {s.func_code}, co_varnames: {s.func_code.co_varnames}") assert s.func_code == fit_base.FuncCode(["scale"]) assert s.func_code.co_varnames == list(s_probfit.func_code.co_varnames) # Now perform the fits fit_result, _ = fit_integration.fit_with_minuit(cost_func=s, minuit_args=minuit_args, x=h.x) fit_result_probfit, _ = fit_integration.fit_with_minuit( cost_func=s_probfit, minuit_args=minuit_args, x=h.x) # And check that the fit results agree logger.debug( f"scale: {fit_result.values_at_minimum['scale']} +/- {fit_result.errors_on_parameters['scale']}" ) logger.info(f"type: {type(fit_result)}, {type(fit_result_probfit)}") assert fit_result == fit_result_probfit