import collections
import iminuit
import ipyopt
import numpy as np
import scipy.optimize
import types
import typing
import zfit
from ..core.parameter import set_values as set_values
from ..util.container import convert_to_container as convert_to_container
from ..util.deprecation import deprecated as deprecated, deprecated_args as deprecated_args
from ..util.exception import BreakingAPIChangeError as BreakingAPIChangeError
from ..util.warnings import ExperimentalFeatureWarning as ExperimentalFeatureWarning
from ..util.ztyping import ParamsTypeOpt as ParamsTypeOpt
from .errors import WeightCorr as WeightCorr, compute_errors as compute_errors, covariance_with_weights as covariance_with_weights, dict_to_matrix as dict_to_matrix, matrix_to_dict as matrix_to_dict
from .evaluation import LossEval as LossEval
from .interface import ZfitMinimizer as ZfitMinimizer, ZfitResult as ZfitResult
from .termination import ConvergenceCriterion as ConvergenceCriterion
from collections.abc import Callable as Callable, Iterable, Mapping
from zfit._interfaces import ZfitData as ZfitData, ZfitIndependentParameter as ZfitIndependentParameter, ZfitLoss as ZfitLoss, ZfitParameter as ZfitParameter, ZfitUnbinnedData as ZfitUnbinnedData

class Approximations:
    def __init__(self, params: list[ZfitParameter] | tuple[ZfitParameter], gradient: np.ndarray | None = None, hessian: np.ndarray | None = None, inv_hessian: np.ndarray | None = None) -> None: ...
    @property
    def params(self): ...
    def gradient(self, params: ZfitParameter | Iterable[ZfitParameter] | None = None) -> np.ndarray | None: ...
    def hessian(self, invert: bool = True) -> np.ndarray | None: ...
    def inv_hessian(self, invert: bool = True) -> None | np.ndarray: ...
    def freeze(self) -> None: ...

class ParamToNameGetitem:
    def __getitem__(self, item): ...

class NameToParamGetitem:
    def __getitem__(self, item): ...
    def __contains__(self, item) -> bool: ...

class OptimizeResultMixin:
    @property
    def success(self) -> bool: ...
    @property
    def fun(self) -> float: ...
    @property
    def jac(self) -> np.ndarray | None: ...
    @property
    def hess(self) -> np.ndarray | None: ...
    @property
    def hess_inv(self) -> np.ndarray | None: ...
    @property
    def nfev(self) -> int | None: ...
    @property
    def njev(self) -> int | None: ...
    @property
    def nhev(self) -> int | None: ...
    @property
    def nit(self) -> int | None: ...
    @property
    def maxcv(self) -> float | None: ...

class FitResult(OptimizeResultMixin, ZfitResult):
    def __init__(self, loss: ZfitLoss, params: dict[ZfitParameter, float], minimizer: ZfitMinimizer, valid: bool, edm: float, fminopt: float, criterion: ConvergenceCriterion | None, status: int | None = None, converged: bool | None = None, message: str | None = None, info: Mapping | None = None, approx: Mapping | Approximations | None = None, niter: int | None = None, evaluator: LossEval = None) -> None: ...
    @classmethod
    def from_ipopt(cls, loss: ZfitLoss, params: Iterable[ZfitParameter], problem: ipyopt.Problem, minimizer: zfit.minimize.Ipyopt, valid: bool, values: np.ndarray, message: str | None, converged: bool | None, edm: zfit.minimizers.termination.CriterionNotAvailable | float, niter: int | None, fminopt: float | None, status: int | None, criterion: zfit.minimizers.termination.ConvergenceCriterion, evaluator: zfit.minimizers.evaluation.LossEval | None) -> FitResult: ...
    @classmethod
    def from_minuit(cls, loss: ZfitLoss, params: Iterable[ZfitParameter], minuit: iminuit.Minuit, minimizer: ZfitMinimizer | iminuit.Minuit, valid: bool | None, values: np.ndarray | None = None, message: str | None = None, converged: bool | None = None, edm: None | zfit.minimizers.termination.CriterionNotAvailable | float = None, niter: int | None = None, fminopt: float | None = None, status: int | None = None, criterion: zfit.minimizers.termination.ConvergenceCriterion | None = None, evaluator: zfit.minimizers.evaluation.LossEval | None = None) -> FitResult: ...
    @classmethod
    def from_scipy(cls, loss: ZfitLoss, params: Iterable[ZfitParameter], result: scipy.optimize.OptimizeResult, minimizer: ZfitMinimizer, message: str | None, valid: bool, criterion: ConvergenceCriterion, edm: float | None = None, niter: int | None = None, evaluator: zfit.minimize.LossEval | None = None) -> FitResult: ...
    @classmethod
    def from_nlopt(cls, loss: ZfitLoss, opt, params: Iterable[ZfitParameter], minimizer: ZfitMinimizer | iminuit.Minuit, valid: bool | None, values: np.ndarray | None = None, message: str | None = None, converged: bool | None = None, edm: None | zfit.minimizers.termination.CriterionNotAvailable | float = None, niter: int | None = None, fminopt: float | None = None, status: int | None = None, criterion: zfit.minimizers.termination.ConvergenceCriterion | None = None, evaluator: zfit.minimizers.evaluation.LossEval | None = None, inv_hessian: np.ndarray | None = None, hessian: np.ndarray | None = None) -> FitResult: ...
    @property
    def approx(self) -> Approximations: ...
    @property
    def params(self) -> Mapping[ZfitIndependentParameter, Mapping[str, Mapping[str, object]]]: ...
    @property
    def values(self) -> Mapping[str | ZfitParameter, float]: ...
    @property
    def criterion(self) -> ConvergenceCriterion: ...
    @property
    def message(self) -> str: ...
    @property
    def edm(self) -> float: ...
    @property
    def minimizer(self) -> ZfitMinimizer: ...
    @property
    def loss(self) -> ZfitLoss: ...
    @property
    def fminopt(self) -> float: ...
    @property
    def fmin(self) -> float: ...
    @property
    def fminfull(self) -> float: ...
    @property
    def status(self): ...
    @property
    def info(self) -> Mapping[str, object]: ...
    @property
    def converged(self) -> bool: ...
    @property
    def valid(self) -> bool: ...
    @property
    def x(self): ...
    @property
    def params_at_limit(self) -> bool: ...
    def hesse(self, params: ParamsTypeOpt = None, method: str | Callable | None = None, *, cl: float | None = None, name: str | bool | None = None, weightcorr: WeightCorr | None = None, error_name: str | None = None) -> dict[ZfitIndependentParameter, dict]: ...
    def error(self, params: ParamsTypeOpt = None, method: str | Callable | None = None, error_name: str | None = None, sigma: float = 1.0) -> dict: ...
    def errors(self, params: ParamsTypeOpt = None, method: str | Callable | None = None, name: str | None = None, cl: float | None = None, *, sigma=None, error_name: str | None = None) -> tuple[dict, None | FitResult]: ...
    def covariance(self, params: ParamsTypeOpt = None, method: str | Callable | None = None, as_dict: bool = False, *, weightcorr: WeightCorr = None): ...
    def correlation(self, params: ParamsTypeOpt = None, method: str | Callable | None = None, as_dict: bool = False): ...
    def freeze(self) -> None: ...
    def __enter__(self): ...
    def __exit__(self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: types.TracebackType | None) -> None: ...
    def update_params(self) -> typing.Self: ...

def covariance_to_correlation(covariance): ...
def format_value(value, highprec: bool = True): ...
def color_on_bool(value, on_true=None, on_false=None): ...

class ListWithKeys(collections.UserList):
    def __init__(self, initdict) -> None: ...
    def __getitem__(self, item): ...
    def keys(self): ...
    def values(self): ...
    def items(self): ...

class ValuesHolder(NameToParamGetitem, ListWithKeys): ...
class ParamHolder(NameToParamGetitem, collections.UserDict): ...
