Example #1
0
def test_out_shape_from_meshgrid():

    # 1d
    x = np.zeros(2)
    mg = sparse_meshgrid(x)
    assert out_shape_from_meshgrid(mg) == (2, )

    # 3d
    x, y, z = np.zeros(2), np.zeros(3), np.zeros(4)
    mg = sparse_meshgrid(x, y, z)
    assert out_shape_from_meshgrid(mg) == (2, 3, 4)

    # 3d, fleshed out meshgrids
    x, y, z = np.zeros(2), np.zeros(3), np.zeros(4)
    mg = np.meshgrid(x, y, z, sparse=False, indexing='ij', copy=True)
    assert out_shape_from_meshgrid(mg) == (2, 3, 4)

    mg = np.meshgrid(x, y, z, sparse=False, indexing='ij', copy=True)
    mg = tuple(reversed([np.asfortranarray(arr) for arr in mg]))
    assert out_shape_from_meshgrid(mg) == (2, 3, 4)
Example #2
0
def test_out_shape_from_meshgrid():

    # 1d
    x = np.zeros(2)
    mg = sparse_meshgrid(x)
    assert out_shape_from_meshgrid(mg) == (2,)

    # 3d
    x, y, z = np.zeros(2), np.zeros(3), np.zeros(4)
    mg = sparse_meshgrid(x, y, z)
    assert out_shape_from_meshgrid(mg) == (2, 3, 4)

    # 3d, fleshed out meshgrids
    x, y, z = np.zeros(2), np.zeros(3), np.zeros(4)
    mg = np.meshgrid(x, y, z, sparse=False, indexing='ij', copy=True)
    assert out_shape_from_meshgrid(mg) == (2, 3, 4)

    mg = np.meshgrid(x, y, z, sparse=False, indexing='ij', copy=True)
    mg = tuple(reversed([np.asfortranarray(arr) for arr in mg]))
    assert out_shape_from_meshgrid(mg) == (2, 3, 4)
Example #3
0
        def one_vec(x, out=None):
            """The one function, vectorized."""
            if is_valid_input_meshgrid(x, self.domain.ndim):
                order = meshgrid_input_order(x)
            else:
                order = 'C'

            out_shape = out_shape_from_meshgrid(x)
            if out is None:
                return np.ones(out_shape, dtype=dtype, order=order)
            else:
                out.fill(1)
Example #4
0
        def one_vec(x, out=None):
            """The one function, vectorized."""
            if is_valid_input_meshgrid(x, self.domain.ndim):
                out_shape = out_shape_from_meshgrid(x)
            elif is_valid_input_array(x, self.domain.ndim):
                out_shape = out_shape_from_array(x)
            else:
                raise TypeError('invalid input type')

            if out is None:
                return np.ones(out_shape, dtype=self.out_dtype)
            else:
                out.fill(1)
Example #5
0
def _default_out_of_place(func, dtype, x, **kwargs):
    """Default in-place evaluation method."""
    if is_valid_input_array(x, func.domain.ndim):
        out_shape = out_shape_from_array(x)
    elif is_valid_input_meshgrid(x, func.domain.ndim):
        out_shape = out_shape_from_meshgrid(x)
    else:
        raise TypeError('cannot use in-place method to implement '
                        'out-of-place non-vectorized evaluation.')

    if dtype is None:
        dtype = np.result_type(*x)

    out = np.empty(out_shape, dtype=dtype)
    func(x, out=out, **kwargs)
    return out
Example #6
0
def _default_out_of_place(func, x, **kwargs):
    """Default in-place evaluation method."""
    if is_valid_input_array(x, func.domain.ndim):
        out_shape = out_shape_from_array(x)
    elif is_valid_input_meshgrid(x, func.domain.ndim):
        out_shape = out_shape_from_meshgrid(x)
    else:
        raise TypeError('cannot use in-place method to implement '
                        'out-of-place non-vectorized evaluation')

    dtype = func.space.out_dtype
    if dtype is None:
        dtype = np.result_type(*x)

    out = np.empty(out_shape, dtype=dtype)
    func(x, out=out, **kwargs)
    return out
Example #7
0
    def __call__(self, x, out=None):
        """Do the interpolation.

        Parameters
        ----------
        x : `meshgrid` or `numpy.ndarray`
            Evaluation points of the interpolator
        out : `numpy.ndarray`, optional
            Array to which the results are written. Needs to have
            correct shape according to input ``x``.

        Returns
        -------
        out : `numpy.ndarray`
            Interpolated values. If ``out`` was given, the returned
            object is a reference to it.
        """
        ndim = len(self.coord_vecs)
        if self.input_type == 'array':
            # Make a (1, n) array from one with shape (n,)
            x = x.reshape([ndim, -1])
            out_shape = out_shape_from_array(x)
        else:
            if len(x) != ndim:
                raise ValueError('number of vectors in x is {} instead of '
                                 'the grid dimension {}'
                                 ''.format(len(x), ndim))
            out_shape = out_shape_from_meshgrid(x)

        if out is not None:
            if not isinstance(out, np.ndarray):
                raise TypeError('`out` {!r} not a `numpy.ndarray` '
                                'instance'.format(out))
            if out.shape != out_shape:
                raise ValueError('output shape {} not equal to expected '
                                 'shape {}'.format(out.shape, out_shape))
            if out.dtype != self.values.dtype:
                raise ValueError('output dtype {} not equal to expected '
                                 'dtype {}'
                                 ''.format(out.dtype, self.values.dtype))

        indices, norm_distances = self._find_indices(x)
        return self._evaluate(indices, norm_distances, out)
Example #8
0
    def _evaluate(self, indices, norm_distances, out=None):
        """Evaluate linear interpolation.

        Modified for in-place evaluation and treatment of out-of-bounds
        points by implicitly assuming 0 at the next node."""
        # slice for broadcasting over trailing dimensions in self.values
        vslice = (slice(None),) + (None,) * (self.values.ndim - len(indices))

        out_shape = out_shape_from_meshgrid(norm_distances)
        out_dtype = norm_distances[0].dtype

        if out is None:
            out = np.zeros(out_shape, dtype=out_dtype)
        else:
            out[:] = 0.0

        # Weights and indices (per axis)
        low_weights, high_weights, edge_indices = _create_weight_edge_lists(
            indices, norm_distances, self.schemes, self.nn_variants)

        # Iterate over all possible combinations of [i, i+1] for each
        # axis, resulting in a loop of length 2**ndim
        for lo_hi, edge in zip(product(*([['l', 'h']] * len(indices))),
                               product(*edge_indices)):
            weight = 1.0
            # TODO: determine best summation order from array strides
            for lh, w_lo, w_hi in zip(lo_hi, low_weights, high_weights):

                # We don't multiply in place to exploit the cheap operations
                # in the beginning: sizes grow gradually as following:
                # (n, 1, 1, ...) -> (n, m, 1, ...) -> ...
                # Hence, it is faster to build up the weight array instead
                # of doing full-size operations from the beginning.
                if lh == 'l':
                    weight = weight * w_lo
                else:
                    weight = weight * w_hi
            out += np.asarray(self.values[edge]) * weight[vslice]
        return np.array(out, copy=False, ndmin=1)
Example #9
0
    def __call__(self, x, out=None, **kwargs):
        """Evaluate the function at one or multiple values ``x``.

        Parameters
        ----------
        x : object
            Input argument for the function evaluation. Conditions
            on ``x`` depend on vectorization:

            `False` : ``x`` must be a domain element

            `True` : ``x`` must be a `numpy.ndarray` with shape
            ``(d, N)``, where ``d`` is the number of dimensions of
            the function domain
            OR
            ``x`` is a sequence of `numpy.ndarray` with length
            ``space.ndim``, and the arrays can be broadcast
            against each other.

        out : `numpy.ndarray`, optional
            Output argument holding the result of the function
            evaluation, can only be used for vectorized
            functions. Its shape must be equal to
            ``np.broadcast(*x).shape``.

        bounds_check : bool
            Whether or not to check if all input points lie in
            the function domain. For vectorized evaluation,
            this requires the domain to implement
            `Set.contains_all`.

            Default: `True`

        Returns
        -------
        out : range element or array of elements
            Result of the function evaluation. If ``out`` was provided,
            the returned object is a reference to it.

        Raises
        ------
        TypeError
            If ``x`` is not a valid vectorized evaluation argument

            If ``out`` is not a range element or a `numpy.ndarray`
            of range elements

        ValueError
            If evaluation points fall outside the valid domain
        """
        bounds_check = kwargs.pop('bounds_check', True)
        if bounds_check and not hasattr(self.domain, 'contains_all'):
            raise AttributeError('bounds check not possible for '
                                 'domain {}, missing `contains_all()` '
                                 'method.'.format(self.domain))

        # Check for input type and determine output shape
        if is_valid_input_array(x, self.domain.ndim):
            out_shape = out_shape_from_array(x)
            scalar_out = False
            # For 1d, squeeze the array
            if self.domain.ndim == 1 and x.ndim == 2:
                x = x.squeeze()
        elif is_valid_input_meshgrid(x, self.domain.ndim):
            out_shape = out_shape_from_meshgrid(x)
            scalar_out = False
            # For 1d, fish out the vector from the tuple
            if self.domain.ndim == 1:
                x = x[0]
        elif x in self.domain:
            x = np.atleast_2d(x).T  # make a (d, 1) array
            out_shape = (1,)
            scalar_out = (out is None)
        else:
            # Unknown input
            raise TypeError('argument {!r} not a valid vectorized '
                            'input. Expected an element of the domain '
                            '{dom}, a ({dom.ndim}, n) array '
                            'or a length-{dom.ndim} meshgrid sequence.'
                            ''.format(x, dom=self.domain))

        # Check bounds if specified
        if bounds_check:
            if not self.domain.contains_all(x):
                raise ValueError('input contains points outside '
                                 'the domain {}.'.format(self.domain))

        # Call the function and check out shape, before or after
        if out is None:
            out = self._call(x, **kwargs)
            if out_shape != (1,) and out.shape != out_shape:
                raise ValueError('output shape {} not equal to shape '
                                 '{} expected from input.'
                                 ''.format(out.shape, out_shape))
        else:
            if not isinstance(out, np.ndarray):
                raise TypeError('output {!r} not a `numpy.ndarray` '
                                'instance.')
            if out_shape != (1,) and out.shape != out_shape:
                raise ValueError('output shape {} not equal to shape '
                                 '{} expected from input.'
                                 ''.format(out.shape, out_shape))
            self._call(x, out=out, **kwargs)

        # Check output values
        if bounds_check:
            if not self.range.contains_all(out):
                raise ValueError('output contains points outside '
                                 'the range {}.'
                                 ''.format(self.domain))

        # Numpy does not implement __complex__ for arrays (in contrast to
        # __float__), so we have to fish out the scalar ourselves.
        return self.range.element(out.ravel()[0]) if scalar_out else out
Example #10
0
    def __call__(self, x, out=None, **kwargs):
        """Return ``self(x[, out, **kwargs])``.

        Parameters
        ----------
        x : domain `element-like`, `meshgrid` or `numpy.ndarray`
            Input argument for the function evaluation. Conditions
            on ``x`` depend on its type:

            element-like: must be a castable to a domain element

            meshgrid: length must be ``space.ndim``, and the arrays must
            be broadcastable against each other.

            array:  shape must be ``(d, N)``, where ``d`` is the number
            of dimensions of the function domain

        out : `numpy.ndarray`, optional
            Output argument holding the result of the function
            evaluation, can only be used for vectorized
            functions. Its shape must be equal to
            ``np.broadcast(*x).shape``.

        Other Parameters
        ----------------
        bounds_check : `bool`
            If `True`, check if all input points lie in the function
            domain in the case of vectorized evaluation. This requires
            the domain to implement `Set.contains_all`.
            Default: `True`

        Returns
        -------
        out : range element or array of elements
            Result of the function evaluation. If ``out`` was provided,
            the returned object is a reference to it.

        Raises
        ------
        TypeError
            If ``x`` is not a valid vectorized evaluation argument

            If ``out`` is not a range element or a `numpy.ndarray`
            of range elements

        ValueError
            If evaluation points fall outside the valid domain
        """
        bounds_check = kwargs.pop('bounds_check', True)
        if bounds_check and not hasattr(self.domain, 'contains_all'):
            raise AttributeError('bounds check not possible for '
                                 'domain {}, missing `contains_all()` '
                                 'method'.format(self.domain))

        if bounds_check and not hasattr(self.range, 'contains_all'):
            raise AttributeError('bounds check not possible for '
                                 'range {}, missing `contains_all()` '
                                 'method'.format(self.range))

        ndim = getattr(self.domain, 'ndim', None)
        # Check for input type and determine output shape
        if is_valid_input_meshgrid(x, ndim):
            out_shape = out_shape_from_meshgrid(x)
            scalar_out = False
            # Avoid operations on tuples like x * 2 by casting to array
            if ndim == 1:
                x = x[0][None, ...]
        elif is_valid_input_array(x, ndim):
            x = np.asarray(x)
            out_shape = out_shape_from_array(x)
            scalar_out = False
            # For 1d, squeeze the array
            if ndim == 1 and x.ndim == 2:
                x = x.squeeze()
        elif x in self.domain:
            x = np.atleast_2d(x).T  # make a (d, 1) array
            out_shape = (1,)
            scalar_out = (out is None)
        else:
            # Unknown input
            txt_1d = ' or (n,)' if ndim == 1 else ''
            raise TypeError('Argument {!r} not a valid vectorized '
                            'input. Expected an element of the domain '
                            '{domain}, an array-like with shape '
                            '({domain.ndim}, n){} or a length-{domain.ndim} '
                            'meshgrid tuple.'
                            ''.format(x, txt_1d, domain=self.domain))

        # Check bounds if specified
        if bounds_check:
            if not self.domain.contains_all(x):
                raise ValueError('input contains points outside '
                                 'the domain {}'.format(self.domain))

        # Call the function and check out shape, before or after
        if out is None:
            if ndim == 1:
                try:
                    out = self._call(x, **kwargs)
                    if np.ndim(out) == 0 and not scalar_out:
                        # Don't accept scalar result. A typical situation where
                        # this occurs is with comparison operators, e.g.
                        # "return x > 0" which simply gives 'True' for a
                        # non-empty tuple (in Python 2). We raise TypeError
                        # to trigger the call with x[0].
                        raise TypeError
                    out = np.atleast_1d(np.squeeze(out))
                except (TypeError, IndexError):
                    # TypeError is raised if a meshgrid was used but the
                    # function expected an array (1d only). In this case we try
                    # again with the first meshgrid vector.
                    # IndexError is raised in expressions like x[x > 0] since
                    # "x > 0" evaluates to 'True', i.e. 1, and that index is
                    # out of range for a meshgrid tuple of length 1 :-). To get
                    # the real errors with indexing, we check again for the
                    # same scenario (scalar output when not valid) as in the
                    # first case.
                    out = self._call(x[0], **kwargs)
                    if np.ndim(out) == 0 and not scalar_out:
                        raise ValueError('invalid scalar output')
                    out = np.atleast_1d(np.squeeze(out))
            else:
                out = self._call(x, **kwargs)

            if self.out_dtype is not None:
                # Cast to proper dtype if needed
                out = out.astype(self.out_dtype)

            if out_shape != (1,) and out.shape != out_shape:
                # Try to broadcast the returned element if possible
                try:
                    out = np.broadcast_to(out, out_shape)
                except AttributeError:
                    # The above requires numpy 1.10, fallback impl else
                    shape = [m if n == 1 and m != 1 else 1
                             for n, m in zip(out.shape, out_shape)]
                    out = out + np.zeros(shape, dtype=out.dtype)
        else:
            if not isinstance(out, np.ndarray):
                raise TypeError('output {!r} not a `numpy.ndarray` '
                                'instance')
            if out_shape != (1,) and out.shape != out_shape:
                raise ValueError('output shape {} not equal to shape '
                                 '{} expected from input'
                                 ''.format(out.shape, out_shape))
            if self.out_dtype is not None and out.dtype != self.out_dtype:
                raise ValueError('`out.dtype` ({}) does not match out_dtype '
                                 '({})'.format(out.dtype, self.out_dtype))

            if ndim == 1:
                # TypeError for meshgrid in 1d, but expected array (see above)
                try:
                    self._call(x, out=out, **kwargs)
                except TypeError:
                    self._call(x[0], out=out, **kwargs)
            else:
                self._call(x, out=out, **kwargs)

        # Check output values
        if bounds_check:
            if not self.range.contains_all(out):
                raise ValueError('output contains points outside '
                                 'the range {}'
                                 ''.format(self.range))

        # Numpy does not implement __complex__ for arrays (in contrast to
        # __float__), so we have to fish out the scalar ourselves.
        return self.range.element(out.ravel()[0]) if scalar_out else out