def __init__(self, size, dtype): """Initialize a new instance. Parameters ---------- size : `int` The number of dimensions of the space dtype : `object` The data type of the storage array. Can be provided in any way the `numpy.dtype` function understands, most notably as built-in type, as one of NumPy's internal datatype objects or as string. Only scalar data types (numbers) are allowed. """ NtuplesBase.__init__(self, size, dtype) if not is_scalar_dtype(self.dtype): raise TypeError('{!r} is not a scalar data type.'.format(dtype)) if is_real_dtype(self.dtype): field = RealNumbers() self._real_dtype = self.dtype self._is_real = True else: field = ComplexNumbers() self._real_dtype = _TYPE_MAP_C2R[self.dtype] self._is_real = False self._is_floating = is_floating_dtype(self.dtype) LinearSpace.__init__(self, field)
def test_resizing_op_call(fn_impl): dtypes = [dt for dt in odl.FN_IMPLS[fn_impl].available_dtypes() if is_scalar_dtype(dt)] for dtype in dtypes: # Minimal test since this operator only wraps resize_array space = odl.uniform_discr([0, -1], [1, 1], (4, 5), impl=fn_impl) res_space = odl.uniform_discr([0, -0.6], [2, 0.2], (8, 2), impl=fn_impl) res_op = odl.ResizingOperator(space, res_space) out = res_op(space.one()) true_res = np.zeros((8, 2)) true_res[:4, :] = 1 assert np.array_equal(out, true_res) out = res_space.element() res_op(space.one(), out=out) assert np.array_equal(out, true_res) # Test also mapping to default impl for other 'fn_impl' if fn_impl != 'numpy': space = odl.uniform_discr([0, -1], [1, 1], (4, 5), impl=fn_impl) res_space = odl.uniform_discr([0, -0.6], [2, 0.2], (8, 2)) res_op = odl.ResizingOperator(space, res_space) out = res_op(space.one()) true_res = np.zeros((8, 2)) true_res[:4, :] = 1 assert np.array_equal(out, true_res) out = res_space.element() res_op(space.one(), out=out) assert np.array_equal(out, true_res)
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
def test_resizing_op_inverse(padding, fn_impl): pad_mode, pad_const = padding dtypes = [dt for dt in odl.FN_IMPLS[fn_impl].available_dtypes() if is_scalar_dtype(dt)] for dtype in dtypes: space = odl.uniform_discr([0, -1], [1, 1], (4, 5), dtype=dtype, impl=fn_impl) res_space = odl.uniform_discr([0, -1.4], [1.5, 1.4], (6, 7), dtype=dtype, impl=fn_impl) res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode, pad_const=pad_const) # Only left inverse if the operator extentds in all axes x = noise_element(space) assert res_op.inverse(res_op(x)) == x
def __init__(self, size, dtype): """Initialize a new instance. Parameters ---------- size : non-negative int Number of entries in a tuple. dtype : Data type for each tuple entry. Can be provided in any way the `numpy.dtype` function understands, most notably as built-in type, as one of NumPy's internal datatype objects or as string. Only scalar data types (numbers) are allowed. """ NtuplesBase.__init__(self, size, dtype) if not is_scalar_dtype(self.dtype): raise TypeError('{!r} is not a scalar data type'.format(dtype)) if is_real_dtype(self.dtype): field = RealNumbers() self.__is_real = True self.__real_dtype = self.dtype self.__real_space = self try: self.__complex_dtype = complex_dtype(self.dtype) except ValueError: self.__complex_dtype = None self.__complex_space = None # Set in first call of astype else: field = ComplexNumbers() self.__is_real = False try: self.__real_dtype = real_dtype(self.dtype) except ValueError: self.__real_dtype = None self.__real_space = None # Set in first call of astype self.__complex_dtype = self.dtype self.__complex_space = self self.__is_floating = is_floating_dtype(self.dtype) LinearSpace.__init__(self, field)
def __init__(self, size, dtype): """Initialize a new instance. Parameters ---------- size : `int` The number of dimensions of the space dtype : `object` The data type of the storage array. Can be provided in any way the `numpy.dtype` function understands, most notably as built-in type, as one of NumPy's internal datatype objects or as string. Only scalar data types (numbers) are allowed. """ super().__init__(size, dtype) if not is_scalar_dtype(self.dtype): raise TypeError('{!r} is not a scalar data type.'.format(dtype)) if is_real_dtype(self.dtype): self._field = RealNumbers() else: self._field = ComplexNumbers()
def test_resizing_op_properties(fn_impl, padding): dtypes = [dt for dt in odl.FN_IMPLS[fn_impl].available_dtypes() if is_scalar_dtype(dt)] pad_mode, pad_const = padding for dtype in dtypes: # Explicit range space = odl.uniform_discr([0, -1], [1, 1], (10, 5), dtype=dtype) res_space = odl.uniform_discr([0, -3], [2, 3], (20, 15), dtype=dtype) res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode, pad_const=pad_const) assert res_op.domain == space assert res_op.range == res_space assert res_op.offset == (0, 5) assert res_op.pad_mode == pad_mode assert res_op.pad_const == pad_const if pad_mode == 'constant' and pad_const != 0: assert not res_op.is_linear else: assert res_op.is_linear # Implicit range via ran_shp and offset res_op = odl.ResizingOperator(space, ran_shp=(20, 15), offset=[0, 5], pad_mode=pad_mode, pad_const=pad_const) assert np.allclose(res_op.range.min_pt, res_space.min_pt) assert np.allclose(res_op.range.max_pt, res_space.max_pt) assert np.allclose(res_op.range.cell_sides, res_space.cell_sides) assert res_op.range.dtype == res_space.dtype assert res_op.offset == (0, 5) assert res_op.pad_mode == pad_mode assert res_op.pad_const == pad_const if pad_mode == 'constant' and pad_const != 0: assert not res_op.is_linear else: assert res_op.is_linear
def __init__(self, size, dtype): """Initialize a new instance. Parameters ---------- size : `int` The number of dimensions of the space dtype : `object` The data type of the storage array. Can be provided in any way the `numpy.dtype` function understands, most notably as built-in type, as one of NumPy's internal datatype objects or as string. Only scalar data types (numbers) are allowed. """ NtuplesBase.__init__(self, size, dtype) if not is_scalar_dtype(self.dtype): raise TypeError('{!r} is not a scalar data type'.format(dtype)) if is_real_dtype(self.dtype): field = RealNumbers() self._is_real = True self._real_dtype = self.dtype self._real_space = self self._complex_dtype = _TYPE_MAP_R2C.get(self.dtype, None) self._complex_space = None # Set in first call of astype else: field = ComplexNumbers() self._is_real = False self._real_dtype = _TYPE_MAP_C2R[self.dtype] self._real_space = None # Set in first call of astype self._complex_dtype = self.dtype self._complex_space = self self._is_floating = is_floating_dtype(self.dtype) LinearSpace.__init__(self, field)
def test_is_scalar_dtype(): for dtype in scalar_dtypes: assert is_scalar_dtype(dtype)
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
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)
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 : optional Set the data type of the vector manually with this option. By default, the space type is inferred from the input data. impl : string The backend to use. See `odl.space.entry_points.NTUPLES_IMPLS` and `odl.space.entry_points.FN_IMPLS` for available options. 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. 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) # 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 else: space_dtype = arr.dtype # Select implementation if space_dtype is None or is_scalar_dtype(space_dtype): space_type = fn else: space_type = ntuples return space_type(len(arr), dtype=space_dtype, impl=impl).element(arr)
def contains_all(self, array): """Test if `array` is an array of real or complex numbers.""" dtype = getattr(array, 'dtype', None) if dtype is None: dtype = np.result_type(*array) return is_scalar_dtype(dtype)
def contains_all(self, other): """Return ``True`` if ``other`` is a sequence of complex numbers.""" dtype = getattr(other, 'dtype', None) if dtype is None: dtype = np.result_type(*other) return is_scalar_dtype(dtype)
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
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)