Exemplo n.º 1
0
    def __repr__(self):
        """Return ``repr(self)``."""
        # Matrix printing itself in an executable way (for dense matrix)
        if self.matrix_issparse:
            # Don't convert to dense, can take forever
            matrix_str = repr(self.matrix)
        else:
            matrix_str = np.array2string(self.matrix, separator=', ')
        posargs = [matrix_str]

        # Optional arguments with defaults, inferred from the matrix
        optargs = []
        # domain
        optargs.append(
            ('domain', self.domain, fn(self.matrix.shape[1],
                                       self.matrix.dtype)))
        # range
        optargs.append(
            ('range', self.range, fn(self.matrix.shape[0], self.matrix.dtype)))

        inner_str = signature_string(posargs,
                                     optargs,
                                     sep=[', ', ', ', ',\n'],
                                     mod=[['!s'], ['!r', '!r']])
        return '{}(\n{}\n)'.format(self.__class__.__name__,
                                   indent_rows(inner_str))
Exemplo n.º 2
0
    def __init__(self, range):
        """Initialize a new instance.

        Parameters
        ----------
        range : `LinearSpace` or `Field`
            Space that the operator should map to.

        Examples
        --------
        General usage example:

        >>> X = odl.uniform_discr(min_pt=[-1, -1], max_pt=[1, 1], shape=[1, 2])
        >>> A = odl.FlatteningOperatorAdjoint(X)
        >>> x = A.domain.element(range(A.domain.size))
        >>> A(x)
        uniform_discr([-1.0, -1.0], [1.0, 1.0], (1, 2)).element([[0.0, 1.0]])
        """
        if not isinstance(range, (LinearSpace, Field)):
            raise TypeError('`range` {!r} not a `LinearSpace` or `Field` '
                            'instance'.format(range))

        domain = fn(range.size, dtype=range.dtype)
        super(FlatteningOperatorAdjoint, self).__init__(
            domain, range, linear=True)
Exemplo n.º 3
0
    def __init__(self, domain, order='C'):
        """Initialize a new instance.

        Parameters
        ----------
        domain : `FnBase` or `DiscreteLp`
            Set of elements on which this operator acts.
        order : {'C', 'F'} (optional)
            The flattening is performed in this order. 'C' means that
            that the last index is changing fastest or in terms of a matrix
            that the read out is row-by-row. Likewise 'F' is column-by-column.

        Examples
        --------
        General usage example:

        >>> X = odl.uniform_discr(min_pt=[-1, -1], max_pt=[1, 1], shape=[2, 3])
        >>> x = X.element(range(X.size))
        >>> A = odl.FlatteningOperator(X)
        >>> A(x)
        rn(6).element([0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
        """
        if not isinstance(domain, (LinearSpace, Field)):
            raise TypeError('`domain` {!r} not a `LinearSpace` or `Field` '
                            'instance'.format(domain))

        self.__order = order
        range = fn(domain.size, dtype=domain.dtype)
        super(FlatteningOperator, self).__init__(domain, range, linear=True)
Exemplo n.º 4
0
Arquivo: fn_ops.py Projeto: TC-18/odl
    def __init__(self, domain, sampling_points, variant='point_eval'):
        """Initialize a new instance.

        Parameters
        ----------
        domain : `FnBase` or `DiscreteLp`
            Set of elements on which this operator acts.
        sampling_points : sequence
            Sequence of indices that determine the sampling points.
            In n dimensions, it should be of length n. Each element of
            this list is a list by itself and should have the length of
            the total number of sampling points. Example: To sample a
            function at the points (0, 1) and (1, 1) the indices should
            be defined as sampling_points = [[0, 1], [1, 1]].
        variant : {'point_eval', 'integrate'}, optional
            For `'point_eval'` this operator performs the sampling by
            evaluation the function at the sampling points. The
            `'integrate'` variant approximates integration by
            multiplying point evaluation with the cell volume.

        Examples
        --------
        >>> X = odl.uniform_discr(min_pt=[0, 0], max_pt=[1, 1], shape=[2, 2])
        >>> x = X.element(range(X.size))
        >>> sampling_points = [[0, 1], [1, 1]]
        >>> A = odl.SamplingOperator(X, sampling_points, 'point_eval')
        >>> A(x)
        rn(2).element([1.0, 3.0])
        >>> A = odl.SamplingOperator(X, sampling_points, 'integrate')
        >>> A(x)
        rn(2).element([0.25, 0.75])
        """
        if not isinstance(domain, (FnBase, DiscreteLp)):
            raise TypeError('`domain` {!r} not a `FnBase` or `DiscreteLp` '
                            'instance'.format(domain))

        self.__sampling_points = np.asarray(sampling_points, dtype=int)
        self.__variant = variant

        # Converts a single sequence to an array of integers
        # and a sequence of arrays to a vertically stacked array
        if self.sampling_points.ndim > 1:
            # Strides = increment in linear indices per axis
            strides = np.concatenate((np.cumprod(domain.shape[1:])[::-1], [1]))
            self.__indices_flat = np.sum(self.sampling_points *
                                         strides[:, None],
                                         axis=0)
        else:
            self.__indices_flat = self.sampling_points

        range = fn(self.indices_flat.size, dtype=domain.dtype)
        super().__init__(domain, range, linear=True)
Exemplo n.º 5
0
    def __init__(self, range, sampling_points, variant='dirac'):
        """Initialize a new instance.

        Parameters
        ----------
        range : `FnBase` or `DiscreteLp`
            Set of elements into which this operator maps.
        sampling_points : sequence
            Sequence of indices that determine the sampling points.
            In n dimensions, it should be of length n. Each element of
            this list is a list by itself and should have the length of
            the total number of sampling points. Example: To sample a
            function at the points (0, 1) and (1, 1) the indices should
            be defined as sampling_points = [[0, 1], [1, 1]].
        variant : {'dirac', 'char_fun'}, optional
            This option determines which function to sum over.

        Examples
        --------
        >>> X = odl.uniform_discr(min_pt=[0, 0], max_pt=[1, 1], shape=[2, 2])
        >>> sampling_points = [[0, 1], [1, 1]]
        >>> A = odl.WeightedSumSamplingOperator(X, sampling_points, 'dirac')
        >>> x = A.domain.one()
        >>> A(x)
        uniform_discr([0.0, 0.0], [1.0, 1.0], (2, 2)).element([[0.0, 4.0],
        [0.0, 4.0]])
        >>> A = odl.WeightedSumSamplingOperator(X, sampling_points, 'char_fun')
        >>> A(x)
        uniform_discr([0.0, 0.0], [1.0, 1.0], (2, 2)).element([[0.0, 1.0],
        [0.0, 1.0]])
        """

        self.__sampling_points = np.asarray(sampling_points, dtype=int)
        self.__variant = variant

        # Converts a single sequence to an array of integers
        # and a sequence of arrays to a vertically stacked array
        if self.sampling_points.ndim > 1:
            # Strides = increment in linear indices per axis
            strides = np.concatenate((np.cumprod(range.shape[1:])[::-1], [1]))
            self.__indices_flat = np.sum(
                self.sampling_points * strides[:, None], axis=0)
        else:
            self.__indices_flat = self.sampling_points

        domain = fn(self.indices_flat.size, dtype=range.dtype)
        super(WeightedSumSamplingOperator, self).__init__(
            domain, range, linear=True)
Exemplo n.º 6
0
def ufunc_class_factory(name, nargin, nargout, docstring):
    """Create a Ufunc `Operator` from a given specification."""

    assert 0 <= nargin <= 2

    def __init__(self, space):
        """Initialize an instance.

        Parameters
        ----------
        space : `FnBase`
            The domain of the operator.
        """
        if not isinstance(space, LinearSpace):
            raise TypeError('`space` {!r} not a `LinearSpace`'.format(space))

        if _is_integer_only_ufunc(name) and not is_int_dtype(space.dtype):
            raise ValueError("ufunc '{}' only defined with integral dtype"
                             "".format(name))

        if nargin == 1:
            domain = space
        else:
            domain = ProductSpace(space, nargin)

        if nargout == 1:
            range = space
        else:
            range = ProductSpace(space, nargout)

        linear = name in LINEAR_UFUNCS
        Operator.__init__(self, domain=domain, range=range, linear=linear)

    def _call(self, x, out=None):
        """Return ``self(x)``."""
        if out is None:
            if nargin == 1:
                return getattr(x.ufuncs, name)()
            else:
                return getattr(x[0].ufuncs, name)(*x[1:])
        else:
            if nargin == 1:
                return getattr(x.ufuncs, name)(out=out)
            else:
                return getattr(x[0].ufuncs, name)(*x[1:], out=out)

    def __repr__(self):
        """Return ``repr(self)``."""
        return '{}({!r})'.format(name, self.domain)

    # Create example (also functions as doctest)
    if 'shift' in name or 'bitwise' in name or name == 'invert':
        dtype = int
    else:
        dtype = float

    space = fn(3, dtype=dtype)
    if nargin == 1:
        vec = space.element([-1, 1, 2])
        arg = '{}'.format(vec)
        with np.errstate(all='ignore'):
            result = getattr(vec.ufuncs, name)()
    else:
        vec = space.element([-1, 1, 2])
        vec2 = space.element([3, 4, 5])
        arg = '[{}, {}]'.format(vec, vec2)
        with np.errstate(all='ignore'):
            result = getattr(vec.ufuncs, name)(vec2)

    if nargout == 2:
        result = '{{{}, {}}}'.format(result[0], result[1])

    examples_docstring = RAW_EXAMPLES_DOCSTRING.format(space=space, name=name,
                                                       arg=arg, result=result)
    full_docstring = docstring + examples_docstring

    attributes = {"__init__": __init__,
                  "_call": _call,
                  "derivative": derivative_factory(name),
                  "__repr__": __repr__,
                  "__doc__": full_docstring}

    full_name = name + '_op'

    return type(full_name, (Operator,), attributes)
Exemplo n.º 7
0
def ufunc_class_factory(name, nargin, nargout, docstring):
    """Create a Ufunc `Operator` from a given specification."""

    assert 0 <= nargin <= 2

    def __init__(self, space):
        """Initialize an instance.

        Parameters
        ----------
        space : `FnBase`
            The domain of the operator.
        """
        if not isinstance(space, LinearSpace):
            raise TypeError('`space` {!r} not a `LinearSpace`'.format(space))

        if _is_integer_only_ufunc(name) and not is_int_dtype(space.dtype):
            raise ValueError("ufunc '{}' only defined with integral dtype"
                             "".format(name))

        if nargin == 1:
            domain = space
        else:
            domain = ProductSpace(space, nargin)

        if nargout == 1:
            range = space
        else:
            range = ProductSpace(space, nargout)

        linear = name in LINEAR_UFUNCS
        Operator.__init__(self, domain=domain, range=range, linear=linear)

    def _call(self, x, out=None):
        """Return ``self(x)``."""
        if out is None:
            if nargin == 1:
                return getattr(x.ufuncs, name)()
            else:
                return getattr(x[0].ufuncs, name)(*x[1:])
        else:
            if nargin == 1:
                return getattr(x.ufuncs, name)(out=out)
            else:
                return getattr(x[0].ufuncs, name)(*x[1:], out=out)

    def __repr__(self):
        """Return ``repr(self)``."""
        return '{}({!r})'.format(name, self.domain)

    # Create example (also functions as doctest)
    if 'shift' in name or 'bitwise' in name or name == 'invert':
        dtype = int
    else:
        dtype = float

    space = fn(3, dtype=dtype)
    if nargin == 1:
        vec = space.element([-1, 1, 2])
        arg = '{}'.format(vec)
        with np.errstate(all='ignore'):
            result = getattr(vec.ufuncs, name)()
    else:
        vec = space.element([-1, 1, 2])
        vec2 = space.element([3, 4, 5])
        arg = '[{}, {}]'.format(vec, vec2)
        with np.errstate(all='ignore'):
            result = getattr(vec.ufuncs, name)(vec2)

    if nargout == 2:
        result = '{{{}, {}}}'.format(result[0], result[1])

    examples_docstring = RAW_EXAMPLES_DOCSTRING.format(space=space,
                                                       name=name,
                                                       arg=arg,
                                                       result=result)
    full_docstring = docstring + examples_docstring

    attributes = {
        "__init__": __init__,
        "_call": _call,
        "derivative": derivative_factory(name),
        "__repr__": __repr__,
        "__doc__": full_docstring
    }

    full_name = name + '_op'

    return type(full_name, (Operator, ), attributes)
Exemplo n.º 8
0
def _resize_discr(discr, newshp, offset, discr_kwargs):
    """Return a space based on ``discr`` and ``newshp``.

    Use the domain of ``discr`` and its partition to create a new
    uniformly discretized space with ``newshp`` as shape. In axes where
    ``offset`` is given, it determines the number of added/removed cells to
    the left. Where ``offset`` is ``None``, the points are distributed
    evenly to left and right. The ``discr_kwargs`` parameter is passed
    to `uniform_discr` for further specification of discretization
    parameters.
    """
    nodes_on_bdry = discr_kwargs.get('nodes_on_bdry', False)
    if np.shape(nodes_on_bdry) == ():
        nodes_on_bdry = ([(bool(nodes_on_bdry), bool(nodes_on_bdry))] *
                         discr.ndim)
    elif discr.ndim == 1 and len(nodes_on_bdry) == 2:
        nodes_on_bdry = [nodes_on_bdry]
    elif len(nodes_on_bdry) != discr.ndim:
        raise ValueError('`nodes_on_bdry` has length {}, expected {}'
                         ''.format(len(nodes_on_bdry), discr.ndim))

    dtype = discr_kwargs.pop('dtype', discr.dtype)
    impl = discr_kwargs.pop('impl', discr.impl)
    exponent = discr_kwargs.pop('exponent', discr.exponent)
    interp = discr_kwargs.pop('interp', discr.interp)
    order = discr_kwargs.pop('order', discr.order)
    weighting = discr_kwargs.pop('weighting', discr.weighting)

    affected = np.not_equal(newshp, discr.shape)
    ndim = discr.ndim
    for i in range(ndim):
        if affected[i] and not discr.is_uniform_byaxis[i]:
            raise ValueError('cannot resize in non-uniformly discretized '
                             'axis {}'.format(i))

    grid_min, grid_max = discr.grid.min(), discr.grid.max()
    cell_size = discr.cell_sides
    new_minpt, new_maxpt = [], []

    for axis, (n_orig, n_new, off, on_bdry) in enumerate(
            zip(discr.shape, newshp, offset, nodes_on_bdry)):

        if not affected[axis]:
            new_minpt.append(discr.min_pt[axis])
            new_maxpt.append(discr.max_pt[axis])
            continue

        n_diff = n_new - n_orig
        if off is None:
            num_r = n_diff // 2
            num_l = n_diff - num_r
        else:
            num_r = n_diff - off
            num_l = off

        try:
            on_bdry_l, on_bdry_r = on_bdry
        except TypeError:
            on_bdry_l = on_bdry
            on_bdry_r = on_bdry

        if on_bdry_l:
            new_minpt.append(grid_min[axis] - num_l * cell_size[axis])
        else:
            new_minpt.append(grid_min[axis] - (num_l + 0.5) * cell_size[axis])

        if on_bdry_r:
            new_maxpt.append(grid_max[axis] + num_r * cell_size[axis])
        else:
            new_maxpt.append(grid_max[axis] + (num_r + 0.5) * cell_size[axis])

    fspace = FunctionSpace(IntervalProd(new_minpt, new_maxpt), out_dtype=dtype)
    dspace = fn(np.prod(newshp),
                dtype=dtype,
                impl=impl,
                exponent=exponent,
                weighting=weighting)

    # Stack together the (unchanged) nonuniform axes and the (new) uniform
    # axes in the right order
    part = uniform_partition([], [], ())
    for i in range(ndim):
        if discr.is_uniform_byaxis[i]:
            part = part.append(
                uniform_partition(new_minpt[i],
                                  new_maxpt[i],
                                  newshp[i],
                                  nodes_on_bdry=nodes_on_bdry[i]))
        else:
            part = part.append(discr.partition.byaxis[i])

    return DiscreteLp(fspace,
                      part,
                      dspace,
                      exponent=exponent,
                      interp=interp,
                      order=order)
Exemplo n.º 9
0
    def __init__(self, matrix, domain=None, range=None):
        """Initialize a new instance.

        Parameters
        ----------
        matrix : `array-like` or `scipy.sparse.base.spmatrix`
            2-dimensional array representing the linear operator.
        domain : `FnBase`, optional
            Space of elements on which the operator can act. Its
            ``dtype`` must be castable to ``range.dtype``.
            For the default ``None``, a `NumpyFn` space with size
            ``matrix.shape[1]`` is used, together with the matrix'
            data type.
        range : `FnBase`, optional
            Space of elements on to which the operator maps. Its
            ``shape`` and ``dtype`` attributes must match the ones
            of the result of the multiplication.
            For the default ``None``, the range is inferred from
            ``matrix`` and ``domain``.

        Examples
        --------
        By default, ``domain`` and ``range`` are `NumpyFn` type spaces:

        >>> matrix = np.ones((3, 4))
        >>> op = MatrixOperator(matrix)
        >>> op
        MatrixOperator(
            [[ 1.,  1.,  1.,  1.],
             [ 1.,  1.,  1.,  1.],
             [ 1.,  1.,  1.,  1.]]
        )
        >>> op.domain
        rn(4)
        >>> op.range
        rn(3)
        >>> op([1, 2, 3, 4])
        rn(3).element([10.0, 10.0, 10.0])

        They can also be provided explicitly, for example with
        `uniform_discr` spaces:

        >>> dom = odl.uniform_discr(0, 1, 4)
        >>> ran = odl.uniform_discr(0, 1, 3)
        >>> op = MatrixOperator(matrix, domain=dom, range=ran)
        >>> op(dom.one())
        uniform_discr(0.0, 1.0, 3).element([4.0, 4.0, 4.0])

        For storage efficiency, SciPy sparse matrices can be used:

        >>> import scipy
        >>> row_idcs = np.array([0, 3, 1, 0])
        >>> col_idcs = np.array([0, 3, 1, 2])
        >>> values = np.array([4.0, 5.0, 7.0, 9.0])
        >>> matrix = scipy.sparse.coo_matrix((values, (row_idcs, col_idcs)),
        ...                                  shape=(4, 4))
        >>> matrix.toarray()
        array([[ 4.,  0.,  9.,  0.],
               [ 0.,  7.,  0.,  0.],
               [ 0.,  0.,  0.,  0.],
               [ 0.,  0.,  0.,  5.]])
        >>> op = MatrixOperator(matrix)
        >>> op(op.domain.one())
        rn(4).element([13.0, 7.0, 0.0, 5.0])
        """
        # TODO: fix dead link `scipy.sparse.spmatrix`
        if scipy.sparse.isspmatrix(matrix):
            self.__matrix = matrix
        else:
            self.__matrix = np.asarray(matrix)

        if self.matrix.ndim != 2:
            raise ValueError('matrix {} has {} axes instead of 2'
                             ''.format(matrix, self.matrix.ndim))

        # Infer domain and range from matrix if necessary
        if domain is None:
            domain = fn(self.matrix.shape[1], dtype=self.matrix.dtype)
        elif not isinstance(domain, FnBase):
            raise TypeError('`domain` {!r} is not an `FnBase` instance'
                            ''.format(domain))

        if range is None:
            range = fn(self.matrix.shape[0], dtype=self.matrix.dtype)
        elif not isinstance(range, FnBase):
            raise TypeError('`range` {!r} is not an `FnBase` instance'
                            ''.format(range))

        # Check compatibility of matrix with domain and range
        if self.matrix.shape != (range.size, domain.size):
            raise ValueError('matrix shape {} does not match the required '
                             'shape {} of a matrix {} --> {}'
                             ''.format(self.matrix.shape,
                                       (range.size, domain.size), domain,
                                       range))

        if not np.can_cast(domain.dtype, range.dtype):
            raise TypeError('domain data type {!r} cannot be safely cast to '
                            'range data type {!r}'
                            ''.format(domain.dtype, range.dtype))

        if not np.can_cast(self.matrix.dtype, range.dtype):
            raise TypeError('matrix data type {!r} cannot be safely cast to '
                            'range data type {!r}.'
                            ''.format(matrix.dtype, range.dtype))

        super().__init__(domain, range, linear=True)