import abc
import numpy as np
import tensorflow as tf
import zfit
import zfit.z.numpy as znp
from .. import z as z
from .._variables.axis import Binnings as Binnings, RegularBinning as RegularBinning, histaxes_to_binning as histaxes_to_binning
from ..settings import ztypes as ztypes
from ..util import ztyping as ztyping
from ..util.container import convert_to_container as convert_to_container
from ..util.deprecation import deprecated as deprecated, deprecated_args as deprecated_args, deprecated_norm_range as deprecated_norm_range
from ..util.exception import AxesIncompatibleError as AxesIncompatibleError, AxesNotSpecifiedError as AxesNotSpecifiedError, BreakingAPIChangeError as BreakingAPIChangeError, CannotConvertToNumpyError as CannotConvertToNumpyError, CoordinatesIncompatibleError as CoordinatesIncompatibleError, CoordinatesUnderdefinedError as CoordinatesUnderdefinedError, IllegalInGraphModeError as IllegalInGraphModeError, IntentionAmbiguousError as IntentionAmbiguousError, InvalidLimitSubspaceError as InvalidLimitSubspaceError, LimitsIncompatibleError as LimitsIncompatibleError, LimitsNotSpecifiedError as LimitsNotSpecifiedError, LimitsUnderdefinedError as LimitsUnderdefinedError, MultipleLimitsNotImplemented as MultipleLimitsNotImplemented, NormNotImplemented as NormNotImplemented, NumberOfEventsIncompatibleError as NumberOfEventsIncompatibleError, ObsIncompatibleError as ObsIncompatibleError, ObsNotSpecifiedError as ObsNotSpecifiedError, OverdefinedError as OverdefinedError, ShapeIncompatibleError as ShapeIncompatibleError, SpaceIncompatibleError as SpaceIncompatibleError
from .baseobject import BaseObject as BaseObject
from .coordinates import Coordinates as Coordinates, convert_to_axes as convert_to_axes, convert_to_obs_str as convert_to_obs_str
from .dimension import common_axes as common_axes, common_obs as common_obs, limits_overlap as limits_overlap
from .serialmixin import SerializableMixin as SerializableMixin
from _typeshed import Incomplete
from collections.abc import Callable as Callable, Iterable, Mapping
from numpy import ndarray
from pandas import DataFrame
from tensorflow import Tensor as Tensor
from zfit._interfaces import ZfitData as ZfitData, ZfitLimit as ZfitLimit, ZfitOrderableDimensional as ZfitOrderableDimensional, ZfitPDF as ZfitPDF, ZfitSpace as ZfitSpace

class LimitRangeDefinition: ...

class Any(LimitRangeDefinition):
    def __new__(cls, *_, **__): ...
    def __init_subclass__(cls, **kwargs) -> None: ...
    def __lt__(self, other): ...
    def __le__(self, other): ...
    def __ge__(self, other): ...
    def __gt__(self, other): ...

class AnyLower(Any): ...
class AnyUpper(Any): ...

ANY: Incomplete
ANY_LOWER: Incomplete
ANY_UPPER: Incomplete

class V1Space:
    space: Incomplete
    def __init__(self, space: ZfitSpace) -> None: ...
    @property
    def lower(self) -> np.ndarray: ...
    @property
    def upper(self) -> np.ndarray: ...
    @property
    def limits(self) -> tuple[np.ndarray, np.ndarray]: ...
    @property
    def volume(self) -> np.ndarray: ...
    def area(self): ...

class V0Space:
    space: Incomplete
    def __init__(self, space: ZfitSpace) -> None: ...
    @property
    def lower(self): ...
    @property
    def upper(self): ...
    @property
    def limits(self): ...
    @property
    def volume(self): ...
    def area(self) -> None: ...

class VectorizeLimits:
    space: Incomplete
    def __init__(self, space) -> None: ...
    @property
    def lower(self): ...
    @property
    def upper(self): ...
    @property
    def limits(self): ...
    @property
    def volume(self): ...

def fail_not_rect(func): ...
def calculate_rect_area(rect_limits): ...
def inside_rect_limits(x, rect_limits): ...
def filter_rect_limits(x, rect_limits, axis=None): ...
def convert_to_tensor_or_numpy(obj, dtype=...): ...
def is_range_definition(limit): ...

class Limit(ZfitLimit):
    def __init__(self, limit_fn: ztyping.LimitsFuncTypeInput = None, rect_limits: ztyping.LimitsTypeInput = None, n_obs: int | None = None) -> None: ...
    @property
    def has_rect_limits(self) -> bool: ...
    @property
    def limits(self) -> ztyping.LimitsReturnType: ...
    @property
    def rect_limits(self) -> ztyping.RectLimitsReturnType: ...
    @property
    def rect_limits_np(self) -> ztyping.RectLimitsNPReturnType: ...
    @property
    def rect_lower(self) -> ztyping.RectLowerReturnType: ...
    @property
    def rect_upper(self) -> ztyping.RectUpperReturnType: ...
    def rect_area(self) -> float | np.ndarray | znp.array: ...
    def inside(self, x: ztyping.XTypeInput, guarantee_limits: bool = False) -> ztyping.XTypeReturnNoData: ...
    def filter(self, x: ztyping.XTypeInput, guarantee_limits: bool = False, axis: int | None = None) -> ztyping.XTypeReturnNoData: ...
    @property
    def limit_fn(self): ...
    @property
    def rect_limits_are_tensors(self) -> bool: ...
    @property
    def limits_are_set(self) -> bool: ...
    @property
    def limits_are_false(self) -> bool: ...
    @property
    def has_limits(self) -> bool: ...
    @property
    def n_obs(self) -> int: ...
    @property
    def n_events(self) -> int | None: ...
    def equal(self, other: object, allow_graph: bool = True) -> znp.array: ...
    def __eq__(self, other: object) -> bool: ...
    def less_equal(self, other: object, allow_graph: bool = True) -> znp.array: ...
    def __le__(self, other: object) -> bool: ...
    def get_sublimits(self) -> Iterable[ZfitLimit]: ...
    def __hash__(self) -> int: ...

def rect_limits_are_any(limit: ZfitLimit) -> bool: ...
def less_equal_limits(limit1: Limit, limit2: Limit, allow_graph: bool = True) -> znp.array: ...
def equal_limits(limit1: Limit, limit2: Limit, allow_graph: bool = True) -> bool: ...
def deprecate_multispace(func): ...

warned_new_limits: bool

def warn_new_limits(func): ...

class BaseSpace(ZfitSpace, BaseObject, metaclass=abc.ABCMeta):
    coords: Incomplete
    def __init__(self, obs, axes, name, **kwargs) -> None: ...
    @property
    def is_binned(self): ...
    def inside(self, x: ztyping.XTypeInput, guarantee_limits: bool = False) -> ztyping.XTypeReturn: ...
    def area(self) -> float | znp.array: ...
    @property
    def volume(self) -> float | znp.array: ...
    def filter(self, x: ztyping.XTypeInput, guarantee_limits: bool = False, axis: int | None = None) -> ndarray | Tensor | DataFrame | Any: ...
    @property
    def n_obs(self) -> int: ...
    @property
    def obs(self) -> ztyping.ObsTypeReturn: ...
    @property
    def axes(self) -> ztyping.AxesTypeReturn: ...
    @property
    def n_limits(self) -> int: ...
    def __iter__(self) -> Iterable[ZfitSpace]: ...
    def get_reorder_indices(self, obs: ztyping.ObsTypeInput = None, axes: ztyping.AxesTypeInput = None) -> tuple[int]: ...
    def __add__(self, other): ...
    def get_sublimits(self): ...
    @deprecate_multispace
    def add(self, *other: ztyping.SpaceOrSpacesTypeInput): ...
    def combine(self, *other: ztyping.SpaceOrSpacesTypeInput) -> ZfitSpace: ...
    def __mul__(self, other): ...
    def __ge__(self, other): ...
    def equal(self, other: object, allow_graph: bool) -> znp.array: ...
    def __eq__(self, other: object) -> bool: ...
    def less_equal(self, other, allow_graph): ...
    def __le__(self, other: object) -> bool: ...
    def __hash__(self): ...
    def reorder_x(self, x, x_obs, x_axes, func_obs, func_axes): ...
    def __len__(self) -> int: ...
    def __bool__(self) -> bool: ...

class Space(BaseSpace, SerializableMixin):
    AUTO_FILL: Incomplete
    ANY = ANY
    ANY_LOWER = ANY_LOWER
    ANY_UPPER = ANY_UPPER
    v1: Incomplete
    v0: Incomplete
    vec: Incomplete
    def __init__(self, obs: ztyping.ObsTypeInput | None = None, *args, limits: ztyping.LimitsTypeInput | None = None, binning: ztyping.BinningTypeInput = None, axes=None, rect_limits=None, name: str | None = None, label: str | Iterable[str] | None = None, lower: ztyping.LimitsTypeInputV1 | None = None, upper: ztyping.LimitsTypeInputV1 | None = None) -> None: ...
    @property
    def labels(self): ...
    @property
    def label(self): ...
    @property
    def binning(self): ...
    @property
    def is_binned(self): ...
    def get_limits(self, obs: ztyping.ObsTypeInput = None, axes: ztyping.AxesTypeInput = None) -> ztyping.LimitsDictWithCoords | ztyping.LimitsDictNoCoords: ...
    @property
    @fail_not_rect
    def limits(self) -> ztyping.LimitsTypeReturn: ...
    @property
    def rect_limits(self) -> ztyping.RectLimitsReturnType: ...
    @property
    def rect_limits_np(self) -> ztyping.RectLimitsNPReturnType: ...
    @property
    def rect_upper(self) -> ztyping.UpperTypeReturn: ...
    @property
    def rect_lower(self) -> ztyping.RectLowerReturnType: ...
    def rect_area(self) -> float | np.ndarray | znp.array: ...
    @property
    def rect_limits_are_tensors(self) -> bool: ...
    @property
    def has_rect_limits(self) -> bool: ...
    @property
    def limits_are_false(self) -> bool: ...
    @property
    def has_limits(self) -> bool: ...
    @property
    def limits_are_set(self): ...
    @property
    def n_events(self) -> int | None: ...
    @property
    @fail_not_rect
    def lower(self) -> ztyping.LowerTypeReturn: ...
    @property
    @fail_not_rect
    def upper(self) -> ztyping.UpperTypeReturn: ...
    @property
    def n_limits(self) -> int: ...
    def with_limits(self, limits: ztyping.LimitsTypeInput = None, rect_limits: ztyping.RectLimitsInputType | None = None, name: str | None = None) -> ZfitSpace: ...
    def reorder_x(self, x: tf.Tensor | np.ndarray, *, x_obs: ztyping.ObsTypeInput = None, x_axes: ztyping.AxesTypeInput = None, func_obs: ztyping.ObsTypeInput = None, func_axes: ztyping.AxesTypeInput = None) -> ztyping.XTypeReturnNoData: ...
    def with_obs(self, obs: ztyping.ObsTypeInput | None, allow_superset: bool = True, allow_subset: bool = True) -> ZfitSpace: ...
    def with_axes(self, axes: ztyping.AxesTypeInput | None, allow_superset: bool = True, allow_subset: bool = True) -> ZfitSpace: ...
    def with_coords(self, coords: ZfitOrderableDimensional, allow_superset: bool = True, allow_subset: bool = True) -> Space: ...
    def with_autofill_axes(self, overwrite: bool = False) -> zfit.Space: ...
    def get_subspace(self, obs: ztyping.ObsTypeInput = None, axes: ztyping.AxesTypeInput = None, name: str | None = None) -> Space: ...
    def with_binning(self, binning): ...
    def copy(self, **overwrite_kwargs) -> zfit.Space: ...
    @property
    @fail_not_rect
    def limit1d(self) -> tuple[float, float]: ...
    @classmethod
    def from_axes(cls, axes: ztyping.AxesTypeInput, limits: ztyping.LimitsTypeInput | None = None, rect_limits=None, name: str | None = None) -> zfit.Space: ...

def extract_limits_from_dict(limits_dict, obs=None, axes=None): ...
def add_spaces(*spaces: Iterable[ZfitSpace], name=None): ...
def get_coord(space, obs_in_use: bool = True): ...
def combine_spaces(*spaces: Iterable[Space]): ...
def less_equal_space(space1, space2, allow_graph: bool = True): ...
def equal_space(space1, space2, allow_graph: bool = True): ...
def compare_spaces_equal_static(space1: Space, space2: Space): ...
def compare_multispace(space1: ZfitSpace, space2: ZfitSpace, comparator: Callable): ...
def compare_limits_multispace(space1: ZfitSpace, space2: ZfitSpace, comparator: Callable) -> bool: ...
def compare_limits_coords_dict(limits1: Mapping[str, Mapping[Iterable, ZfitLimit]], limits2: Mapping[str, Mapping[Iterable, ZfitLimit]], comparator: Callable, require_all_coord_types: bool = False) -> bool: ...
def compare_limits_dict(dict1: Mapping, dict2: Mapping, comparator: Callable) -> bool: ...
def flatten_spaces(spaces): ...

class MultiSpace(BaseSpace):
    def __new__(cls, spaces: Iterable[ZfitSpace], obs: ztyping.ObsTypeInput = None, binning: ztyping.BinningTypeInput = None, axes: ztyping.AxesTypeInput = None, name: str | None = None) -> Space | MultiSpace: ...
    spaces: Incomplete
    v0: Incomplete
    def __init__(self, spaces: Iterable[ZfitSpace], obs=None, axes=None, name: str | None = None) -> None: ...
    @property
    def label(self) -> None: ...
    @property
    def labels(self): ...
    @property
    def binning(self): ...
    @property
    @fail_not_rect
    def limits(self) -> None: ...
    @property
    def rect_limits(self) -> None: ...
    @property
    @fail_not_rect
    def lower(self) -> None: ...
    @property
    @fail_not_rect
    def upper(self) -> None: ...
    @property
    def rect_limits_np(self) -> None: ...
    @property
    def rect_lower(self) -> None: ...
    @property
    def rect_upper(self) -> None: ...
    def rect_area(self) -> float | np.ndarray | tf.Tensor: ...
    @property
    def rect_limits_are_tensors(self) -> bool: ...
    @property
    def has_rect_limits(self) -> bool: ...
    @property
    def limits_are_false(self) -> bool: ...
    @property
    def has_limits(self) -> bool: ...
    @property
    def limits_are_set(self) -> bool: ...
    @property
    def n_events(self) -> int | None: ...
    def with_limits(self, limits: ztyping.LimitsTypeInput = None, rect_limits: ztyping.RectLimitsInputType | None = None, name: str | None = None) -> ZfitSpace: ...
    def with_obs(self, obs: ztyping.ObsTypeInput | None, allow_superset: bool = True, allow_subset: bool = True) -> MultiSpace: ...
    def with_axes(self, axes: ztyping.AxesTypeInput | None, allow_superset: bool = True, allow_subset: bool = True) -> MultiSpace: ...
    def with_coords(self, coords: ZfitOrderableDimensional, allow_superset: bool = True, allow_subset: bool = True) -> MultiSpace: ...
    def with_autofill_axes(self, overwrite: bool = False) -> MultiSpace: ...
    def get_subspace(self, obs: ztyping.ObsTypeInput = None, axes: ztyping.AxesTypeInput = None, name: str | None = None) -> MultiSpace: ...
    def copy(self, *, deep: bool = False, name: str | None = None, **overwrite_params) -> MultiSpace: ...
    def __iter__(self) -> ZfitSpace: ...
    def __eq__(self, other): ...
    def __le__(self, other): ...
    def __hash__(self): ...

def convert_to_space(obs: ztyping.ObsTypeInput | None = None, axes: ztyping.AxesTypeInput | None = None, limits: ztyping.LimitsTypeInput | None = None, *, overwrite_limits: bool = False, one_dim_limits_only: bool = True, simple_limits_only: bool = True) -> None | ZfitSpace | bool: ...
def check_norm(supports=None): ...
def param_args_supported(func): ...
def no_multiple_limits(func): ...
@deprecated_norm_range
def supports(*, norm: bool | str | Iterable[str] | None = None, multiple_limits: bool | None = None) -> Callable: ...
def contains_tensor(objects): ...
def shape_np_tf(objects): ...
def limits_consistent(spaces: Iterable[zfit.Space]): ...
def add_spaces_old(spaces: Iterable[zfit.Space]): ...
