def one_vec(x, out=None): """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)
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
def _check_interp_input(x, f): """Return transformed ``x``, its input type and whether it's scalar. On bad input, raise ``ValueError``. """ errmsg_1d = ( 'bad input: expected scalar, array-like of shape (1,), (n,) or ' '(1, n), or a meshgrid of length 1; got {!r}' ''.format(x) ) errmsg_nd = ( 'bad input: expected scalar, array-like of shape ({0},) or ' '({0}, n), or a meshgrid of length {0}; got {1!r}' ''.format(f.ndim, x) ) if is_valid_input_meshgrid(x, f.ndim): x_is_scalar = False x_type = 'meshgrid' else: x = np.asarray(x) if f.ndim == 1 and x.shape == (): x_is_scalar = True x = x.reshape((1, 1)) elif f.ndim == 1 and x.ndim == 1: x_is_scalar = False x = x.reshape((1, x.size)) elif f.ndim > 1 and x.shape == (f.ndim,): x_is_scalar = True x = x.reshape((f.ndim, 1)) else: x_is_scalar = False if not is_valid_input_array(x, f.ndim): errmsg = errmsg_1d if f.ndim == 1 else errmsg_nd raise ValueError(errmsg) x_type = 'array' return x, x_type, x_is_scalar
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, optional 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) 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) # squeeze to remove extra axes. out = np.squeeze(out) else: out = self._call(x, **kwargs) # Cast to proper dtype if needed, also convert to array if out # is scalar. out = np.asarray(out, self.out_dtype) if out_shape != (1, ) and out.shape != out_shape: # Try to broadcast the returned element if possible out = _broadcast_to(out, 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)) 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
def contains_all(self, other, atol=0.0): """Return ``True`` if all points defined by ``other`` are contained. Parameters ---------- other : Collection of points to be tested. Can be given as a single point, a ``(d, N)`` array-like where ``d`` is the number of dimensions, or a length-``d`` `meshgrid` tuple. atol : float, optional The maximum allowed distance in 'inf'-norm between the other set and this interval product. Returns ------- contains : bool ``True`` if all points are contained, ``False`` otherwise. Examples -------- >>> min_pt, max_pt = [-1, 0, 2], [-0.5, 0, 3] >>> rbox = IntervalProd(min_pt, max_pt) Arrays are expected in ``(ndim, npoints)`` shape: >>> arr = np.array([[-1, 0, 2], # defining one point at a time ... [-0.5, 0, 2]]) >>> rbox.contains_all(arr.T) True Implicit meshgrids defined by coordinate vectors: >>> from odl.discr.grid import sparse_meshgrid >>> vec1 = (-1, -0.9, -0.7) >>> vec2 = (0, 0, 0) >>> vec3 = (2.5, 2.75, 3) >>> mg = sparse_meshgrid(vec1, vec2, vec3) >>> rbox.contains_all(mg) True Works also with an arbitrary iterable: >>> rbox.contains_all([[-1, -0.5], # define points by axis ... [0, 0], ... [2, 2]]) True Grids are also accepted as input: >>> agrid = odl.uniform_grid(rbox.min_pt, rbox.max_pt, [3, 1, 3]) >>> rbox.contains_all(agrid) True """ atol = float(atol) # First try optimized methods if other in self: return True if hasattr(other, 'meshgrid'): return self.contains_all(other.meshgrid, atol=atol) elif is_valid_input_meshgrid(other, self.ndim): vecs = tuple(vec.squeeze() for vec in other) mins = np.fromiter((np.min(vec) for vec in vecs), dtype=float) maxs = np.fromiter((np.max(vec) for vec in vecs), dtype=float) return (np.all(mins >= self.min_pt - atol) and np.all(maxs <= self.max_pt + atol)) # Convert to array and check each element other = np.asarray(other) if is_valid_input_array(other, self.ndim): if self.ndim == 1: mins = np.min(other) maxs = np.max(other) else: mins = np.min(other, axis=1) maxs = np.max(other, axis=1) return np.all(mins >= self.min_pt) and np.all(maxs <= self.max_pt) else: return False
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, optional 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) 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) # squeeze to remove extra axes. out = np.squeeze(out) else: out = self._call(x, **kwargs) # Cast to proper dtype if needed, also convert to array if out # is scalar. out = np.asarray(out, self.out_dtype) if out_shape != (1,) and out.shape != out_shape: # Try to broadcast the returned element if possible out = _broadcast_to(out, 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)) 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