def test_resizing_op_call(odl_tspace_impl): impl = odl_tspace_impl dtypes = [ dt for dt in tensor_space_impl(impl).available_dtypes() if is_numeric_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=impl) res_space = odl.uniform_discr([0, -0.6], [2, 0.2], (8, 2), impl=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 'impl' if impl != 'numpy': space = odl.uniform_discr([0, -1], [1, 1], (4, 5), impl=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 test_resizing_op_adjoint(padding, odl_tspace_impl): impl = odl_tspace_impl pad_mode, pad_const = padding dtypes = [ dt for dt in tensor_space_impl(impl).available_dtypes() if is_real_floating_dtype(dt) ] for dtype in dtypes: space = odl.uniform_discr([0, -1], [1, 1], (4, 5), dtype=dtype, impl=impl) res_space = odl.uniform_discr([0, -1.4], [1.5, 1.4], (6, 7), dtype=dtype, impl=impl) res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode, pad_const=pad_const) if pad_const != 0.0: with pytest.raises(NotImplementedError): res_op.adjoint return elem = noise_element(space) res_elem = noise_element(res_space) inner1 = res_op(elem).inner(res_elem) inner2 = elem.inner(res_op.adjoint(res_elem)) assert almost_equal(inner1, inner2, places=dtype_places(dtype))
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)
def space(request, ndim, dtype, odl_tspace_impl): """Provide a space for unit tests.""" impl = odl_tspace_impl supported_dtypes = tensor_space_impl(impl).available_dtypes() if np.dtype(dtype) not in supported_dtypes: pytest.skip('dtype not available for this backend') return odl.uniform_discr([-1] * ndim, [1] * ndim, [20] * ndim, impl=impl, dtype=dtype)
def space(request, ndim, interp, dtype, odl_tspace_impl): """Example space. Generates example spaces with various implementations, dimensions, dtypes and interpolations. """ impl = odl_tspace_impl supported_dtypes = tensor_space_impl(impl).available_dtypes() if np.dtype(dtype) not in supported_dtypes: pytest.skip('dtype not available for this backend') return odl.uniform_discr([-1] * ndim, [1] * ndim, [20] * ndim, interp=interp, impl=impl, dtype=dtype)
def tspace_type(space, impl, dtype=None): """Select the correct corresponding tensor space. Parameters ---------- space : `LinearSpace` Template space from which to infer an adequate tensor space. If it has a `LinearSpace.field` attribute, ``dtype`` must be consistent with it. impl : string Implementation backend for the tensor space. 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. """ 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_numeric_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)) try: return tensor_space_impl(impl) except ValueError: raise NotImplementedError('no corresponding tensor space available ' 'for space {!r} and implementation {!r}' ''.format(space, impl))
def test_resizing_op_properties(odl_tspace_impl, padding): impl = odl_tspace_impl dtypes = [ dt for dt in tensor_space_impl(impl).available_dtypes() if is_numeric_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 test_resizing_op_inverse(padding, odl_tspace_impl): impl = odl_tspace_impl pad_mode, pad_const = padding dtypes = [dt for dt in tensor_space_impl(impl).available_dtypes() if is_numeric_dtype(dt)] for dtype in dtypes: space = odl.uniform_discr([0, -1], [1, 1], (4, 5), dtype=dtype, impl=impl) res_space = odl.uniform_discr([0, -1.4], [1.5, 1.4], (6, 7), dtype=dtype, impl=impl) res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode, pad_const=pad_const) # Only left inverse if the operator extends in all axes x = noise_element(space) assert res_op.inverse(res_op(x)) == x
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