Esempio n. 1
0
def dspace_type(space, impl, dtype=None):
    """Select the correct corresponding n-tuples space.

    Parameters
    ----------
    space : `LinearSpace`
        Template space from which to infer an adequate data space. If
        it has a `LinearSpace.field` attribute, ``dtype`` must be
        consistent with it.
    impl : string
        Implementation backend for the data space
    dtype : `numpy.dtype`, optional
        Data type which the space is supposed to use. If ``None`` is
        given, the space type is purely determined from ``space`` and
        ``impl``. Otherwise, it must be compatible with the
        field of ``space``.

    Returns
    -------
    stype : type
        Space type selected after the space's field, the backend and
        the data type
    """
    spacetype_map = {RealNumbers: FN_IMPLS,
                     ComplexNumbers: FN_IMPLS,
                     type(None): NTUPLES_IMPLS}

    field_type = type(getattr(space, 'field', None))

    if dtype is None:
        pass
    elif is_real_floating_dtype(dtype):
        if field_type is None or field_type == ComplexNumbers:
            raise TypeError('real floating data type {!r} requires space '
                            'field to be of type RealNumbers, got {}'
                            ''.format(dtype, field_type))
    elif is_complex_floating_dtype(dtype):
        if field_type is None or field_type == RealNumbers:
            raise TypeError('complex floating data type {!r} requires space '
                            'field to be of type ComplexNumbers, got {!r}'
                            ''.format(dtype, field_type))
    elif is_scalar_dtype(dtype):
        if field_type == ComplexNumbers:
            raise TypeError('non-floating data type {!r} requires space field '
                            'to be of type RealNumbers, got {!r}'
                            .format(dtype, field_type))
    else:
        raise TypeError('non-scalar data type {!r} cannot be combined with '
                        'a `LinearSpace`'.format(dtype))

    stype = spacetype_map[field_type].get(impl, None)

    if stype is None:
        raise NotImplementedError('no corresponding data space available '
                                  'for space {!r} and implementation {!r}'
                                  ''.format(space, impl))
    return stype
Esempio n. 2
0
def dspace_type(space, impl, dtype=None):
    """Select the correct corresponding n-tuples space.

    Parameters
    ----------
    space : `object`
        The template space. If it has a ``field`` attribute,
        ``dtype`` must be consistent with it
    impl : {'numpy', 'cuda'}
        The backend for the data space
    dtype : `type`, optional
        Data type which the space is supposed to use. If `None`, the
        space type is purely determined from ``space`` and
        ``impl``. If given, it must be compatible with the
        field of ``space``. Non-floating types result in basic
        `Fn`-type spaces.

    Returns
    -------
    stype : `type`
        Space type selected after the space's field, the backend and
        the data type
    """
    impl_ = str(impl).lower()
    if impl_ not in ('numpy', 'cuda'):
        raise ValueError('implementation type {} not understood.'
                         ''.format(impl))

    if impl_ == 'cuda' and not CUDA_AVAILABLE:
        raise ValueError('CUDA implementation not available.')

    basic_map = {'numpy': Fn, 'cuda': CudaFn}

    spacetype_map = {
        'numpy': {RealNumbers: Rn, ComplexNumbers: Cn,
                  type(None): Ntuples},
        'cuda': {RealNumbers: CudaRn, ComplexNumbers: None,
                 type(None): CudaNtuples}
    }

    field_type = type(getattr(space, 'field', None))

    if dtype is None:
        stype = spacetype_map[impl_][field_type]
    elif is_real_floating_dtype(dtype):
        if field_type is None or field_type == ComplexNumbers:
            raise TypeError('real floating data type {!r} requires space '
                            'field to be of type `RealNumbers`, got {}.'
                            ''.format(dtype, field_type))
        stype = spacetype_map[impl_][field_type]
    elif is_complex_floating_dtype(dtype):
        if field_type is None or field_type == RealNumbers:
            raise TypeError('complex floating data type {!r} requires space '
                            'field to be of type `ComplexNumbers`, got {!r}.'
                            ''.format(dtype, field_type))
        stype = spacetype_map[impl_][field_type]
    elif is_scalar_dtype(dtype):
        if field_type == ComplexNumbers:
            raise TypeError('non-floating data type {!r} requires space field '
                            'to be of type `RealNumbers`, got {!r}.'
                            .format(dtype, field_type))
        elif field_type == RealNumbers:
            stype = basic_map[impl_]
        else:
            stype = spacetype_map[impl_][field_type]
    elif field_type is None:  # Only in this case are arbitrary types allowed
        stype = spacetype_map[impl_][field_type]
    else:
        raise TypeError('non-scalar data type {!r} cannot be combined with '
                        'a `LinearSpace`.'.format(dtype))

    if stype is None:
        raise NotImplementedError('no corresponding data space available '
                                  'for space {!r} and implementation {!r}.'
                                  ''.format(space, impl))
    return stype
Esempio n. 3
0
def dspace_type(space, impl, dtype=None):
    """Select the correct corresponding n-tuples space.

    Parameters
    ----------
    space :
        Template space from which to infer an adequate data space. If
        it has a `LinearSpace.field` attribute, ``dtype`` must be
        consistent with it.
    impl : {'numpy', 'cuda'}
        Implementation backend for the data space
    dtype : `type`, optional
        Data type which the space is supposed to use. If `None`, the
        space type is purely determined from ``space`` and
        ``impl``. If given, it must be compatible with the
        field of ``space``.

    Returns
    -------
    stype : `type`
        Space type selected after the space's field, the backend and
        the data type
    """
    impl, impl_in = str(impl).lower(), impl
    if impl not in ('numpy', 'cuda'):
        raise ValueError("`impl` '{}' not understood"
                         ''.format(impl_in))

    if impl == 'cuda' and not CUDA_AVAILABLE:
        raise ValueError("'cuda' implementation not available")

    basic_map = {'numpy': Fn, 'cuda': CudaFn}

    spacetype_map = {
        'numpy': {RealNumbers: Fn, ComplexNumbers: Fn,
                  type(None): Ntuples},
        'cuda': {RealNumbers: CudaFn, ComplexNumbers: None,
                 type(None): CudaNtuples}
    }

    field_type = type(getattr(space, 'field', None))

    if dtype is None:
        stype = spacetype_map[impl][field_type]

    elif is_real_floating_dtype(dtype):
        if field_type is None or field_type == ComplexNumbers:
            raise TypeError('real floating data type {!r} requires space '
                            'field to be of type RealNumbers, got {}'
                            ''.format(dtype, field_type))
        stype = spacetype_map[impl][field_type]
    elif is_complex_floating_dtype(dtype):
        if field_type is None or field_type == RealNumbers:
            raise TypeError('complex floating data type {!r} requires space '
                            'field to be of type ComplexNumbers, got {!r}'
                            ''.format(dtype, field_type))
        stype = spacetype_map[impl][field_type]
    elif is_scalar_dtype(dtype):
        if field_type == ComplexNumbers:
            raise TypeError('non-floating data type {!r} requires space field '
                            'to be of type RealNumbers, got {!r}'
                            .format(dtype, field_type))
        elif field_type == RealNumbers:
            stype = basic_map[impl]
        else:
            stype = spacetype_map[impl][field_type]
    elif field_type is None:  # Only in this case are arbitrary types allowed
        stype = spacetype_map[impl][field_type]
    else:
        raise TypeError('non-scalar data type {!r} cannot be combined with '
                        'a `LinearSpace`'.format(dtype))

    if stype is None:
        raise NotImplementedError('no corresponding data space available '
                                  'for space {!r} and implementation {!r}'
                                  ''.format(space, impl))
    return stype
Esempio n. 4
0
def test_is_complex_floating_dtype():
    for dtype in complex_float_dtypes:
        assert is_complex_floating_dtype(dtype)
Esempio n. 5
0
def test_is_complex_floating_dtype():
    for dtype in complex_float_dtypes:
        assert is_complex_floating_dtype(dtype)
Esempio n. 6
0
def vector(array, dtype=None, impl="numpy"):
    """Create an n-tuples type vector from an array.

    Parameters
    ----------
    array : array-like
        Array from which to create the vector. Scalars become
        one-dimensional vectors.
    dtype : `object`, optional
        Set the data type of the vector manually with this option.
        By default, the space type is inferred from the input data.
    impl : {'numpy', 'cuda'}
        Implementation backend for the vector

    Returns
    -------
    vec : `NtuplesBaseVector`
        Vector created from the input array. Its concrete type depends
        on the provided arguments.

    Notes
    -----
    This is a convenience function and not intended for use in
    speed-critical algorithms. It creates a NumPy array first, hence
    especially CUDA vectors as input result in a large speed penalty.

    Examples
    --------
    >>> vector([1, 2, 3])  # No automatic cast to float
    Fn(3, 'int').element([1, 2, 3])
    >>> vector([1, 2, 3], dtype=float)
    Rn(3).element([1.0, 2.0, 3.0])
    >>> vector([1 + 1j, 2, 3 - 2j])
    Cn(3).element([(1+1j), (2+0j), (3-2j)])

    Non-scalar types are also supported:

    >>> vector([u'Hello,', u' world!'])
    Ntuples(2, '<U7').element([u'Hello,', u' world!'])

    Scalars become a one-element vector:

    >>> vector(0.0)
    Rn(1).element([0.0])
    """
    # Sanitize input
    arr = np.array(array, copy=False, ndmin=1)
    impl = str(impl).lower()

    # Validate input
    if arr.ndim > 1:
        raise ValueError("array has {} dimensions, expected 1." "".format(arr.ndim))

    # Set dtype
    if dtype is not None:
        space_dtype = dtype
    elif arr.dtype == float and impl == "cuda":
        # Special case, default float is float32 on cuda
        space_dtype = "float32"
    else:
        space_dtype = arr.dtype

    # Select implementation
    if impl == "numpy":
        if is_real_floating_dtype(space_dtype):
            space_type = Rn
        elif is_complex_floating_dtype(space_dtype):
            space_type = Cn
        elif is_scalar_dtype(space_dtype):
            space_type = Fn
        else:
            space_type = Ntuples

    elif impl == "cuda":
        if not CUDA_AVAILABLE:
            raise ValueError("CUDA implementation not available.")

        if is_real_floating_dtype(space_dtype):
            space_type = CudaRn
        elif is_complex_floating_dtype(space_dtype):
            raise NotImplementedError("complex spaces in CUDA not supported.")
        elif is_scalar_dtype(space_dtype):
            space_type = CudaFn
        else:
            space_type = CudaNtuples

    else:
        raise ValueError("implementation '{}' not understood.".format(impl))

    return space_type(len(arr), dtype=space_dtype).element(arr)
Esempio n. 7
0
    def __init__(self, domain, field=None, out_dtype=None):
        """Initialize a new instance.

        Parameters
        ----------
        domain : `Set`
            The domain of the functions
        field : `Field`, optional
            The range of the functions, usually the `RealNumbers` or
            `ComplexNumbers`. If not given, the field is either inferred
            from ``out_dtype``, or, if the latter is also `None`, set
            to ``RealNumbers()``.
        out_dtype : optional
            Data type of the return value of a function in this space.
            Can be given in any way `numpy.dtype` understands, e.g. as
            string ('float64') or data type (`float`).
            By default, 'float64' is used for real and 'complex128'
            for complex spaces.
        """
        if not isinstance(domain, Set):
            raise TypeError('`domain` {!r} not a Set instance'.format(domain))

        if field is not None and not isinstance(field, Field):
            raise TypeError('`field` {!r} not a `Field` instance'
                            ''.format(field))

        # Data type: check if consistent with field, take default for None
        dtype, dtype_in = np.dtype(out_dtype), out_dtype

        # Default for both None
        if field is None and out_dtype is None:
            field = RealNumbers()
            out_dtype = np.dtype('float64')

        # field None, dtype given -> infer field
        elif field is None:
            if is_real_dtype(dtype):
                field = RealNumbers()
            elif is_complex_floating_dtype(dtype):
                field = ComplexNumbers()
            else:
                raise ValueError('{} is not a scalar data type'
                                 ''.format(dtype_in))

        # field given -> infer dtype if not given, else check consistency
        elif field == RealNumbers():
            if out_dtype is None:
                out_dtype = np.dtype('float64')
            elif not is_real_dtype(dtype):
                raise ValueError('{} is not a real data type'
                                 ''.format(dtype_in))
        elif field == ComplexNumbers():
            if out_dtype is None:
                out_dtype = np.dtype('complex128')
            elif not is_complex_floating_dtype(dtype):
                raise ValueError('{} is not a complex data type'
                                 ''.format(dtype_in))

        # Else: keep out_dtype=None, which results in lazy dtype determination

        LinearSpace.__init__(self, field)
        FunctionSet.__init__(self, domain, field, out_dtype)

        # Init cache attributes for real / complex variants
        if self.field == RealNumbers():
            self._real_out_dtype = self.out_dtype
            self._real_space = self
            self._complex_out_dtype = _TYPE_MAP_R2C.get(self.out_dtype,
                                                        np.dtype(object))
            self._complex_space = None
        elif self.field == ComplexNumbers():
            self._real_out_dtype = _TYPE_MAP_C2R[self.out_dtype]
            self._real_space = None
            self._complex_out_dtype = self.out_dtype
            self._complex_space = self
        else:
            self._real_out_dtype = None
            self._real_space = None
            self._complex_out_dtype = None
            self._complex_space = None
Esempio n. 8
0
def uniform_discr_fromspace(fspace, nsamples, exponent=2.0, interp='nearest',
                            impl='numpy', **kwargs):
    """Discretize an Lp function space by uniform partition.

    Parameters
    ----------
    fspace : `FunctionSpace`
        Continuous function space. Its domain must be an
        `IntervalProd` instance.
    nsamples : `int` or `tuple` of `int`
        Number of samples per axis. For dimension >= 2, a tuple is
        required.
    exponent : positive `float`, optional
        The parameter ``p`` in ``L^p``. If the exponent is not
        equal to the default 2.0, the space has no inner product.
    interp : `str` or `sequence` of `str`, optional
        Interpolation type to be used for discretization.
        A sequence is interpreted as interpolation scheme per axis.

            'nearest' : use nearest-neighbor interpolation

            'linear' : use linear interpolation

    impl : {'numpy', 'cuda'}, optional
        Implementation of the data storage arrays

    Other Parameters
    ----------------
    nodes_on_bdry : `bool` or boolean `array-like`, optional
        If `True`, place the outermost grid points at the boundary. For
        `False`, they are shifted by half a cell size to the 'inner'.
        If an array-like is given, it must have shape ``(ndim, 2)``,
        where ``ndim`` is the number of dimensions. It defines per axis
        whether the leftmost (first column) and rightmost (second column)
        nodes node lie on the boundary.
        Default: `False`
    order : {'C', 'F'}, optional
        Axis ordering in the data storage. Default: 'C'
    dtype : dtype, optional
        Data type for the discretized space. If not specified, the
        `FunctionSpace.out_dtype` of ``fspace`` is used.
    weighting : {'const', 'none'}, optional
        Weighting of the discretized space functions.

            'const' : weight is a constant, the cell volume (default)

            'none' : no weighting

    Returns
    -------
    discr : `DiscreteLp`
        The uniformly discretized function space

    Examples
    --------
    >>> from odl import Interval, FunctionSpace
    >>> intv = Interval(0, 1)
    >>> space = FunctionSpace(intv)
    >>> uniform_discr_fromspace(space, 10)
    uniform_discr(0.0, 1.0, 10)

    See also
    --------
    uniform_discr : implicit uniform Lp discretization
    uniform_discr_frompartition : uniform Lp discretization using a given
        uniform partition of a function domain
    uniform_discr_fromintv : uniform discretization from an existing
        interval product
    odl.discr.partition.uniform_partition :
        partition of the function domain
    """
    if not isinstance(fspace, FunctionSpace):
        raise TypeError('space {!r} is not a `FunctionSpace` instance.'
                        ''.format(fspace))
    if not isinstance(fspace.domain, IntervalProd):
        raise TypeError('domain {!r} of the function space is not an '
                        '`IntervalProd` instance.'.format(fspace.domain))

    impl, impl_in = str(impl).lower(), impl
    dtype = kwargs.pop('dtype', None)

    # Set data type. If given check consistency with fspace's field and
    # out_dtype. If not given, take the latter.
    if dtype is None:
        dtype = fspace.out_dtype
    else:
        dtype, dtype_in = np.dtype(dtype), dtype
        if not np.can_cast(fspace.out_dtype, dtype, casting='safe'):
            raise ValueError('cannot safely cast from output data {} type of '
                             'the function space to given data type {}.'
                             ''.format(fspace.out, dtype_in))

    if fspace.field == RealNumbers() and not is_real_dtype(dtype):
        raise ValueError('cannot discretize real space {} with '
                         'non-real data type {}.'
                         ''.format(fspace, dtype))
    elif (fspace.field == ComplexNumbers() and
          not is_complex_floating_dtype(dtype)):
        raise ValueError('cannot discretize complex space {} with '
                         'non-complex-floating data type {}.'
                         ''.format(fspace, dtype))

    nodes_on_bdry = kwargs.pop('nodes_on_bdry', False)
    partition = uniform_partition_fromintv(fspace.domain, nsamples,
                                           nodes_on_bdry)

    return uniform_discr_frompartition(partition, exponent, interp, impl_in,
                                       dtype=dtype, **kwargs)
Esempio n. 9
0
def vector(array, dtype=None, impl='numpy'):
    """Create an n-tuples type vector from an array.

    Parameters
    ----------
    array : `array-like`
        Array from which to create the vector. Scalars become
        one-dimensional vectors.
    dtype : `object`, optional
        Set the data type of the vector manually with this option.
        By default, the space type is inferred from the input data.
    impl : {'numpy', 'cuda'}
        Implementation backend for the vector

    Returns
    -------
    vec : `NtuplesBaseVector`
        Vector created from the input array. Its concrete type depends
        on the provided arguments.

    Notes
    -----
    This is a convenience function and not intended for use in
    speed-critical algorithms. It creates a NumPy array first, hence
    especially CUDA vectors as input result in a large speed penalty.

    Examples
    --------
    >>> vector([1, 2, 3])  # No automatic cast to float
    Fn(3, 'int').element([1, 2, 3])
    >>> vector([1, 2, 3], dtype=float)
    Rn(3).element([1.0, 2.0, 3.0])
    >>> vector([1 + 1j, 2, 3 - 2j])
    Cn(3).element([(1+1j), (2+0j), (3-2j)])

    Non-scalar types are also supported:

    >>> vector([True, False])
    Ntuples(2, 'bool').element([True, False])

    Scalars become a one-element vector:

    >>> vector(0.0)
    Rn(1).element([0.0])
    """
    # Sanitize input
    arr = np.array(array, copy=False, ndmin=1)
    impl, impl_in = str(impl).lower(), impl

    # Validate input
    if arr.ndim > 1:
        raise ValueError('array has {} dimensions, expected 1'
                         ''.format(arr.ndim))

    # Set dtype
    if dtype is not None:
        space_dtype = dtype
    elif arr.dtype == np.dtype('float64') and impl == 'cuda':
        # Special case, default float is float32 on cuda
        space_dtype = 'float32'
    else:
        space_dtype = arr.dtype

    # Select implementation
    if impl == 'numpy':
        if is_real_floating_dtype(space_dtype):
            space_type = Rn
        elif is_complex_floating_dtype(space_dtype):
            space_type = Cn
        elif is_scalar_dtype(space_dtype):
            space_type = Fn
        else:
            space_type = Ntuples

    elif impl == 'cuda':
        if not CUDA_AVAILABLE:
            raise ValueError("'cuda' implementation not available")

        if is_real_floating_dtype(space_dtype):
            space_type = CudaRn
        elif is_complex_floating_dtype(space_dtype):
            raise NotImplementedError('complex spaces in CUDA not supported')
        elif is_scalar_dtype(space_dtype):
            space_type = CudaFn
        else:
            space_type = CudaNtuples

    else:
        raise ValueError("`impl` '{}' not understood".format(impl_in))

    return space_type(len(arr), dtype=space_dtype).element(arr)