Source code for odl.space.space_utils

# Copyright 2014-2019 The ODL contributors
#
# This file is part of ODL.
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.

"""Utility functions for space implementations."""

from __future__ import print_function, division, absolute_import
import numpy as np

from odl.set import RealNumbers, ComplexNumbers
from odl.space.entry_points import tensor_space_impl


__all__ = ('vector', 'tensor_space', 'cn', 'rn')


[docs]def vector(array, dtype=None, order=None, impl='numpy'): """Create a vector from an array-like object. Parameters ---------- array : `array-like` Array from which to create the vector. Scalars become one-dimensional vectors. dtype : optional Set the data type of the vector manually with this option. By default, the space type is inferred from the input data. order : {None, 'C', 'F'}, optional Axis ordering of the data storage. For the default ``None``, no contiguousness is enforced, avoiding a copy if possible. impl : str, optional Impmlementation back-end for the space. See `odl.space.entry_points.tensor_space_impl_names` for available options. Returns ------- vector : `Tensor` 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. Examples -------- Create one-dimensional vectors: >>> odl.vector([1, 2, 3]) # No automatic cast to float tensor_space(3, dtype=int).element([1, 2, 3]) >>> odl.vector([1, 2, 3], dtype=float) rn(3).element([ 1., 2., 3.]) >>> odl.vector([1, 2 - 1j, 3]) cn(3).element([ 1.+0.j, 2.-1.j, 3.+0.j]) Non-scalar types are also supported: >>> odl.vector([True, True, False]) tensor_space(3, dtype=bool).element([ True, True, False]) The function also supports multi-dimensional input: >>> odl.vector([[1, 2, 3], ... [4, 5, 6]]) tensor_space((2, 3), dtype=int).element( [[1, 2, 3], [4, 5, 6]] ) """ # Sanitize input arr = np.array(array, copy=False, order=order, ndmin=1) if arr.dtype is object: raise ValueError('invalid input data resulting in `dtype==object`') # Set dtype if dtype is not None: space_dtype = dtype else: space_dtype = arr.dtype space = tensor_space(arr.shape, dtype=space_dtype, impl=impl) return space.element(arr)
[docs]def tensor_space(shape, dtype=None, impl='numpy', **kwargs): """Return a tensor space with arbitrary scalar data type. Parameters ---------- shape : positive int or sequence of positive ints Number of entries per axis for elements in this space. A single integer results in a space with 1 axis. dtype : optional Data type of each element. Can be provided in any way the `numpy.dtype` function understands, e.g. as built-in type or as a string. For ``None``, the `TensorSpace.default_dtype` of the created space is used. impl : str, optional Impmlementation back-end for the space. See `odl.space.entry_points.tensor_space_impl_names` for available options. kwargs : Extra keyword arguments passed to the space constructor. Returns ------- space : `TensorSpace` Examples -------- Space of 3-tuples with ``uint64`` entries (although not strictly a vector space): >>> odl.tensor_space(3, dtype='uint64') tensor_space(3, dtype='uint64') 2x3 tensors with same data type: >>> odl.tensor_space((2, 3), dtype='uint64') tensor_space((2, 3), dtype='uint64') The default data type depends on the implementation. For ``impl='numpy'``, it is ``'float64'``: >>> ts = odl.tensor_space((2, 3)) >>> ts rn((2, 3)) >>> ts.dtype dtype('float64') See Also -------- rn, cn : Constructors for real and complex spaces """ tspace_cls = tensor_space_impl(impl) if dtype is None: dtype = tspace_cls.default_dtype() # Use args by keyword since the constructor may take other arguments # by position return tspace_cls(shape=shape, dtype=dtype, **kwargs)
[docs]def cn(shape, dtype=None, impl='numpy', **kwargs): """Return a space of complex tensors. Parameters ---------- shape : positive int or sequence of positive ints Number of entries per axis for elements in this space. A single integer results in a space with 1 axis. dtype : optional Data type of each element. Can be provided in any way the `numpy.dtype` function understands, e.g. as built-in type or as a string. Only complex floating-point data types are allowed. For ``None``, the `TensorSpace.default_dtype` of the created space is used in the form ``default_dtype(ComplexNumbers())``. impl : str, optional Impmlementation back-end for the space. See `odl.space.entry_points.tensor_space_impl_names` for available options. kwargs : Extra keyword arguments passed to the space constructor. Returns ------- cn : `TensorSpace` Examples -------- Space of complex 3-tuples with ``complex64`` entries: >>> odl.cn(3, dtype='complex64') cn(3, dtype='complex64') Complex 2x3 tensors with ``complex64`` entries: >>> odl.cn((2, 3), dtype='complex64') cn((2, 3), dtype='complex64') The default data type depends on the implementation. For ``impl='numpy'``, it is ``'complex128'``: >>> space = odl.cn((2, 3)) >>> space cn((2, 3)) >>> space.dtype dtype('complex128') See Also -------- tensor_space : Space of tensors with arbitrary scalar data type. rn : Real tensor space. """ cn_cls = tensor_space_impl(impl) if dtype is None: dtype = cn_cls.default_dtype(ComplexNumbers()) # Use args by keyword since the constructor may take other arguments # by position cn = cn_cls(shape=shape, dtype=dtype, **kwargs) if not cn.is_complex: raise ValueError('data type {!r} not a complex floating-point type.' ''.format(dtype)) return cn
[docs]def rn(shape, dtype=None, impl='numpy', **kwargs): """Return a space of real tensors. Parameters ---------- shape : positive int or sequence of positive ints Number of entries per axis for elements in this space. A single integer results in a space with 1 axis. dtype : optional Data type of each element. Can be provided in any way the `numpy.dtype` function understands, e.g. as built-in type or as a string. Only real floating-point data types are allowed. For ``None``, the `TensorSpace.default_dtype` of the created space is used in the form ``default_dtype(RealNumbers())``. impl : str, optional Impmlementation back-end for the space. See `odl.space.entry_points.tensor_space_impl_names` for available options. kwargs : Extra keyword arguments passed to the space constructor. Returns ------- real_space : `TensorSpace` Examples -------- Space of real 3-tuples with ``float32`` entries: >>> odl.rn(3, dtype='float32') rn(3, dtype='float32') Real 2x3 tensors with ``float32`` entries: >>> odl.rn((2, 3), dtype='float32') rn((2, 3), dtype='float32') The default data type depends on the implementation. For ``impl='numpy'``, it is ``'float64'``: >>> ts = odl.rn((2, 3)) >>> ts rn((2, 3)) >>> ts.dtype dtype('float64') See Also -------- tensor_space : Space of tensors with arbitrary scalar data type. cn : Complex tensor space. """ rn_cls = tensor_space_impl(impl) if dtype is None: dtype = rn_cls.default_dtype(RealNumbers()) # Use args by keyword since the constructor may take other arguments # by position rn = rn_cls(shape=shape, dtype=dtype, **kwargs) if not rn.is_real: raise ValueError('data type {!r} not a real floating-point type.' ''.format(dtype)) return rn
if __name__ == '__main__': from odl.util.testutils import run_doctests run_doctests()