def __init__(self, *spaces, **kwargs):
        r"""Initialize a new instance.

        Parameters
        ----------
        space1,...,spaceN : `LinearSpace` or int
            The individual spaces ("factors / parts") in the product
            space. Can also be given as ``space, n`` with ``n`` integer,
            in which case the power space ``space ** n`` is created.
        exponent : non-zero float or ``float('inf')``, optional
            Order of the product distance/norm, i.e.

            ``dist(x, y) = np.linalg.norm(x-y, ord=exponent)``

            ``norm(x) = np.linalg.norm(x, ord=exponent)``

            Values ``0 <= exponent < 1`` are currently unsupported
            due to numerical instability. See ``Notes`` for further
            information about the interpretation of the values.

            Default: 2.0

        field : `Field`, optional
            Scalar field of the resulting space.
            Default: ``spaces[0].field``

        weighting : optional
            Use weighted inner product, norm, and dist. The following
            types are supported as ``weighting``:

            ``None`` : no weighting (default)

            `Weighting` : weighting class, used directly. Such a
            class instance can be retrieved from the space by the
            `ProductSpace.weighting` property.

            `array-like` : weigh each component with one entry from the
            array. The array must be one-dimensional and have the same
            length as the number of spaces.

            float : same weighting factor in each component

        Other Parameters
        ----------------
        dist : callable, optional
            The distance function defining a metric on the space.
            It must accept two `ProductSpaceElement` arguments and
            fulfill the following mathematical conditions for any
            three space elements ``x, y, z``:

            - ``dist(x, y) >= 0``
            - ``dist(x, y) = 0``  if and only if  ``x = y``
            - ``dist(x, y) = dist(y, x)``
            - ``dist(x, y) <= dist(x, z) + dist(z, y)``

            By default, ``dist(x, y)`` is calculated as ``norm(x - y)``.

            Cannot be combined with: ``weighting, norm, inner``

        norm : callable, optional
            The norm implementation. It must accept an
            `ProductSpaceElement` argument, return a float and satisfy the
            following conditions for all space elements ``x, y`` and scalars
            ``s``:

            - ``||x|| >= 0``
            - ``||x|| = 0``  if and only if  ``x = 0``
            - ``||s * x|| = |s| * ||x||``
            - ``||x + y|| <= ||x|| + ||y||``

            By default, ``norm(x)`` is calculated as ``inner(x, x)``.

            Cannot be combined with: ``weighting, dist, inner``

        inner : callable, optional
            The inner product implementation. It must accept two
            `ProductSpaceElement` arguments, return a element from
            the field of the space (real or complex number) and
            satisfy the following conditions for all space elements
            ``x, y, z`` and scalars ``s``:

            - ``<x, y> = conj(<y, x>)``
            - ``<s*x + y, z> = s * <x, z> + <y, z>``
            - ``<x, x> = 0``  if and only if  ``x = 0``

            Cannot be combined with: ``weighting, dist, norm``

        Examples
        --------
        Product of two rn spaces

        >>> r2x3 = ProductSpace(odl.rn(2), odl.rn(3))

        Powerspace of rn space

        >>> r2x2x2 = ProductSpace(odl.rn(2), 3)

        Notes
        -----
        Inner product, norm and distance are evaluated by collecting
        the result of the corresponding operation in the individual
        components and reducing the resulting vector to a single number.
        The ``exponent`` parameter influences only this last part,
        not the computations in the individual components. We give the
        exact definitions in the following:

        Let :math:`\mathcal{X} = \mathcal{X}_1 \times \dots \times
        \mathcal{X}_d` be a product space, and
        :math:`\langle \cdot, \cdot\rangle_i`,
        :math:`\lVert \cdot \rVert_i`, :math:`d_i(\cdot, \cdot)` be
        inner products, norms and distances in the respective
        component spaces.

        **Inner product:**

        .. math::
            \langle x, y \rangle = \sum_{i=1}^d \langle x_i, y_i \rangle_i

        **Norm:**

        - :math:`p < \infty`:

        .. math::
            \lVert x\rVert =
            \left( \sum_{i=1}^d \lVert x_i \rVert_i^p \right)^{1/p}

        - :math:`p = \infty`:

        .. math::
            \lVert x\rVert = \max_i \lVert x_i \rVert_i

        **Distance:**

        - :math:`p < \infty`:

        .. math::
            d(x, y) = \left( \sum_{i=1}^d d_i(x_i, y_i)^p \right)^{1/p}

        - :math:`p = \infty`:

        .. math::
            d(x, y) = \max_i d_i(x_i, y_i)

        To implement own versions of these functions, you can use
        the following snippet to gather the vector of norms (analogously
        for inner products and distances)::

            norms = np.fromiter(
                (xi.norm() for xi in x),
                dtype=np.float64, count=len(x))

        See Also
        --------
        ProductSpaceArrayWeighting
        ProductSpaceConstWeighting
        """
        field = kwargs.pop('field', None)
        dist = kwargs.pop('dist', None)
        norm = kwargs.pop('norm', None)
        inner = kwargs.pop('inner', None)
        weighting = kwargs.pop('weighting', None)
        exponent = float(kwargs.pop('exponent', 2.0))
        if kwargs:
            raise TypeError('got unexpected keyword arguments: {}'
                            ''.format(kwargs))

        # Check validity of option combination (3 or 4 out of 4 must be None)
        if sum(x is None for x in (dist, norm, inner, weighting)) < 3:
            raise ValueError('invalid combination of options weighting, '
                             'dist, norm and inner')

        if any(x is not None for x in (dist, norm, inner)) and exponent != 2.0:
            raise ValueError('`exponent` cannot be used together with '
                             'inner, norm or dist')

        # Make a power space if the second argument is an integer.
        # For the case that the integer is 0, we already set the field here.
        if len(spaces) == 2 and isinstance(spaces[1], Integral):
            field = spaces[0].field
            spaces = [spaces[0]] * spaces[1]

        # Validate the space arguments
        if not all(isinstance(spc, LinearSpace) for spc in spaces):
            raise TypeError(
                'all arguments must be `LinearSpace` instances, or the '
                'first argument must be `LinearSpace` and the second '
                'integer; got {!r}'.format(spaces))
        if not all(spc.field == spaces[0].field for spc in spaces):
            raise ValueError('all spaces must have the same field')

        # Assign spaces and field
        self.__spaces = tuple(spaces)

        # Cache for efficiency
        self.__is_power_space = all(spc == self.spaces[0]
                                    for spc in self.spaces[1:])

        # Assing or infer field
        if field is None:
            if len(self) == 0:
                raise ValueError('no spaces provided, cannot deduce field')
            else:
                field = self.spaces[0].field

        super(ProductSpace, self).__init__(field)

        # Assign weighting
        if weighting is not None:
            if isinstance(weighting, Weighting):
                self.__weighting = weighting
            elif np.isscalar(weighting):
                self.__weighting = ProductSpaceConstWeighting(
                    weighting, exponent)
            elif weighting is None:
                # Need to wait until dist, norm and inner are handled
                pass
            else:  # last possibility: make a product space element
                arr = np.asarray(weighting)
                if arr.dtype == object:
                    raise ValueError('invalid weighting argument {}'
                                     ''.format(weighting))
                if arr.ndim == 1:
                    self.__weighting = ProductSpaceArrayWeighting(
                        arr, exponent)
                else:
                    raise ValueError('weighting array has {} dimensions, '
                                     'expected 1'.format(arr.ndim))

        elif dist is not None:
            self.__weighting = ProductSpaceCustomDist(dist)
        elif norm is not None:
            self.__weighting = ProductSpaceCustomNorm(norm)
        elif inner is not None:
            self.__weighting = ProductSpaceCustomInner(inner)
        else:  # all None -> no weighing
            self.__weighting = ProductSpaceConstWeighting(1.0, exponent)
def __init__ ( self , * spaces , ** kwargs ) : field = kwargs . pop ( 'field' , None ) dist = kwargs . pop ( 'dist' , None ) norm = kwargs . pop ( 'norm' , None ) inner = kwargs . pop ( 'inner' , None ) weighting = kwargs . pop ( 'weighting' , None ) exponent = float ( kwargs . pop ( 'exponent' , 2.0 ) ) if kwargs : raise TypeError ( 'got unexpected keyword arguments: {}' '' . format ( kwargs ) ) if sum ( x is None for x in ( dist , norm , inner , weighting ) ) < 3 : raise ValueError ( 'invalid combination of options weighting, ' 'dist, norm and inner' ) if any ( x is not None for x in ( dist , norm , inner ) ) and exponent != 2.0 : raise ValueError ( '`exponent` cannot be used together with ' 'inner, norm or dist' ) if len ( spaces ) == 2 and isinstance ( spaces [ 1 ] , Integral ) : field = spaces [ 0 ] . field spaces = [ spaces [ 0 ] ] * spaces [ 1 ] if not all ( isinstance ( spc , LinearSpace ) for spc in spaces ) : raise TypeError ( 'all arguments must be `LinearSpace` instances, or the ' 'first argument must be `LinearSpace` and the second ' 'integer; got {!r}' . format ( spaces ) ) if not all ( spc . field == spaces [ 0 ] . field for spc in spaces ) : raise ValueError ( 'all spaces must have the same field' ) self . __spaces = tuple ( spaces ) self . __is_power_space = all ( spc == self . spaces [ 0 ] for spc in self . spaces [ 1 : ] ) if field is None : if len ( self ) == 0 : raise ValueError ( 'no spaces provided, cannot deduce field' ) else : field = self . spaces [ 0 ] . field super ( ProductSpace , self ) . __init__ ( field ) if weighting is not None : if isinstance ( weighting , Weighting ) : self . __weighting = weighting elif np . isscalar ( weighting ) : self . __weighting = ProductSpaceConstWeighting ( weighting , exponent ) elif weighting is None : pass else : arr = np . asarray ( weighting ) if arr . dtype == object : raise ValueError ( 'invalid weighting argument {}' '' . format ( weighting ) ) if arr . ndim == 1 : self . __weighting = ProductSpaceArrayWeighting ( arr , exponent ) else : raise ValueError ( 'weighting array has {} dimensions, ' 'expected 1' . format ( arr . ndim ) ) elif dist is not None : self . __weighting = ProductSpaceCustomDist ( dist ) elif norm is not None : self . __weighting = ProductSpaceCustomNorm ( norm ) elif inner is not None : self . __weighting = ProductSpaceCustomInner ( inner ) else : self . __weighting = ProductSpaceConstWeighting ( 1.0 , exponent )
r"""Initialize a new instance.

        Parameters
        ----------
        space1,...,spaceN : `LinearSpace` or int
            The individual spaces ("factors / parts") in the product
            space. Can also be given as ``space, n`` with ``n`` integer,
            in which case the power space ``space ** n`` is created.
        exponent : non-zero float or ``float('inf')``, optional
            Order of the product distance/norm, i.e.

            ``dist(x, y) = np.linalg.norm(x-y, ord=exponent)``

            ``norm(x) = np.linalg.norm(x, ord=exponent)``

            Values ``0 <= exponent < 1`` are currently unsupported
            due to numerical instability. See ``Notes`` for further
            information about the interpretation of the values.

            Default: 2.0

        field : `Field`, optional
            Scalar field of the resulting space.
            Default: ``spaces[0].field``

        weighting : optional
            Use weighted inner product, norm, and dist. The following
            types are supported as ``weighting``:

            ``None`` : no weighting (default)

            `Weighting` : weighting class, used directly. Such a
            class instance can be retrieved from the space by the
            `ProductSpace.weighting` property.

            `array-like` : weigh each component with one entry from the
            array. The array must be one-dimensional and have the same
            length as the number of spaces.

            float : same weighting factor in each component

        Other Parameters
        ----------------
        dist : callable, optional
            The distance function defining a metric on the space.
            It must accept two `ProductSpaceElement` arguments and
            fulfill the following mathematical conditions for any
            three space elements ``x, y, z``:

            - ``dist(x, y) >= 0``
            - ``dist(x, y) = 0``  if and only if  ``x = y``
            - ``dist(x, y) = dist(y, x)``
            - ``dist(x, y) <= dist(x, z) + dist(z, y)``

            By default, ``dist(x, y)`` is calculated as ``norm(x - y)``.

            Cannot be combined with: ``weighting, norm, inner``

        norm : callable, optional
            The norm implementation. It must accept an
            `ProductSpaceElement` argument, return a float and satisfy the
            following conditions for all space elements ``x, y`` and scalars
            ``s``:

            - ``||x|| >= 0``
            - ``||x|| = 0``  if and only if  ``x = 0``
            - ``||s * x|| = |s| * ||x||``
            - ``||x + y|| <= ||x|| + ||y||``

            By default, ``norm(x)`` is calculated as ``inner(x, x)``.

            Cannot be combined with: ``weighting, dist, inner``

        inner : callable, optional
            The inner product implementation. It must accept two
            `ProductSpaceElement` arguments, return a element from
            the field of the space (real or complex number) and
            satisfy the following conditions for all space elements
            ``x, y, z`` and scalars ``s``:

            - ``<x, y> = conj(<y, x>)``
            - ``<s*x + y, z> = s * <x, z> + <y, z>``
            - ``<x, x> = 0``  if and only if  ``x = 0``

            Cannot be combined with: ``weighting, dist, norm``

        Examples
        --------
        Product of two rn spaces

        >>> r2x3 = ProductSpace(odl.rn(2), odl.rn(3))

        Powerspace of rn space

        >>> r2x2x2 = ProductSpace(odl.rn(2), 3)

        Notes
        -----
        Inner product, norm and distance are evaluated by collecting
        the result of the corresponding operation in the individual
        components and reducing the resulting vector to a single number.
        The ``exponent`` parameter influences only this last part,
        not the computations in the individual components. We give the
        exact definitions in the following:

        Let :math:`\mathcal{X} = \mathcal{X}_1 \times \dots \times
        \mathcal{X}_d` be a product space, and
        :math:`\langle \cdot, \cdot\rangle_i`,
        :math:`\lVert \cdot \rVert_i`, :math:`d_i(\cdot, \cdot)` be
        inner products, norms and distances in the respective
        component spaces.

        **Inner product:**

        .. math::
            \langle x, y \rangle = \sum_{i=1}^d \langle x_i, y_i \rangle_i

        **Norm:**

        - :math:`p < \infty`:

        .. math::
            \lVert x\rVert =
            \left( \sum_{i=1}^d \lVert x_i \rVert_i^p \right)^{1/p}

        - :math:`p = \infty`:

        .. math::
            \lVert x\rVert = \max_i \lVert x_i \rVert_i

        **Distance:**

        - :math:`p < \infty`:

        .. math::
            d(x, y) = \left( \sum_{i=1}^d d_i(x_i, y_i)^p \right)^{1/p}

        - :math:`p = \infty`:

        .. math::
            d(x, y) = \max_i d_i(x_i, y_i)

        To implement own versions of these functions, you can use
        the following snippet to gather the vector of norms (analogously
        for inner products and distances)::

            norms = np.fromiter(
                (xi.norm() for xi in x),
                dtype=np.float64, count=len(x))

        See Also
        --------
        ProductSpaceArrayWeighting
        ProductSpaceConstWeighting