\subsection{Spaces and Dimensions} \label{sec:spaces and dimensions} The extension to more than one dimension when fitting a model contains some ambiguities. The data, limits and the models all have corresponding axes or columns that should match. To deal with that in a simple, yet consistent manner, \zfit{} has a \zspace{}. The responsibility of this class is to define and handle the axes or dimensions and limits. To understand the concept and the \zspace{} itself, three definitions need to be made: \begin{description} \item[Observables] The observables are the \textit{named axes of a coordinate system}. A single observable is a string and a list of strings acts as several observables describing a higher dimensional system. In the context of data this is equivalent to columns in a data frame. Observables allow a named, \textit{inter-object} identification of axes. Therefore, working with observables allows to work independently of the underlying data ordering. \item[Axes] Axes are integers and are used to \textit{enumerate the axes of a coordinate system}. This corresponds to indices of an array and provides the fully order-based mapping necessary for \textit{intra-object} manipulations. For example, a \zdata{} with three columns has three axes, 0, 1, and 2, which can though be reordered so that the corresponding observables match the order of some other observables. \item[Limits] A description of boundaries that can be used to define any kind of limits of the axes. Currently only rectangular limits are supported but arbitrary shaped limits will be provided in the future. \end{description} A \zspace{} can be initialized with observables and limits to define a domain. When it's assigned to an object, it automatically connects the axes of the object with the observables from the \zspace{}. More details on the implementation and use cases as well as additional functionality for dimensional handling can be found in Appendix \ref{appendix:spaces defined}. \subsubsection{Limits} \label{sec:multiple limits} Limits are used in many instances, be it in sampling limits, integration or data limits. A \zspace{} not only defines the observables but typically also has limits associated with it. In one-dimensional fits, limits as seen in the example in Sec. \ref{sec:quickstart} are needed. Simple limits consist of a tuple for each observable with lower and upper limits. For example a \zspace{} in one observable \texttt{x} from $-5$ to $3$ can be created like \begin{center} \begin{minipage}{\textwidth} \begin{python} limits = zfit.Space(obs="x", limits=(-5, 3)) \end{python} \end{minipage} \end{center} This is the simplest way of specifying limits and rather a special case. For anything more sophisticated, such as multiple limits or multiple observables, either a composition of \zspace s or the more general format as explained in Appendix \ref{appendix:general limits} has to be used. For example when blinding a region, a \zspace{} with multiple limits can be used. While the general format is fully specified independent of a \zspace{} and can therefore be useful programmatically, a \zspace{} with multiple limits can be built unambiguously from \zspace s with simple limits by adding them, either through a dedicated \zfit{} function or using the addition operator in Python. In this way, multiple limits can be created through simple composition and without the need of using the more general format. As an example, let's assume a \zspace{} should be created with the observables \texttt{x, y} in the two domains $l_01$ and $l_23$ \begin{align*} l_01 &= \{(x, y) | x_0 < x < x_1, y_0 < y < y_1\} \\ l_23 &= \{(x, y) | x_2 < x < x_3, y_2 < y < y_3\}. \end{align*} We start out creating the domains by specifying the limits in the \textit{x} observable \begin{center} \begin{minipage}{\textwidth} \begin{python} limit_x_01 = zfit.Space(obs="x", limits=(x0, x1)) limit_x_23 = zfit.Space(obs="x", limits=(x2, x3)) limits_x = limit_x_01 + limit_x_23 \end{python} \end{minipage} \end{center} Equivalently \pyth{limits_y} can be composed. Since going to higher dimensions is unambiguous with two limits in each space, this can be done using the multiplication operator in Python or the function \pyth{combine}.\footnote{If a different number of limits were defined, an error would be thrown.} \begin{center} \begin{minipage}{\textwidth} \begin{python} limits_xy = limits_x * limits_y limits_yx = limits_y * limits_x \end{python} \end{minipage} \end{center} The difference between \pyth{limits_xy} and \pyth{limits_yx} is the order of the observables. In the first case, it's \pyth{["x", "y"]} while for the latter it's \pyth{["y", "x"]}. In order to ensure consistency, if the two \zspace s already have observables in common, the limits in this observables have to be the same. \footnote{This exact behaviour of the multiplication and observables is the same if models are multiplied.} Reordering the \zspace{} is possible as well as extracting a subspace, a \zspace{} only defined in subset of the dimensions. More details can be found in Appendix \ref{appendix:spaces defined}.