<commit_before># Copyright 2014, 2015 The ODL development group
#
# This file is part of ODL.
#
# ODL is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ODL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with ODL.  If not, see <http://www.gnu.org/licenses/>.

"""Abstract vector spaces.

The classes in this module represent abstract mathematical concepts
of vector spaces. They cannot be used directly but are rather intended
to be subclassed by concrete space implementations. The spaces
provide default implementations of the most important vector space
operations. See the documentation of the respective classes for more
details.

Class descriptions
------------------

+--------------+-------------+----------------------------------------+
|Class name    |Direct       |Description                             |
|              |ancestors    |                                        |
+==============+=============+========================================+
|`LinearSpace` |`Set`        |**Abstract class.** A vector space over |
|              |             |a field (real or complex numbers)       |
|              |             |defining a vector-vector addition and a |
|              |             |scalar-vector multiplication with       |
|              |             |certain properties. See the article     |
|              |             |`Vector space`_ on Wikipedia for further|
|              |             |information.                            |
+--------------+-------------+----------------------------------------+
|`MetricSpace` |`LinearSpace`|**Abstract class.** A vector space with |
|              |             |a metric, i.e. a `dist` function        |
|              |             |measuring the distance between two      |
|              |             |vectors.                                |
+--------------+-------------+----------------------------------------+
|`NormedSpace` |`MetricSpace`|**Abstract class.** A metric space with |
|              |             |a `norm` function measuring the length  |
|              |             |a vector. The `dist` function is induced|
|              |             |by the norm as                          |
|              |             |`dist(x, y) = norm(x - y)`.             |
+--------------+-------------+----------------------------------------+
|`HilbertSpace`|`NormedSpace`|**Abstract class.** A normed space with |
|              |             |an inner product measuring angles       |
|              |             |between vectors with unit length. The   |
|              |             |`norm` function is induced by the inner |
|              |             |product by the according to             |
|              |             |`norm(x) = inner(x, x)`.                |
+--------------+-------------+----------------------------------------+
|`Algebra`     |`LinearSpace`|**Abstract class.** A linear space with |
|              |             |a vector-vector multiplication under    |
|              |             |which the space is closed. See the      |
|              |             |Algebra_ article on Wikipedia for       |
|              |             |further information. (Note that we      |
|              |             |assume commutativity and unitality.)    |
+--------------+-------------+----------------------------------------+

See also
--------
The `Set` class is defined in `odl.space.set`.

.. _Vector space: https://en.wikipedia.org/wiki/Vector_space#Definition
.. _Algebra: https://en.wikipedia.org/wiki/Associative_algebra
"""

# Imports for common Python 2/3 codebase
from __future__ import (unicode_literals, print_function, division,
                        absolute_import)
from builtins import object, str, super
from future import standard_library
from future.utils import with_metaclass

# External module imports
from abc import ABCMeta, abstractmethod, abstractproperty
from math import sqrt

# ODL imports
from odl.space.set import Set
from odl.utility.utility import errfmt

standard_library.install_aliases()

#__all__ = ('LinearSpace')


class LinearSpace(Set):

    """Abstract linear vector space.

    Its elements are represented as instances of the inner
    `LinearSpace.Vector` class.

    The concept of linear vector spaces in ODL is largely inspired by
    the `Rice Vector Library`_ (RVL).

    The abstract `LinearSpace` class is intended for quick prototyping.
    It has a number of abstract methods which must be overridden by a
    subclass. On the other hand, it provides automatic error checking
    and numerous attributes and methods for convenience.

    In the following, the abstract methods are explained in detail.

    Abstract methods
    ----------------

    `element(inp=None)`
    ~~~~~~~~~~~~~~~~~~~~
    This public method is the factory for the inner
    `LinearSpace.Vector` class. It creates a new element of the space,
    either from scratch or from an existing data container. In the
    simplest possible case, it just delegates the construction to the
    `Vector` class.

    If no data is provided, the new element is **merely allocated, not
    initialized**, thus it can contain *any* value.

    **Parameters:**
        `inp` : `object`, optional
            A container for values for the element initialization

    **Returns:**
        `element` : `LinearSpace.Vector`
            The new vector.

    `_lincomb(z, a, x, b, y)`
    ~~~~~~~~~~~~~~~~~~~~~~~~~
    This private method is the raw implementation (i.e. no error
    checking) of the linear combination `z <-- a * x + b * y`.
    `_lincomb` and its public counterpart `lincomb` are used to cover
    a range of convenience functions, see below.

    **Parameters:**
        `z` : `LinearSpace.Vector`
            Element to which the result of the computation is written
        `a` : `LinearSpace.field` element
            Multiplicative scalar factor for input vector `x`
        `x` : `LinearSpace.Vector`
            First input vector
        `b` : `LinearSpace.field` element
            Multiplicative scalar factor for input vector `y`
        `y` : `LinearSpace.Vector`
            Second input vector

    **Returns:** `None`

    **Requirements:**
     * Aliasing of `x`, `y` and `z` **must** be allowed.
     * The input vectors `x` and `y` **must not** be modified.
     * The initial state of the output vector `z` **must not**
       influence the result.

    `field`
    ~~~~~~~
    The public attribute determining the type of scalars which
    underlie the space. Can be either `RealNumbers` or
    `ComplexNumbers` (see `odl.space.set`).

    Must be implemented as a `@property` to make it immutable.

    `equals(other)`
    ~~~~~~~~~~~~~~~
    `LinearSpace` inherits this abstract method from `Set`. Its
    purpose is to check two `LinearSpace` instances for equality.

    **Parameters:**
        `other` : `object`
            The object to compare to.

    **Returns:**
        `equals` : `boolean`
            `True` if `other` is the same `LinearSpace`, `False`
            otherwise.

    Optional methods
    ----------------

    `_dist(x, y)`
    ~~~~~~~~~~~~~
    A raw (not type-checking) private method measuring the distance
    between two vectors `x` and `y`.

    A space with a distance is called a Metric Space.

    **Parameters:**
        `x` : `object`
            The first vector
        `y` : `object`
            The second vector

    **Returns:**
        `distance` : `RealNumber`
            The distance between `x` and `y`, measured in the space's
            metric

    **Requirements:**
        * `_dist(x, y) == _dist(y, x)`
        * `_dist(x, y) <= _dist(x, z) + _dist(z, y)`
        * `_dist(x, y) >= 0`
        * `_dist(x, y) == 0` (approx.) if and only if `x == y` (approx.)

    `_norm(x)`
    ~~~~~~~~~~
    A raw (not type-checking) private method measuring the length of a
    space element `x`.

    A space with a norm is called a `Normed Space`.

    **Parameters:**
        `x` : ``object``
            The vector to measure

    **Returns:**
        `norm` : ``RealNumber``
            The length of `x` as measured in the space's metric

    **Requirements:**
     * `_norm(s * x) = |s| * _norm(x)` for any scalar `s`
     * `_norm(x + y) <= _norm(x) + _norm(y)`
     * `_norm(x) >= 0`
     * `_norm(x) == 0` (approx.) if and only if `x == 0` (approx.)

    Note
    ----
    A `Normed Space` is a `Metric Space` with the distance function
    `_dist(x, y) = _norm(x - y)`.


    `_inner(x, y)`
    ~~~~~~~~~~~~~~
    A raw (not type-checking) private method calculating the inner
    product of two space elements `x` and `y`.

    **Parameters:**
        `x` : `object`
            The first vector
        `y` : `object`
            The second vector

    **Returns:**
        `inner` : `space.field` element
            The inner product of `x` and `y`

    **Requirements:**
     * `_inner(x, y) == _inner(y, x)^*` with '*' = complex conjugation
     * `_inner(s * x, y) == s * _inner(x, y)` for `s` scalar
     * `_inner(x + z, y) == _inner(x, y) + _inner(z, y)`
     * `_inner(x, x) == 0` (approx.) if and only if `x == 0` (approx.)

    Note
    ----
    A `HilbertSpace` is a `NormedSpace` with the norm function
    `_norm(x) = sqrt(_inner(x, x))`, and in consequence also a
    `MetricSpace` with the distance function
    `_dist(x, y) = _norm(x - y)`.


    `_multiply(x, y)`
    ~~~~~~~~~~~~~~~~~
    A raw (not type-checking) private method multiplying two vectors
    `x` and `y`.

    **Parameters:**
        `x` : `object`
            First vector
        `y` : `object`
            Second vector, stores the final result

    **Returns:** `None`

    **Requirements:**
     * `y` after `_multiply(x, y)` equals `x` after `_multiply(y, x)`
     * `_multiply(s * x, y) <==> y *= s; _multiply(x, y)  <==>
        _multiply(x, y); y *= s` for `s` scalar
     * There is a space element `one` with
       `x` after `_multiply(one, x)` equals `x` equals `one`
       after `_multiply(x, one)`.

    Note
    ----
    The above conditions on the multiplication make `Algebra` a
    *unital commutative algebra* in the mathematical sense.


    Default convenience methods
    ---------------------------
    `LinearSpace` provides several default methods for convenience
    which use the abstract methods above. A subclass may override
    them with own implementations.

    +--------------+--------------------+-----------------------------+
    |Signature     |Return type         |Description                  |
    +==============+====================+=============================+
    |`lincomb(z, a,|`None`              |Linear combination           |
    |x, b, y)`     |                    |`z <-- a * x + b * y`. Like  |
    |              |                    |`_lincomb()`, but with type  |
    |              |                    |checks.                      |
    +--------------+--------------------+-----------------------------+
    |`zero()`      |`LinearSpace.Vector`|Create a zero vector by first|
    |              |                    |issuing `x = element()` and  |
    |              |                    |then                         |
    |              |                    |`_lincomb(x, 0, x, 0, x)`    |
    +--------------+--------------------+-----------------------------+    
    |Metric Space methods                                             |
    +--------------+--------------------+-----------------------------+    
    |`dist(x, y)`|`float`     |Distance between two space elements.   |
    |            |            |Like `_dist()`, but with type checks.  |
    +------------+------------+---------------------------------------+
    |Normed Space methods                                             |
    +-------------+------------+--------------------------------------+
    |`norm(x)`    |`float`     |Length of a space element. Like       |
    |             |            |`_norm()`, but with type checks.      |
    +-------------+------------+--------------------------------------+
    |Hilbert Space methods                                            |
    +-------------+------------+--------------------------------------+
    |`inner(x, y)`|`field`     |Inner product of two space elements.  |
    |             |element     |Like `_inner()`, but with type        |
    |             |            |checks.                               |
    +-------------+------------+--------------------------------------+
    |Algebra       methods                                            |
    +----------------+-----------+------------------------------------+
    |`multiply(x, y)`|`None`     |Multiplication of two space         |
    |                |           |elements. Like `_multiply()`, but   |
    |                |           |with type checks.                   |
    +----------------+-----------+------------------------------------+

    Magic methods
    -------------

    +----------------------+----------------+--------------------+
    |Signature             |Provides syntax |Implementation      |
    +======================+================+====================+
    |`__eq__(other)`       |`self == other` |`equals(other)`     |
    +----------------------+----------------+--------------------+
    |`__ne__(other)`       |`self != other` |`not equals(other)` |
    +----------------------+----------------+--------------------+
    |`__contains__(other)` |`other in self` |`contains(other)`   |
    +----------------------+----------------+--------------------+

    See also
    --------
    See Wikipedia's `Vector space`_ article for a mathematical
    overview.

    .. _`Rice Vector Library`:
       http://www.trip.caam.rice.edu/software/rvl/rvl/doc/html/
    .. _`Vector space`:
       https://en.wikipedia.org/wiki/Vector_space
    """

    @abstractmethod
    def element(self, inp=None):
        """Create an element from `inp` or from scratch.

        If called without `inp` argument, an arbitrary element in the
        space is generated without guarantee of its state.

        Parameters
        ----------
        inp : `object`, optional
            The input data from which to create the element

        Returns
        -------
        element : `LinearSpace.Vector`
            A vector in this space
        """

    @abstractmethod
    def _lincomb(self, z, a, x, b, y):
        """Calculate z = a*x + b*y.

        This method is intended to be private, public callers should
        resort to lincomb which is type-checked.
        """

    def _dist(self, x, y):
        """Calculate the distance between x and y.

        This method is intended to be private, public callers should
        resort to dist which is type-checked.
        """
        #default implementation
        return self.norm(x-y)

    
    def _norm(self, x):
        """Calculate the norm of x

        This method is intended to be private, public callers should
        resort to dist which is type-checked.
        """
        #default implementation
        return math.sqrt(self.inner(x,x))

    def _inner(self, x, y):
        """ Calculate the inner product of x and y

        This method is intended to be private, public callers should
        resort to dist which is type-checked.
        """
        #No default implementation possible
        raise NotImplementedError("Inner product not implemented")

    def _multiply(self, z, x, y):
        """ Calculate the multiplication of z = x * y

        This method is intended to be private, public callers should
        resort to dist which is type-checked.
        """
        #No default implementation possible
        raise NotImplementedError("Multiplication not implemented")

    @abstractproperty
    def field(self):
        """The field of the vector space."""

    # Default methods
    def zero(self):
        """A zero vector in this space.

        The zero vector is defined as the additive unit of a space.

        Parameters
        ----------
        None

        Returns
        -------
        v : Vector
            The zero vector of this space
        """
        # Default implementation using lincomb
        tmp = self.element()
        self._lincomb(tmp, 0, tmp, 0, tmp)
        return tmp

    def contains(self, other):
        """Test an object for membership in space.

        Parameters
        ----------
        other : `object`
            The object to test for membership

        Returns
        -------
        contains : `bool`
            True if `other` is a `LinearSpace.Vector` instance and
            `other.space` is equal to this space.

        Notes
        -----
        This is the strict default where spaces must be equal.
        Subclasses may choose to implement a less strict check.
        """
        return isinstance(other, LinearSpace.Vector) and other.space == self

    # Error checking variant of methods
    def lincomb(self, z, a, x, b=None, y=None):
        """Linear combination of vectors.

        Calculates

        z = a*x
        or if b and y are given
        z = a*x + b*y

        with error checking of types.

        Parameters
        ----------
        z : Vector
            The Vector that the result should be written to.
        a : Scalar in the field of this space
            Scalar to multiply `x` with.
        x : Vector
            The first of the summands
        b : Scalar, optional
            Scalar to multiply `y` with.
        y : Vector, optional
            The second of the summands

        Returns
        -------
        None

        Notes
        -----
        Some notes and examples

        Alignment
        ~~~~~~~~~
        The vectors `z`, `x` and `y` may be aligned, thus a call

        space.lincomb(x, 2, x, 3.14, x)

        is (mathematically) equivalent to

        x = x * (1 + 2 + 3.14)
        """
        if z not in self:
            raise TypeError(errfmt('''
            `z` {!r} not in space {!r}.'''.format(z, self)))

        if a not in self.field:
            raise TypeError(errfmt('''
            `a` {!r} not in `field` {!r} of space {!r}.
            '''.format(a, self.field, self)))

        if x not in self:
            raise TypeError(errfmt('''
            `x` {!r} not in space {!r}.'''.format(x, self)))

        if b is None:  # Single argument
            if y is not None:
                raise ValueError('`y` provided but not `b`.')

            # Call method
            return self._lincomb(z, a, x, 0, x)
        else:  # Two arguments
            if b not in self.field:
                raise TypeError(errfmt('''
                `b` {!r} not in `field` {!r} of space {!r}.
                '''.format(b, self.field, self)))

            if y not in self:
                raise TypeError(errfmt('''
                `y` {!r} not in space {!r}.'''.format(y, self)))

            # Call method
            return self._lincomb(z, a, x, b, y)

    def dist(self, x, y):
        """Calculate the distance between two vectors.

        Parameters
        ----------
        x : MetricSpace.Vector
            The first element

        y : MetricSpace.Vector
            The second element

        Returns
        -------
        dist : RealNumber
               Distance between vectors
        """
        if x not in self:
            raise TypeError('`x` {} not in space {}'.format(x, self))

        if y not in self:
            raise TypeError('`y` {} not in space {}'.format(y, self))

        return float(self._dist(x, y))

    def norm(self, vector):
        """Calculate the norm of a vector."""
        if not self.contains(vector):
            raise TypeError('x ({}) is not in space ({})'.format(vector, self))

        return float(self._norm(vector))

    def inner(self, x, y):
        """ Calculates the inner product of the vectors x and y
        """

        # Check spaces
        if not self.contains(x):
            raise TypeError('x ({}) is not in space ({})'.format(x, self))

        if not self.contains(y):
            raise TypeError('y ({}) is not in space ({})'.format(y, self))

        return self.field.element(self._inner(x, y))
    
    def multiply(self, z, x, y):
        """ Calculates the pointwise product of x and y and assigns it to y
        z = x * y
        """
        # Check spaces
        if not self.contains(x):
            raise TypeError('x ({}) is in wrong space'.format(x))

        if not self.contains(y):
            raise TypeError('y ({}) is in wrong space'.format(y))

        self._multiply(z, x, y)

    class Vector(with_metaclass(ABCMeta, object)):

        """Abstract `LinearSpace` element.<commit_msg>Fixed some hyperlinks<commit_after># Copyright 2014, 2015 The ODL development group
#
# This file is part of ODL.
#
# ODL is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# ODL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with ODL.  If not, see <http://www.gnu.org/licenses/>.

"""Abstract vector spaces.

The classes in this module represent abstract mathematical concepts
of vector spaces. They cannot be used directly but are rather intended
to be subclassed by concrete space implementations. The spaces
provide default implementations of the most important vector space
operations. See the documentation of the respective classes for more
details.

Class descriptions
------------------

+--------------+-------------+----------------------------------------+
|Class name    |Direct       |Description                             |
|              |ancestors    |                                        |
+==============+=============+========================================+
|`LinearSpace` |`Set`        |**Abstract class.** A vector space over |
|              |             |a field (real or complex numbers)       |
|              |             |defining a vector-vector addition and a |
|              |             |scalar-vector multiplication with       |
|              |             |certain properties. See the article     |
|              |             |`Vector space`_ on Wikipedia for further|
|              |             |information.                            |
+--------------+-------------+----------------------------------------+
|`MetricSpace` |`LinearSpace`|**Abstract class.** A vector space with |
|              |             |a metric, i.e. a `dist` function        |
|              |             |measuring the distance between two      |
|              |             |vectors.                                |
+--------------+-------------+----------------------------------------+
|`NormedSpace` |`MetricSpace`|**Abstract class.** A metric space with |
|              |             |a `norm` function measuring the length  |
|              |             |a vector. The `dist` function is induced|
|              |             |by the norm as                          |
|              |             |`dist(x, y) = norm(x - y)`.             |
+--------------+-------------+----------------------------------------+
|`HilbertSpace`|`NormedSpace`|**Abstract class.** A normed space with |
|              |             |an inner product measuring angles       |
|              |             |between vectors with unit length. The   |
|              |             |`norm` function is induced by the inner |
|              |             |product by the according to             |
|              |             |`norm(x) = inner(x, x)`.                |
+--------------+-------------+----------------------------------------+
|`Algebra`     |`LinearSpace`|**Abstract class.** A linear space with |
|              |             |a vector-vector multiplication under    |
|              |             |which the space is closed. See the      |
|              |             |Algebra_ article on Wikipedia for       |
|              |             |further information. (Note that we      |
|              |             |assume commutativity and unitality.)    |
+--------------+-------------+----------------------------------------+

See also
--------
The `Set` class is defined in `odl.space.set`.

.. _Vector space: https://en.wikipedia.org/wiki/Vector_space#Definition
.. _Algebra: https://en.wikipedia.org/wiki/Associative_algebra
"""

# Imports for common Python 2/3 codebase
from __future__ import (unicode_literals, print_function, division,
                        absolute_import)
from builtins import object, str, super
from future import standard_library
from future.utils import with_metaclass

# External module imports
from abc import ABCMeta, abstractmethod, abstractproperty
from math import sqrt

# ODL imports
from odl.space.set import Set
from odl.utility.utility import errfmt

standard_library.install_aliases()

#__all__ = ('LinearSpace')


class LinearSpace(Set):

    """Abstract linear vector space.

    Its elements are represented as instances of the inner
    `LinearSpace.Vector` class.

    The concept of linear vector spaces in ODL is largely inspired by
    the `Rice Vector Library
    <http://www.trip.caam.rice.edu/software/rvl/rvl/doc/html/>`_ (RVL).

    The abstract `LinearSpace` class is intended for quick prototyping.
    It has a number of abstract methods which must be overridden by a
    subclass. On the other hand, it provides automatic error checking
    and numerous attributes and methods for convenience.

    In the following, the abstract methods are explained in detail.

    Abstract methods
    ----------------

    `element(inp=None)`
    ~~~~~~~~~~~~~~~~~~~~
    This public method is the factory for the inner
    `LinearSpace.Vector` class. It creates a new element of the space,
    either from scratch or from an existing data container. In the
    simplest possible case, it just delegates the construction to the
    `Vector` class.

    If no data is provided, the new element is **merely allocated, not
    initialized**, thus it can contain *any* value.

    **Parameters:**
        `inp` : `object`, optional
            A container for values for the element initialization

    **Returns:**
        `element` : `LinearSpace.Vector`
            The new vector.

    `_lincomb(z, a, x, b, y)`
    ~~~~~~~~~~~~~~~~~~~~~~~~~
    This private method is the raw implementation (i.e. no error
    checking) of the linear combination `z <-- a * x + b * y`.
    `_lincomb` and its public counterpart `lincomb` are used to cover
    a range of convenience functions, see below.

    **Parameters:**
        `z` : `LinearSpace.Vector`
            Element to which the result of the computation is written
        `a` : `LinearSpace.field` element
            Multiplicative scalar factor for input vector `x`
        `x` : `LinearSpace.Vector`
            First input vector
        `b` : `LinearSpace.field` element
            Multiplicative scalar factor for input vector `y`
        `y` : `LinearSpace.Vector`
            Second input vector

    **Returns:** `None`

    **Requirements:**
     * Aliasing of `x`, `y` and `z` **must** be allowed.
     * The input vectors `x` and `y` **must not** be modified.
     * The initial state of the output vector `z` **must not**
       influence the result.

    `field`
    ~~~~~~~
    The public attribute determining the type of scalars which
    underlie the space. Can be either `RealNumbers` or
    `ComplexNumbers` (see `odl.space.set`).

    Must be implemented as a `@property` to make it immutable.

    `equals(other)`
    ~~~~~~~~~~~~~~~
    `LinearSpace` inherits this abstract method from `Set`. Its
    purpose is to check two `LinearSpace` instances for equality.

    **Parameters:**
        `other` : `object`
            The object to compare to.

    **Returns:**
        `equals` : `boolean`
            `True` if `other` is the same `LinearSpace`, `False`
            otherwise.

    Optional methods
    ----------------

    `_dist(x, y)`
    ~~~~~~~~~~~~~
    A raw (not type-checking) private method measuring the distance
    between two vectors `x` and `y`.

    A space with a distance is called a Metric Space.

    **Parameters:**
        `x` : `object`
            The first vector
        `y` : `object`
            The second vector

    **Returns:**
        `distance` : `RealNumber`
            The distance between `x` and `y`, measured in the space's
            metric

    **Requirements:**
        * `_dist(x, y) == _dist(y, x)`
        * `_dist(x, y) <= _dist(x, z) + _dist(z, y)`
        * `_dist(x, y) >= 0`
        * `_dist(x, y) == 0` (approx.) if and only if `x == y` (approx.)

    `_norm(x)`
    ~~~~~~~~~~
    A raw (not type-checking) private method measuring the length of a
    space element `x`.

    A space with a norm is called a `Normed Space`.

    **Parameters:**
        `x` : ``object``
            The vector to measure

    **Returns:**
        `norm` : ``RealNumber``
            The length of `x` as measured in the space's metric

    **Requirements:**
     * `_norm(s * x) = |s| * _norm(x)` for any scalar `s`
     * `_norm(x + y) <= _norm(x) + _norm(y)`
     * `_norm(x) >= 0`
     * `_norm(x) == 0` (approx.) if and only if `x == 0` (approx.)

    Note
    ----
    A `Normed Space` is a `Metric Space` with the distance function
    `_dist(x, y) = _norm(x - y)`.


    `_inner(x, y)`
    ~~~~~~~~~~~~~~
    A raw (not type-checking) private method calculating the inner
    product of two space elements `x` and `y`.

    **Parameters:**
        `x` : `object`
            The first vector
        `y` : `object`
            The second vector

    **Returns:**
        `inner` : `space.field` element
            The inner product of `x` and `y`

    **Requirements:**
     * `_inner(x, y) == _inner(y, x)^*` with '*' = complex conjugation
     * `_inner(s * x, y) == s * _inner(x, y)` for `s` scalar
     * `_inner(x + z, y) == _inner(x, y) + _inner(z, y)`
     * `_inner(x, x) == 0` (approx.) if and only if `x == 0` (approx.)

    Note
    ----
    A `HilbertSpace` is a `NormedSpace` with the norm function
    `_norm(x) = sqrt(_inner(x, x))`, and in consequence also a
    `MetricSpace` with the distance function
    `_dist(x, y) = _norm(x - y)`.


    `_multiply(x, y)`
    ~~~~~~~~~~~~~~~~~
    A raw (not type-checking) private method multiplying two vectors
    `x` and `y`.

    **Parameters:**
        `x` : `object`
            First vector
        `y` : `object`
            Second vector, stores the final result

    **Returns:** `None`

    **Requirements:**
     * `y` after `_multiply(x, y)` equals `x` after `_multiply(y, x)`
     * `_multiply(s * x, y) <==> y *= s; _multiply(x, y)  <==>
        _multiply(x, y); y *= s` for `s` scalar
     * There is a space element `one` with
       `x` after `_multiply(one, x)` equals `x` equals `one`
       after `_multiply(x, one)`.

    Note
    ----
    The above conditions on the multiplication make `Algebra` a
    *unital commutative algebra* in the mathematical sense.


    Default convenience methods
    ---------------------------
    `LinearSpace` provides several default methods for convenience
    which use the abstract methods above. A subclass may override
    them with own implementations.

    +--------------+--------------------+-----------------------------+
    |Signature     |Return type         |Description                  |
    +==============+====================+=============================+
    |`lincomb(z, a,|`None`              |Linear combination           |
    |x, b, y)`     |                    |`z <-- a * x + b * y`. Like  |
    |              |                    |`_lincomb()`, but with type  |
    |              |                    |checks.                      |
    +--------------+--------------------+-----------------------------+
    |`zero()`      |`LinearSpace.Vector`|Create a zero vector by first|
    |              |                    |issuing `x = element()` and  |
    |              |                    |then                         |
    |              |                    |`_lincomb(x, 0, x, 0, x)`    |
    +--------------+--------------------+-----------------------------+
    |Metric Space methods                                             |
    +--------------+--------------------+-----------------------------+
    |`dist(x, y)`|`float`     |Distance between two space elements.   |
    |            |            |Like `_dist()`, but with type checks.  |
    +------------+------------+---------------------------------------+
    |Normed Space methods                                             |
    +-------------+------------+--------------------------------------+
    |`norm(x)`    |`float`     |Length of a space element. Like       |
    |             |            |`_norm()`, but with type checks.      |
    +-------------+------------+--------------------------------------+
    |Hilbert Space methods                                            |
    +-------------+------------+--------------------------------------+
    |`inner(x, y)`|`field`     |Inner product of two space elements.  |
    |             |element     |Like `_inner()`, but with type        |
    |             |            |checks.                               |
    +-------------+------------+--------------------------------------+
    |Algebra       methods                                            |
    +----------------+-----------+------------------------------------+
    |`multiply(x, y)`|`None`     |Multiplication of two space         |
    |                |           |elements. Like `_multiply()`, but   |
    |                |           |with type checks.                   |
    +----------------+-----------+------------------------------------+

    Magic methods
    -------------

    +----------------------+----------------+--------------------+
    |Signature             |Provides syntax |Implementation      |
    +======================+================+====================+
    |`__eq__(other)`       |`self == other` |`equals(other)`     |
    +----------------------+----------------+--------------------+
    |`__ne__(other)`       |`self != other` |`not equals(other)` |
    +----------------------+----------------+--------------------+
    |`__contains__(other)` |`other in self` |`contains(other)`   |
    +----------------------+----------------+--------------------+

    Notes
    -----
    See Wikipedia's `Vector space
    <https://en.wikipedia.org/wiki/Vector_space>`_ mathematical
    overview article
    """

    @abstractmethod
    def element(self, inp=None):
        """Create an element from `inp` or from scratch.

        If called without `inp` argument, an arbitrary element in the
        space is generated without guarantee of its state.

        Parameters
        ----------
        inp : `object`, optional
            The input data from which to create the element

        Returns
        -------
        element : `LinearSpace.Vector`
            A vector in this space
        """

    @abstractmethod
    def _lincomb(self, z, a, x, b, y):
        """Calculate z = a*x + b*y.

        This method is intended to be private, public callers should
        resort to lincomb which is type-checked.
        """

    def _dist(self, x, y):
        """Calculate the distance between x and y.

        This method is intended to be private, public callers should
        resort to dist which is type-checked.
        """
        #default implementation
        return self.norm(x-y)


    def _norm(self, x):
        """Calculate the norm of x

        This method is intended to be private, public callers should
        resort to dist which is type-checked.
        """
        #default implementation
        return math.sqrt(self.inner(x,x))

    def _inner(self, x, y):
        """ Calculate the inner product of x and y

        This method is intended to be private, public callers should
        resort to dist which is type-checked.
        """
        #No default implementation possible
        raise NotImplementedError("Inner product not implemented")

    def _multiply(self, z, x, y):
        """ Calculate the multiplication of z = x * y

        This method is intended to be private, public callers should
        resort to dist which is type-checked.
        """
        #No default implementation possible
        raise NotImplementedError("Multiplication not implemented")

    @abstractproperty
    def field(self):
        """The field of the vector space."""

    # Default methods
    def zero(self):
        """A zero vector in this space.

        The zero vector is defined as the additive unit of a space.

        Parameters
        ----------
        None

        Returns
        -------
        v : Vector
            The zero vector of this space
        """
        # Default implementation using lincomb
        tmp = self.element()
        self._lincomb(tmp, 0, tmp, 0, tmp)
        return tmp

    def contains(self, other):
        """Test an object for membership in space.

        Parameters
        ----------
        other : `object`
            The object to test for membership

        Returns
        -------
        contains : `bool`
            True if `other` is a `LinearSpace.Vector` instance and
            `other.space` is equal to this space.

        Notes
        -----
        This is the strict default where spaces must be equal.
        Subclasses may choose to implement a less strict check.
        """
        return isinstance(other, LinearSpace.Vector) and other.space == self

    # Error checking variant of methods
    def lincomb(self, z, a, x, b=None, y=None):
        """Linear combination of vectors.

        Calculates

        z = a*x
        or if b and y are given
        z = a*x + b*y

        with error checking of types.

        Parameters
        ----------
        z : Vector
            The Vector that the result should be written to.
        a : Scalar in the field of this space
            Scalar to multiply `x` with.
        x : Vector
            The first of the summands
        b : Scalar, optional
            Scalar to multiply `y` with.
        y : Vector, optional
            The second of the summands

        Returns
        -------
        None

        Notes
        -----
        Some notes and examples

        Alignment
        ~~~~~~~~~
        The vectors `z`, `x` and `y` may be aligned, thus a call

        space.lincomb(x, 2, x, 3.14, x)

        is (mathematically) equivalent to

        x = x * (1 + 2 + 3.14)
        """
        if z not in self:
            raise TypeError(errfmt('''
            `z` {!r} not in space {!r}.'''.format(z, self)))

        if a not in self.field:
            raise TypeError(errfmt('''
            `a` {!r} not in `field` {!r} of space {!r}.
            '''.format(a, self.field, self)))

        if x not in self:
            raise TypeError(errfmt('''
            `x` {!r} not in space {!r}.'''.format(x, self)))

        if b is None:  # Single argument
            if y is not None:
                raise ValueError('`y` provided but not `b`.')

            # Call method
            return self._lincomb(z, a, x, 0, x)
        else:  # Two arguments
            if b not in self.field:
                raise TypeError(errfmt('''
                `b` {!r} not in `field` {!r} of space {!r}.
                '''.format(b, self.field, self)))

            if y not in self:
                raise TypeError(errfmt('''
                `y` {!r} not in space {!r}.'''.format(y, self)))

            # Call method
            return self._lincomb(z, a, x, b, y)

    def dist(self, x, y):
        """Calculate the distance between two vectors.

        Parameters
        ----------
        x : MetricSpace.Vector
            The first element

        y : MetricSpace.Vector
            The second element

        Returns
        -------
        dist : RealNumber
               Distance between vectors
        """
        if x not in self:
            raise TypeError('`x` {} not in space {}'.format(x, self))

        if y not in self:
            raise TypeError('`y` {} not in space {}'.format(y, self))

        return float(self._dist(x, y))

    def norm(self, vector):
        """Calculate the norm of a vector."""
        if not self.contains(vector):
            raise TypeError('x ({}) is not in space ({})'.format(vector, self))

        return float(self._norm(vector))

    def inner(self, x, y):
        """ Calculates the inner product of the vectors x and y
        """

        # Check spaces
        if not self.contains(x):
            raise TypeError('x ({}) is not in space ({})'.format(x, self))

        if not self.contains(y):
            raise TypeError('y ({}) is not in space ({})'.format(y, self))

        return self.field.element(self._inner(x, y))

    def multiply(self, z, x, y):
        """ Calculates the pointwise product of x and y and assigns it to y
        z = x * y
        """
        # Check spaces
        if not self.contains(x):
            raise TypeError('x ({}) is in wrong space'.format(x))

        if not self.contains(y):
            raise TypeError('y ({}) is in wrong space'.format(y))

        self._multiply(z, x, y)

    class Vector(with_metaclass(ABCMeta, object)):

        """Abstract `LinearSpace` element.
{'fraction_non_alphanumeric': 0.18454905119518608, 'fraction_numerical': 0.0015161924616806045, 'mean_word_length': 1.4539007092198581, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 15, 'https://': 6, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 34, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3782232', 'n_tokens_mistral': 11109, 'n_tokens_neox': 10578, 'n_words': 3967}