def _prep(self, order='C'): M, N, K = 2, 3, 4 rng = nlcpy.random.default_rng(0) a = nlcpy.asarray(rng.random((M, K), dtype='f8'), order=order) b = nlcpy.asarray(rng.random((K, N), dtype='f8'), order=order) c = nlcpy.empty((M, N), dtype='f8', order=order) return M, N, K, a, b, c
def test_fft_with_order(dtype, order, fft): # Check that FFT/IFFT produces identical results for C, Fortran and # non contiguous arrays rng = np.random.RandomState(42) # X = rng.rand(8, 7, 13).astype(dtype, copy=False) X = rng.rand((8, 7, 13)).astype(dtype, copy=False) # See discussion in pull/14178 _tol = 8.0 * np.sqrt(np.log2(X.size)) * np.finfo(X.dtype).eps if order == 'F': # Y = np.asfortranarray(X) Y = np.asarray(X, order='F') else: # Make a non contiguous array # #Y = X[::-1] # #X = np.ascontiguousarray(X[::-1]) Y = X[:-1] X = np.asarray(X[:-1], order='C') if fft.__name__.endswith('fft'): for axis in range(3): X_res = fft(X, axis=axis) Y_res = fft(Y, axis=axis) assert_allclose(X_res, Y_res, atol=_tol, rtol=_tol) elif fft.__name__.endswith(('fft2', 'fftn')): axes = [(0, 1), (1, 2), (0, 2)] if fft.__name__.endswith('fftn'): axes.extend([(0, ), (1, ), (2, ), None]) for ax in axes: X_res = fft(X, axes=ax) Y_res = fft(Y, axes=ax) assert_allclose(X_res, Y_res, atol=_tol, rtol=_tol) else: raise ValueError()
def _lange(x, norm, axis): order = 'F' if x.flags.f_contiguous and not x.flags.c_contiguous else 'C' dtype = 'f' if x.dtype.char in 'fF' else 'd' if x.size == 0: shape = [x.shape[i] for i in set(range(x.ndim)) - set(axis)] return nlcpy.zeros(shape, dtype=dtype) if norm in (None, 'fro', 'f'): if x.dtype.kind == 'c': x = abs(x) return nlcpy.sqrt(nlcpy.sum(x * x, axis=axis)) if norm == nlcpy.inf: norm = 'I' else: norm = '1' lwork = x.shape[0] if norm == 'I' else 1 x = nlcpy.asarray(nlcpy.moveaxis(x, (axis[0], axis[1]), (0, 1)), order='F') y = nlcpy.empty(x.shape[2:], dtype=dtype, order='F') work = nlcpy.empty(lwork, dtype=dtype) fpe = request._get_fpe_flag() args = ( ord(norm), x._ve_array, y._ve_array, work._ve_array, veo.OnStack(fpe, inout=veo.INTENT_OUT), ) request._push_and_flush_request( 'nlcpy_norm', args, ) return nlcpy.asarray(y, order=order)
def wrap_func(*args, **kwargs): is_out = False try: return func(*args, **kwargs) except NotImplementedError: f = getattr(numpy, func.__name__) # retrieve input ndarrays of NLCPy from VE largs = list(args) for i, _l in enumerate(largs): if isinstance(_l, nlcpy.ndarray): largs[i] = _l.get() for k, v in kwargs.items(): if isinstance(v, nlcpy.ndarray): kwargs[k] = v.get() if k == 'out': is_out = True in_out = v # call NumPy function ret = f(*largs, **kwargs) # transfer the return values to VE if isinstance(ret, numpy.ndarray) or \ numpy.isscalar(ret) and numpy.dtype(type(ret)).char in '?iIlLfFdD': vp_ret = nlcpy.asarray(ret) if is_out: in_out[...] = vp_ret return vp_ret elif isinstance(ret, numpy.lib.npyio.NpzFile): return nlcpy.NpzFile(ret) elif isinstance(ret, dict): for key, val in ret.items(): ret[key] = nlcpy.asarray(val) return ret elif isinstance(ret, (list, tuple)): vpp = [] for x in ret: if isinstance(x, numpy.ndarray) is False: if numpy.any(isinstance(x, numpy.ndarray)) is True: b_ret = [nlcpy.asarray(i) for i in x] else: b_ret = x else: b_ret = nlcpy.asarray(x) vpp.append(b_ret) vp_ret = vpp if isinstance(ret, tuple): vp_ret = tuple(vp_ret) return vp_ret else: return ret
def test_eigvals(self, dtype, order): a = nlcpy.asarray(testing.shaped_random(self.shape, nlcpy, dtype), order=order) args = dict() args["a"] = a w1 = nlcpy.linalg.eigvals(**args) w2, v = nlcpy.linalg.eig(**args) numpy.testing.assert_allclose(w1, w2, atol=1e-12, rtol=1e-12)
def count_nonzero(a, axis=None, keepdims=False): """Counts the number of non-zero values in the array ``a``. The word "non-zero" is in reference to the Python 2.x built-in method ``__nonzero__()`` (renamed ``__bool__()`` in Python 3.x) of Python objects that tests an object's "truthfulness". For example, any number is considered truthful if it is nonzero, whereas any string is considered truthful if it is not the empty string. Thus, this function (recursively) counts how many elements in a (and in sub-arrays thereof) have their ``__nonzero__()`` or ``__bool__()`` method evaluated to ``True``. Parameters ---------- a : array_like The array for which to count non-zeros. axis : int or tuple, optional Axis or tuple of axes along which to count non-zeros. Default is None, meaning that non-zeros will be counted along a flattened version of ``a``. keepdims : bool, optional If this is set to True, the axes that are counted are left in the result as dimensions with size one. With this option, the result will broadcast correctly against the input array. Returns ------- count : int or array of int Number of non-zero values in the array along a given axis. Otherwise, the total number of non-zero values in the array is returned. See Also -------- nonzero : Returns the indices of the elements that are non-zero. Examples -------- >>> import nlcpy as vp >>> vp.count_nonzero(vp.eye(4)) array(4) >>> a = vp.array([[0, 1, 7, 0], [3, 0, 2, 19]]) >>> vp.count_nonzero(a) array(5) >>> vp.count_nonzero(a, axis=0) array([1, 1, 2, 1]) >>> vp.count_nonzero(a, axis=1) array([2, 3]) >>> vp.count_nonzero(a, axis=1, keepdims=True) array([[2], [3]]) """ a = nlcpy.asarray(a).astype('?', copy=False) return a.sum(axis=axis, dtype=nlcpy.intp, keepdims=keepdims)
def _precheck_func_for_ufunc( self, args, kw, impl, name, op, type_check, accept_error): kw[name] = nlcpy nlcpy_result, nlcpy_error, nlcpy_msg, nlcpy_tb = \ helper._call_func(self, impl, args, kw) kw[name] = numpy numpy_result, numpy_error, numpy_msg, numpy_tb = \ helper._call_func(self, impl, args, kw) if nlcpy_msg is not None: nlcpy_msg = re.sub(r'nlcpy', "numpy", nlcpy_msg) if nlcpy_error or numpy_error: helper._check_nlcpy_numpy_error(self, nlcpy_error, nlcpy_msg, nlcpy_tb, numpy_error, numpy_msg, numpy_tb, accept_error=accept_error) return None, None if not isinstance(nlcpy_result, (tuple, list)): nlcpy_result = nlcpy_result, if not isinstance(numpy_result, (tuple, list)): numpy_result = numpy_result, # shape check for numpy_r, nlcpy_r in zip(numpy_result, nlcpy_result): assert numpy.asarray(numpy_r).shape == nlcpy.asarray(nlcpy_r).shape # type check if type_check: for numpy_r, nlcpy_r in zip(numpy_result, nlcpy_result): if type(numpy_r) is not numpy.ndarray: numpy_r = numpy.array(numpy_r) if type(nlcpy_r) is not nlcpy.ndarray: nlcpy_r = nlcpy.array(numpy_r) if numpy_r.dtype != nlcpy_r.dtype: msg = ['\n'] msg.append(' numpy.dtype: {}'.format(numpy_r.dtype)) msg.append(' nlcpy.dtype: {}'.format(nlcpy_r.dtype)) raise AssertionError('\n'.join(msg)) return nlcpy_result, numpy_result
def test_reshape_contiguity(self): shape_init, shape_final = self.shape_in_out a_nlcpy = testing.shaped_arange(shape_init, xp=nlcpy) a_nlcpy = nlcpy.asarray(a_nlcpy, order=self.order_init) b_nlcpy = a_nlcpy.reshape(shape_final, order=self.order_reshape) a_numpy = testing.shaped_arange(shape_init, xp=numpy) a_numpy = numpy.asarray(a_numpy, order=self.order_init) b_numpy = a_numpy.reshape(shape_final, order=self.order_reshape) assert b_nlcpy.flags.f_contiguous == b_numpy.flags.f_contiguous assert b_nlcpy.flags.c_contiguous == b_numpy.flags.c_contiguous testing.assert_array_equal(b_nlcpy.strides, b_numpy.strides) testing.assert_array_equal(b_nlcpy, b_numpy)
def test_array_function(self): a = numpy.random.randn(100, 100) a_cpu = numpy.asarray(a) a_ve = nlcpy.asarray(a) # The numpy call for both CPU and ve arrays is intentional to test the # __array_function__ protocol qr_cpu = numpy.linalg.qr(a_cpu) qr_ve = numpy.linalg.qr(a_ve) if isinstance(qr_cpu, tuple): for b_cpu, b_ve in zip(qr_cpu, qr_ve): self.assertEqual(b_cpu.dtype, b_ve.dtype) nlcpy.testing.assert_allclose(b_cpu, b_ve, atol=1e-4) else: self.assertEqual(qr_cpu.dtype, qr_ve.dtype) nlcpy.testing.assert_allclose(qr_cpu, qr_ve, atol=1e-4)
def full_like(a, fill_value, dtype=None, order='K', subok=False, shape=None): """Returns a full array with the same shape and type as a given array. Parameters ---------- a : array_like The shape and dtype of *a* define these same attributes of the returned array. fill_value : scalar Fill value. dtype : dtype, optional Overrides the data type of the result. order : {'C', 'F', 'A', or 'K'}, optional Overrides the memory layout of the result. 'C' means C-order, 'F' means F-order, 'A' means 'F' if *a* is Fortran contiguous, 'C' otherwise. 'K' means match the layout of *a* as closely as possible. subok : bool, optional Not implemented. shape : int or sequence of ints, optional Overrides the shape of the result. If order='K' and the number of dimensions is unchanged, will try to keep order, otherwise, order='C' is implied. Returns ------- out : ndarray Array of *fill_value* with the same shape and type as *a*. See Also -------- empty_like : Returns a new array with the same shape and type as a given array. ones_like : Returns an array of ones with the same shape and type as a given array. zeros_like : Returns an array of zeros with the same shape and type as a given array. full : Returns a new array of given shape and type, filled with fill_value. Examples -------- >>> import nlcpy as vp >>> x = vp.arange(6, dtype=int) >>> vp.full_like(x, 1) array([1, 1, 1, 1, 1, 1]) >>> vp.full_like(x, 0.1) array([0, 0, 0, 0, 0, 0]) >>> vp.full_like(x, 0.1, dtype=vp.double) array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1]) >>> vp.full_like(x, vp.nan, dtype=vp.double) array([nan, nan, nan, nan, nan, nan]) >>> y = vp.arange(6, dtype=vp.double) >>> vp.full_like(y, 0.1) array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1]) """ if subok is not False: raise NotImplementedError('subok in full_like is not implemented yet.') a = nlcpy.asanyarray(a) if shape is None: shape = a.shape if dtype is None: dtype = a.dtype else: dtype = nlcpy.dtype(dtype) if numpy.dtype(dtype).kind == 'V': raise NotImplementedError( 'void dtype in full_like is not implemented yet.') if order is None or order in 'kKaA': if a._f_contiguous and not a._c_contiguous: order = 'F' else: order = 'C' if numpy.isscalar(fill_value): if numpy.iscomplex(fill_value): if dtype in ('complex64', 'complex128'): pass else: fill_value = numpy.real(fill_value) warnings.warn( 'Casting complex values to real discards the imaginary part', numpy.ComplexWarning, stacklevel=2) out = nlcpy.ndarray(shape=shape, dtype=dtype, order=order) out.fill(fill_value) elif fill_value is None: raise NotImplementedError('fill_value in nlcpy.full_like is None') else: fill_value = nlcpy.asarray(fill_value) out = nlcpy.array(nlcpy.broadcast_to(fill_value, shape=shape), dtype=dtype, order=order) return out
def full(shape, fill_value, dtype=None, order='C'): """Returns a new array of given shape and type, filled with *fill_value*. Parameters ---------- shape : int or sequence of ints Shape of the new array, e.g., ``(2, 3)`` or ``2``. fill_value : scalar Fill value. dtype : dtype, optional The desired dtype for the array, e.g, ``nlcpy.int64``. Default is ``nlcpy.float64``. order : {'C', 'F'}, optional Whether to store multidimensional data in C- or Fortran-contiguous (row- or column-wise) order in memory. Returns ------- out : ndarray Array of *fill_value* with the given shape, dtype, and order. See Also -------- full_like : Returns a full array with the same shape and type as a given array. empty : Returns a new array of given shape and type, without initializing entries. ones : Returns a new array of given shape and type, filled with ones. zeros : Returns a new array of given shape and type, filled with zeros. Examples -------- >>> import nlcpy as vp >>> vp.full((2, 2), vp.inf) array([[inf, inf], [inf, inf]]) >>> vp.full((2, 2), 10) array([[10, 10], [10, 10]]) """ if numpy.dtype(dtype).kind == 'V': raise NotImplementedError('void dtype in full is not implemented yet.') if dtype is None: dtype = numpy.result_type(fill_value) else: dtype = nlcpy.dtype(dtype) if numpy.isscalar(fill_value): if numpy.iscomplex(fill_value): if dtype in ('complex64', 'complex128'): pass else: fill_value = numpy.real(fill_value) warnings.warn( 'Casting complex values to real discards the imaginary part', numpy.ComplexWarning, stacklevel=2) out = nlcpy.ndarray(shape=shape, dtype=dtype, order=order) out.fill(fill_value) elif fill_value is None: raise NotImplementedError('fill_value in nlcpy.full is None') else: fill_value = nlcpy.asarray(fill_value) out = nlcpy.array(nlcpy.broadcast_to(fill_value, shape=shape), dtype=dtype, order=order) return out
def where(condition, x=None, y=None): """Returns elements chosen from *x* or *y* depending on *condition*. Note ---- When only condition is provided, this function is a shorthand for ``nlcpy.asarray(condition).nonzero()``. Using nonzero directly should be preferred, as it behaves correctly for subclasses. The rest of this documentation covers only the case where all three arguments are provided. Parameters ---------- condition : array_like, bool Where True, yield *x*, otherwise yield *y*. x, y : array_like Values from which to choose. *x*, *y* and *condition* need to be broadcastable to some shape. Returns ------- out : ndarray An array with elements from *x* where *condition* is True, and elements from *y* elsewhere. Note ---- If all the arrays are 1-D, :func:`where` is equivalent to:: [xv if c else yv for c, xv, yv in zip(condition, x, y)] See Also -------- nonzero : Returns the indices of the elements that are non-zero. Examples -------- >>> import nlcpy as vp >>> a = vp.arange(10) >>> a array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> vp.where(a < 5, a, 10*a) array([ 0, 1, 2, 3, 4, 50, 60, 70, 80, 90]) This can be used on multidimensional arrays too: >>> vp.where([[True, False], [True, True]], ... [[1, 2], [3, 4]], ... [[9, 8], [7, 6]]) array([[1, 8], [3, 4]]) The shapes of x, y, and the condition are broadcast together: >>> x = vp.arange(3).reshape([3,1]) >>> y = vp.arange(4).reshape([1,4]) >>> vp.where(x < y, x, 10 + y) # both x and 10+y are broadcast array([[10, 0, 0, 0], [10, 11, 1, 1], [10, 11, 12, 2]]) >>> a = vp.array([[0, 1, 2], ... [0, 2, 4], ... [0, 3, 6]]) >>> vp.where(a < 4, a, -1) # -1 is broadcast array([[ 0, 1, 2], [ 0, 2, -1], [ 0, 3, -1]]) """ if condition is None: condition = False arr = nlcpy.asarray(condition) if x is None and y is None: return nlcpy.nonzero(arr) if x is None or y is None: raise ValueError("either both or neither of x and y should be given") if not isinstance(x, nlcpy.ndarray): x = numpy.asarray(x) if not isinstance(y, nlcpy.ndarray): y = numpy.asarray(y) ret_type = numpy.result_type(x, y) arr_x = nlcpy.asarray(x, dtype=ret_type) arr_y = nlcpy.asarray(y, dtype=ret_type) if arr.dtype != bool: arr = (arr != 0) values, shape = core._broadcast_core((arr, arr_x, arr_y)) ret = nlcpy.ndarray(shape=shape, dtype=ret_type) request._push_request( "nlcpy_where", "indexing_op", (ret, values[0], values[1], values[2]), ) return ret
def insert(arr, obj, values, axis=None): """Inserts values along the given axis before the given indices. Parameters ---------- arr : array_like Input array. obj : int, slice or sequence of ints Object that defines the index or indices before which values is inserted. Support for multiple insertions when obj is a single scalar or a sequence with one element (similar to calling insert multiple times). values : array_like Values to insert into arr. If the type of values is different from that of arr, values is converted to the type of arr. values should be shaped so that arr[...,obj,...] = values is legal. axis : int, optional Axis along which to insert values. If axis is None then arr is flattened first. Returns ------- out : ndarray A copy of arr with values inserted. Note that insert does not occur in-place: a new array is returned. If axis is None, out is a flattened array. Note: Note that for higher dimensional inserts obj=0 behaves very different from obj=[0] just like arr[:,0,:] = values is different from arr[:,[0],:] = values. See Also -------- append : Appends values to the end of an array. concatenate : Joins a sequence of arrays along an existing axis. delete : Returns a new array with sub-arrays along an axis deleted. Examples -------- >>> import nlcpy as vp >>> from nlcpy import testing >>> a = vp.array([[1, 1], [2, 2], [3, 3]]) >>> a array([[1, 1], [2, 2], [3, 3]]) >>> vp.insert(a, 1, 5) array([1, 5, 1, 2, 2, 3, 3]) >>> vp.insert(a, 1, 5, axis=1) array([[1, 5, 1], [2, 5, 2], [3, 5, 3]]) Difference between sequence and scalars: >>> vp.insert(a, [1], [[1],[2],[3]], axis=1) array([[1, 1, 1], [2, 2, 2], [3, 3, 3]]) >>> vp.testing.assert_array_equal( ... vp.insert(a, 1, [1, 2, 3], axis=1), ... vp.insert(a, [1], [[1],[2],[3]], axis=1)) >>> b = a.flatten() >>> b array([1, 1, 2, 2, 3, 3]) >>> vp.insert(b, [2, 2], [5, 6]) array([1, 1, 5, 6, 2, 2, 3, 3]) >>> vp.insert(b, slice(2, 4), [5, 6]) array([1, 1, 5, 2, 6, 2, 3, 3]) >>> vp.insert(b, [2, 2], [7.13, False]) # type casting array([1, 1, 7, 0, 2, 2, 3, 3]) >>> x = vp.arange(8).reshape(2, 4) >>> idx = (1, 3) >>> vp.insert(x, idx, 999, axis=1) array([[ 0, 999, 1, 2, 999, 3], [ 4, 999, 5, 6, 999, 7]]) """ a = nlcpy.asarray(arr) if axis is None: if a.ndim != 1: a = a.ravel() axis = 0 elif isinstance(axis, nlcpy.ndarray) or isinstance(axis, numpy.ndarray): axis = int(axis) elif not isinstance(axis, int): raise TypeError("an integer is required " "(got type {0})".format(type(axis).__name__)) if axis < -a.ndim or axis >= a.ndim: raise nlcpy.AxisError( "axis {0} is out of bounds for array of dimension {1}".format(axis, a.ndim)) if axis < 0: axis += a.ndim if type(obj) is slice: start, stop, step = obj.indices(a.shape[axis]) obj = nlcpy.arange(start, stop, step) else: obj = nlcpy.array(obj) if obj.dtype.char == '?': warnings.warn( "in the future insert will treat boolean arrays and " "array-likes as a boolean index instead of casting it to " "integer", FutureWarning, stacklevel=3) elif obj.dtype.char in 'fdFD': if obj.size == 1: raise TypeError( "slice indices must be integers or " "None or have an __index__ method") elif obj.size > 0: raise IndexError( 'arrays used as indices must be of integer (or boolean) type') elif obj.dtype.char in 'IL': if obj.size == 1: objval = obj[()] if obj.ndim == 0 else obj[0] if objval > a.shape[axis]: raise IndexError( "index {0} is out of bounds for axis {1} with size {2}".format( objval, axis, a.shape[axis])) else: tmp = 'float64' if obj.dtype.char == 'L' else 'int64' raise UFuncTypeError( "Cannot cast ufunc 'add' output from dtype('{0}') to " "dtype('{1}') with casting rule 'same_kind'".format(tmp, obj.dtype)) obj = obj.astype('l') if obj.ndim > 1: raise ValueError( "index array argument obj to insert must be one dimensional or scalar") if obj.ndim == 0: if obj > a.shape[axis] or obj < -a.shape[axis]: raise IndexError( "index {0} is out of bounds for axis {1} with size {2}".format( obj[()] if obj > 0 else obj[()] + a.shape[axis], axis, a.shape[axis])) newshape = list(a.shape) if obj.size == 1: values = nlcpy.array(values, copy=False, ndmin=a.ndim, dtype=a.dtype) if obj.ndim == 0: values = nlcpy.moveaxis(values, 0, axis) newshape[axis] += values.shape[axis] obj = nlcpy.array(nlcpy.broadcast_to(obj, values.shape[axis])) val_shape = list(a.shape) val_shape[axis] = values.shape[axis] values = nlcpy.broadcast_to(values, val_shape) else: newshape[axis] += obj.size values = nlcpy.array(values, copy=False, ndmin=a.ndim, dtype=a.dtype) val_shape = list(a.shape) val_shape[axis] = obj.size values = nlcpy.broadcast_to(values, val_shape) out = nlcpy.empty(newshape, dtype=a.dtype) work = nlcpy.zeros(obj.size + out.shape[axis] + 2, dtype='l') work[-1] = -1 request._push_request( 'nlcpy_insert', 'manipulation_op', (a, obj, values, out, axis, work) ) if work[-1] != -1: raise IndexError( "index {0} is out of bounds for axis {1} with size {2}" .format(obj[work[-1]], axis, out.shape[axis])) return out
def qr(a, mode='reduced'): """Computes the qr factorization of a matrix. Factor the matrix *a* as *qr*, where *q* is orthonormal and *r* is upper-triangular. Parameters ---------- a : (M, N) array_like Matrix to be factored. mode : {'reduced', 'complete', 'r', 'raw', 'full', 'economic'}, optional If K = min(M, N), then - 'reduced' : returns q, r with dimensions (M, K), (K, N) (default) - 'complete' : returns q, r with dimensions (M, M), (M, N) - 'r' : returns r only with dimensions (K, N) - 'raw' : returns h, tau with dimensions (N, M), (K,) - 'full' or 'f' : alias of 'reduced', deprecated - 'economic' or 'e' : returns h from 'raw', deprecated. Returns ------- q : ndarray, optional A matrix with orthonormal columns. When mode = 'complete' the result is an orthogonal/unitary matrix depending on whether or not a is real/complex. The determinant may be either +/- 1 in that case. r : ndarray, optional The upper-triangular matrix. (h, tau) : ndarray, optional The array h contains the Householder reflectors that generate q along with r. The tau array contains scaling factors for the reflectors. In the deprecated 'economic' mode only h is returned. Note ---- This is an interface to the LAPACK routines ``dgeqrf``, ``zgeqrf``, ``dorgqr``, and ``zungqr``. For more information on the qr factorization, see for example: https://en.wikipedia.org/wiki/QR_factorization Note that when 'raw' option is specified the returned arrays are of type "float64" or "complex128" and the h array is transposed to be FORTRAN compatible. Examples -------- >>> import numpy as np >>> import nlcpy as vp >>> from nlcpy import testing >>> a = vp.random.randn(9, 6) >>> q, r = vp.linalg.qr(a) >>> vp.testing.assert_allclose(a, vp.dot(q, r)) # a does equal qr >>> r2 = vp.linalg.qr(a, mode='r') >>> r3 = vp.linalg.qr(a, mode='economic') >>> # mode='r' returns the same r as mode='full' >>> vp.testing.assert_allclose(r, r2) >>> # But only triu parts are guaranteed equal when mode='economic' >>> vp.testing.assert_allclose(r, np.triu(r3[:6,:6], k=0)) Example illustrating a common use of qr: solving of least squares problems What are the least-squares-best *m* and *y0* in ``y = y0 + mx`` for the following data: {(0,1), (1,0), (1,2), (2,1)}. (Graph the points and you’ll see that it should be y0 = 0, m = 1.) The answer is provided by solving the over-determined matrix equation ``Ax = b``, where:: A = array([[0, 1], [1, 1], [1, 1], [2, 1]]) x = array([[y0], [m]]) b = array([[1], [0], [2], [1]]) If A = qr such that q is orthonormal (which is always possible via Gram-Schmidt), then ``x = inv(r) * (q.T) * b``. (In practice, however, we simply use :func:`lstsq`.) >>> A = vp.array([[0, 1], [1, 1], [1, 1], [2, 1]]) >>> A array([[0, 1], [1, 1], [1, 1], [2, 1]]) >>> b = vp.array([1, 0, 2, 1]) >>> q, r = vp.linalg.qr(A) >>> p = vp.dot(q.T, b) >>> vp.dot(vp.linalg.inv(r), p) array([1.1102230246251565e-16, 1.0000000000000002e+00]) """ if mode not in ('reduced', 'complete', 'r', 'raw'): if mode in ('f', 'full'): msg = "".join( ("The 'full' option is deprecated in favor of 'reduced'.\n", "For backward compatibility let mode default.")) warnings.warn(msg, DeprecationWarning, stacklevel=3) mode = 'reduced' elif mode in ('e', 'economic'): msg = "The 'economic' option is deprecated." warnings.warn(msg, DeprecationWarning, stacklevel=3) mode = 'economic' else: raise ValueError("Unrecognized mode '%s'" % mode) a = nlcpy.asarray(a) util._assertRank2(a) if a.dtype == 'F': dtype = 'D' a_dtype = 'F' elif a.dtype == 'D': dtype = 'D' a_dtype = 'D' elif a.dtype == 'f': dtype = 'd' a_dtype = 'f' else: dtype = 'd' a_dtype = 'd' m, n = a.shape if a.size == 0: if mode == 'reduced': return nlcpy.empty((m, 0), a_dtype), nlcpy.empty((0, n), a_dtype) elif mode == 'complete': return nlcpy.identity(m, a_dtype), nlcpy.empty((m, n), a_dtype) elif mode == 'r': return nlcpy.empty((0, n), a_dtype) elif mode == 'raw': return nlcpy.empty((n, m), dtype), nlcpy.empty((0, ), dtype) else: return nlcpy.empty((m, n), a_dtype), nlcpy.empty((0, ), a_dtype) a = nlcpy.asarray(a, dtype=dtype, order='F') k = min(m, n) if mode == 'complete': if m > n: x = nlcpy.empty((m, m), dtype=dtype, order='F') x[:m, :n] = a a = x r_shape = (m, n) elif mode in ('r', 'reduced', 'economic'): r_shape = (k, n) else: r_shape = 1 jobq = 0 if mode in ('r', 'raw', 'economic') else 1 tau = nlcpy.empty(k, dtype=dtype) r = nlcpy.zeros(r_shape, dtype=dtype) work = nlcpy.empty(n * 64, dtype=dtype) fpe = request._get_fpe_flag() args = ( m, n, jobq, a._ve_array, tau._ve_array, r._ve_array, work._ve_array, veo.OnStack(fpe, inout=veo.INTENT_OUT), ) request._push_and_flush_request( 'nlcpy_qr', args, ) if mode == 'raw': return a.T, tau if mode == 'r': return nlcpy.asarray(r, dtype=a_dtype) if mode == 'economic': return nlcpy.asarray(a, dtype=a_dtype) mc = m if mode == 'complete' else k q = nlcpy.asarray(a[:, :mc], dtype=a_dtype, order='C') r = nlcpy.asarray(r, dtype=a_dtype, order='C') return q, r
def sort(a, axis=-1, kind=None, order=None): """Returns a sorted copy of an array. Parameters ---------- a : array_like Array to be sorted. axis : int or None, optional Axis along which to sort. If None, the array is flattened before sorting. The default is -1, which sorts along the last axis. kind : {'None','stable'}, optional Sorting algorithm. The default is 'stable', kind only supported 'stable'. ('None' is treated as 'stable'.) order : str or list of str, optional In the current NLCPy, This argument is not supported. The default is 'None'. Returns ------- sorted_array : ndarray Array of the same type and shape as *a*. Restriction ----------- *NotImplementedError*: - If *kind* is not None and ``kind != 'stable'``. - If *order* is not None. - If 'c' is contained in *a.dtype.kind*. Note ---- 'stable' uses the radix sort for all data types. See Also -------- ndarray.sort : Method to sort an array in-place. argsort : Indirect sort. Examples -------- >>> import nlcpy as vp >>> a = vp.array([[1,4],[3,1]]) >>> vp.sort(a) # sort along the last axis array([[1, 4], [1, 3]]) >>> vp.sort(a, axis=None) # sort the flattened array array([1, 1, 3, 4]) >>> vp.sort(a, axis=0) # sort along the first axis array([[1, 1], [3, 4]]) """ a = nlcpy.asarray(a) if kind is not None and kind not in 'stable': raise NotImplementedError('kind only supported \'stable\'.') if order is not None: raise NotImplementedError('order is not implemented.') if a.dtype.kind in ('c', ): raise NotImplementedError('Unsupported dtype %s' % a.dtype) if axis is None: ret = a.flatten() axis = -1 else: ret = a.copy() ret.sort(axis=axis, kind=kind, order=order) return ret
def _geev(a, jobvr): a = nlcpy.asarray(a) util._assertRankAtLeast2(a) util._assertNdSquareness(a) # used to match the contiguous of result to numpy. c_order = a.flags.c_contiguous or sum([i > 1 for i in a.shape[:-2]]) < 2 a_complex = a.dtype.char in 'FD' if a.dtype.char == 'F': dtype = 'D' f_dtype = 'f' c_dtype = 'F' elif a.dtype.char == 'D': dtype = 'D' f_dtype = 'd' c_dtype = 'D' else: dtype = 'd' if a.dtype.char == 'f': f_dtype = 'f' c_dtype = 'F' else: f_dtype = 'd' c_dtype = 'D' if a.size == 0: dtype = c_dtype if a_complex else f_dtype w = nlcpy.empty(shape=a.shape[:-1], dtype=dtype) if jobvr: vr = nlcpy.empty(shape=a.shape, dtype=dtype) return w, vr else: return w a = nlcpy.array(nlcpy.moveaxis(a, (-1, -2), (1, 0)), dtype=dtype, order='F') wr = nlcpy.empty(a.shape[1:], dtype=dtype, order='F') wi = nlcpy.empty(a.shape[1:], dtype=dtype, order='F') vr = nlcpy.empty(a.shape if jobvr else 1, dtype=dtype, order='F') vc = nlcpy.empty(a.shape if jobvr else 1, dtype='D', order='F') n = a.shape[0] work = nlcpy.empty( 65 * n if a_complex else 66 * n, dtype=dtype, order='F') rwork = nlcpy.empty(2 * n if a_complex else 1, dtype=f_dtype, order='F') info = numpy.empty(1, dtype='l') fpe = request._get_fpe_flag() args = ( a._ve_array, wr._ve_array, wi._ve_array, vr._ve_array, vc._ve_array, work._ve_array, rwork._ve_array, ord('V') if jobvr else ord('N'), veo.OnStack(info, inout=veo.INTENT_OUT), veo.OnStack(fpe, inout=veo.INTENT_OUT), ) request._push_and_flush_request( 'nlcpy_eig', args, ) if a_complex: w_complex = True w = wr vc = vr else: w_complex = nlcpy.any(wi) w = wr + wi * 1.0j if w_complex: if c_order: w = nlcpy.asarray(nlcpy.moveaxis(w, 0, -1), dtype=c_dtype, order='C') else: w = nlcpy.moveaxis(nlcpy.asarray(w, dtype=c_dtype), 0, -1) else: wr = w.real w = nlcpy.moveaxis(nlcpy.asarray(wr, dtype=f_dtype), 0, -1) if jobvr: if w_complex: if c_order: vr = nlcpy.asarray( nlcpy.moveaxis(vc, (1, 0), (-1, -2)), dtype=c_dtype, order='C') else: vr = nlcpy.moveaxis( nlcpy.asarray(vc, dtype=c_dtype), (1, 0), (-1, -2)) else: if c_dtype == "F": vr = nlcpy.asarray(vc.real, dtype=f_dtype, order='C') else: vc = nlcpy.moveaxis( nlcpy.asarray(vc, dtype=c_dtype), (1, 0), (-1, -2)) vr = vc.real if jobvr: return w, vr else: return w
def norm(x, ord=None, axis=None, keepdims=False): """Returns matrix or vector norm. This function is able to return one of eight different matrix norms, or one of an infinite number of vector norms (described below), depending on the value of the ``ord`` parameter. Parameters ---------- x : array_like Input array. If *axis* is None, *x* must be 1-D or 2-D. ord : {non-zero int, inf, -inf, 'fro', 'nuc'}, optional Order of the norm (see table under ``Note``). inf means nlcpy's *inf* object. axis : {None, int, 2-tuple of ints}, optional If *axis* is an integer, it specifies the axis of *x* along which to compute the vector norms. If *axis* is a 2-tuple, it specifies the axes that hold 2-D matrices, and the matrix norms of these matrices are computed. If *axis* is None then either a vector norm (when *x* is 1-D) or a matrix norm (when *x* is 2-D) is returned. keepdims : bool, optional If this is set to True, the axes which are normed over are left in the result as dimensions with size one. With this option the result will broadcast correctly against the original x. Returns ------- n : ndarray Norm of the matrix or vector(s). Note ---- For values of ``ord < 1``, the result is, strictly speaking, not a mathematical 'norm', but it may still be useful for various numerical purposes. The following norms can be calculated: .. csv-table:: :header: ord, norm for matrices, norm for vectors None, Frobenius norm, 2-norm 'fro', Frobenius norm, \- 'nuc', nuclear norm, \- inf, "max(sum(abs(x), axis=1))", max(abs(x)) -inf, "min(sum(abs(x), axis=1))", min(abs(x)) 0, \-, sum(x != 0) 1, "max(sum(abs(x), axis=0))", as below -1, "min(sum(abs(x), axis=0))", as below 2, 2-norm (largest sing. value), as below -2, smallest singular value, as below other, \-, sum(abs(x)**ord)**(1./ord) The Frobenius norm is given by :math:`|A|_F = [\\sum_{i,j}abs(a_{i,j})^2]^{1/2}` The nuclear norm is the sum of the singular values. Examples -------- >>> import nlcpy as vp >>> a = vp.arange(9) - 4 >>> a array([-4, -3, -2, -1, 0, 1, 2, 3, 4]) >>> b = a.reshape((3, 3)) >>> b array([[-4, -3, -2], [-1, 0, 1], [ 2, 3, 4]]) >>> vp.linalg.norm(a) # doctest: +SKIP array(7.74596669) >>> vp.linalg.norm(b) # doctest: +SKIP array(7.74596669) >>> vp.linalg.norm(b, 'fro') # doctest: +SKIP array(7.74596669) >>> vp.linalg.norm(a, vp.inf) # doctest: +SKIP array(4.) >>> vp.linalg.norm(b, vp.inf) # doctest: +SKIP array(9.) >>> vp.linalg.norm(a, -vp.inf) # doctest: +SKIP array(0.) >>> vp.linalg.norm(b, -vp.inf) # doctest: +SKIP array(2.) >>> vp.linalg.norm(a, 1) # doctest: +SKIP array(20.) >>> vp.linalg.norm(b, 1) # doctest: +SKIP array(7.) >>> vp.linalg.norm(a, -1) # doctest: +SKIP array(0.) >>> vp.linalg.norm(b, -1) # doctest: +SKIP array(6.) >>> vp.linalg.norm(a, 2) # doctest: +SKIP array(7.74596669) >>> vp.linalg.norm(b, 2) # doctest: +SKIP array(7.34846923) >>> vp.linalg.norm(a, -2) # doctest: +SKIP array(0.) >>> vp.linalg.norm(b, -2) # doctest: +SKIP array(3.75757704e-16) >>> vp.linalg.norm(a, 3) # doctest: +SKIP array(5.84803548) >>> vp.linalg.norm(a, -3) # doctest: +SKIP array(0.) Using the *axis* argument to compute vector norms: >>> c = vp.array([[ 1, 2, 3], ... [-1, 1, 4]]) >>> vp.linalg.norm(c, axis=0) # doctest: +SKIP array([1.41421356, 2.23606798, 5. ]) >>> vp.linalg.norm(c, axis=1) # doctest: +SKIP array([3.74165739, 4.24264069]) >>> vp.linalg.norm(c, ord=1, axis=1) # doctest: +SKIP array([6., 6.]) Using the axis argument to compute matrix norms: >>> m = vp.arange(8).reshape(2,2,2) >>> vp.linalg.norm(m, axis=(1,2)) # doctest: +SKIP array([ 3.74165739, 11.22497216]) >>> vp.linalg.norm(m[0, :, :]), vp.linalg.norm(m[1, :, :]) # doctest: +SKIP (array(3.74165739), array(11.22497216)) """ x = nlcpy.asarray(x) if x.dtype.char in '?ilIL': x = nlcpy.array(x, dtype='d') # used to match the contiguous of result to numpy. order = 'F' if x.flags.f_contiguous and not x.flags.c_contiguous else 'C' # Immediately handle some default, simple, fast, and common cases. if axis is None: ret = None ndim = x.ndim axis = tuple(range(x.ndim)) if ord is None and x.ndim == 2: ret = _lange(x, ord, axis) elif ord is None or ord == 2 and x.ndim == 1: x = x.ravel() if x.dtype.char in 'FD': sqnorm = nlcpy.dot(x.real, x.real) + nlcpy.dot(x.imag, x.imag) else: sqnorm = nlcpy.dot(x, x) ret = nlcpy.sqrt(sqnorm) if ret is not None: if keepdims: ret = ret.reshape(ndim * [1]) return ret elif not isinstance(axis, tuple): try: axis = (int(axis), ) except Exception: raise TypeError( "'axis' must be None, an integer or a tuple of integers") if len(axis) == 1: if ord == nlcpy.inf: return abs(x).max(axis=axis, keepdims=keepdims) elif ord == -nlcpy.inf: return abs(x).min(axis=axis, keepdims=keepdims) elif ord == 0: return nlcpy.sum((x != 0).astype(x.real.dtype), axis=axis, keepdims=keepdims) elif ord == 1: return nlcpy.add.reduce(abs(x), axis=axis, keepdims=keepdims) elif ord is None or ord == 2: s = (nlcpy.conj(x) * x).real ret = nlcpy.sqrt(nlcpy.add.reduce(s, axis=axis, keepdims=keepdims)) return nlcpy.asarray(ret, order=order) else: try: ord + 1 except TypeError: raise ValueError("Invalid norm order for vectors.") ret = abs(x)**ord ret = nlcpy.add.reduce(ret, axis=axis, keepdims=keepdims) ret **= (1 / ord) if (keepdims or x.ndim > 1) and x.dtype.char in 'fF': ret = nlcpy.asarray(ret, dtype='f') else: ret = nlcpy.asarray(ret, dtype='d') return ret elif len(axis) == 2: row_axis, col_axis = axis if row_axis < 0: row_axis += x.ndim if col_axis < 0: col_axis += x.ndim if row_axis == col_axis: raise ValueError('Duplicate axes given.') if ord == 2: y = nlcpy.moveaxis(x, (row_axis, col_axis), (-2, -1)) ret = nlcpy.linalg.svd(y, compute_uv=0).max(axis=-1) elif ord == -2: y = nlcpy.moveaxis(x, (row_axis, col_axis), (-2, -1)) ret = nlcpy.linalg.svd(y, compute_uv=0).min(axis=-1) elif ord == 1: if x.shape[col_axis] == 0: raise ValueError( 'zero-size array to ' 'reduction operation maximum which has no identity') ret = _lange(x, ord, axis) elif ord == nlcpy.inf: if x.shape[row_axis] == 0: raise ValueError( 'zero-size array to ' 'reduction operation maximum which has no identity') ret = _lange(x, ord, axis) elif ord in (None, 'fro', 'f'): ret = _lange(x, ord, axis) elif ord == -1: if col_axis > row_axis: col_axis -= 1 ret = nlcpy.add.reduce(abs(x), axis=row_axis).min(axis=col_axis) elif ord == -nlcpy.inf: if row_axis > col_axis: row_axis -= 1 ret = nlcpy.add.reduce(abs(x), axis=col_axis).min(axis=row_axis) elif ord == 'nuc': y = nlcpy.moveaxis(x, (row_axis, col_axis), (-2, -1)) ret = nlcpy.sum(nlcpy.linalg.svd(y, compute_uv=0), axis=-1) else: raise ValueError("Invalid norm order for matrices.") if keepdims: ret_shape = list(x.shape) ret_shape[axis[0]] = 1 ret_shape[axis[1]] = 1 ret = ret.reshape(ret_shape) ret = nlcpy.asarray(ret, order=order) return ret else: raise ValueError("Improper number of dimensions to norm.")
def solve(a, b): """Solves a linear matrix equation, or system of linear scalar equations. Computes the "exact" solution, *x*, of the well-determined, i.e., full rank, linear matrix equation :math:`ax = b`. Parameters ---------- a : (..., M, M) array_like Coefficient matrix. b : {(..., M,), (..., M, K)} array_like Ordinate or "dependent variable" values. Returns ------- x : {(..., M,), (..., M, K)} ndarray Solution to the system a x = b. Returned shape is identical to *b*. Note ---- The solutions are computed using LAPACK routine ``_gesv``. `a` must be square and of full-rank, i.e., all rows (or, equivalently, columns) must be linearly independent; if either is not true, use :func:`lstsq` for the least-squares best "solution" of the system/equation. Examples -------- Solve the system of equations ``3 * x0 + x1 = 9`` and ``x0 + 2 * x1 = 8``: >>> import nlcpy as vp >>> a = vp.array([[3,1], [1,2]]) >>> b = vp.array([9,8]) >>> x = vp.linalg.solve(a, b) >>> x array([2., 3.]) """ a = nlcpy.asarray(a) b = nlcpy.asarray(b) c_order = (a.flags.c_contiguous or a.ndim < 4 or a.ndim - b.ndim < 2 and b.flags.c_contiguous) and \ not (a.ndim < b.ndim and not b.flags.c_contiguous) util._assertRankAtLeast2(a) util._assertNdSquareness(a) if a.ndim - 1 == b.ndim: if a.shape[-1] != b.shape[-1]: raise ValueError( 'solve1: Input operand 1 has a mismatch in ' 'its core dimension 0, with gufunc signature (m,m),(m)->(m) ' '(size {0} is different from {1})'.format( b.shape[-1], a.shape[-1])) elif b.ndim == 1: raise ValueError( 'solve: Input operand 1 does not have enough dimensions ' '(has 1, gufunc core with signature (m,m),(m,n)->(m,n) requires 2)' ) else: if a.shape[-1] != b.shape[-2]: raise ValueError( 'solve: Input operand 1 has a mismatch in ' 'its core dimension 0, with gufunc signature (m,m),(m,n)->(m,n) ' '(size {0} is different from {1})'.format( b.shape[-2], a.shape[-1])) if b.ndim == 1 or a.ndim - 1 == b.ndim and a.shape[-1] == b.shape[-1]: tmp = 1 _newaxis = (None, ) else: tmp = 2 _newaxis = (None, None) for i in range(1, min(a.ndim - 2, b.ndim - tmp) + 1): if a.shape[-2 - i] != b.shape[-tmp - i] and \ 1 not in (a.shape[-2 - i], b.shape[-tmp - i]): raise ValueError( 'operands could not be broadcast together with ' 'remapped shapes [original->remapped]: {0}->({1}) ' '{2}->({3}) and requested shape ({4})'.format( str(a.shape).replace(' ', ''), str(a.shape[:-2] + _newaxis).replace(' ', '').replace( 'None', 'newaxis').strip('(,)'), str(b.shape).replace(' ', ''), str(b.shape[:-tmp] + _newaxis).replace(' ', '').replace( 'None', 'newaxis').replace('None', 'newaxis').strip('(,)'), str(b.shape[-tmp:]).replace(' ', '').strip('(,)'))) if a.dtype.char in 'FD' or b.dtype.char in 'FD': dtype = 'complex128' if a.dtype.char in 'fF' and b.dtype.char in 'fF': x_dtype = 'complex64' else: x_dtype = 'complex128' else: dtype = 'float64' if a.dtype.char == 'f' and b.dtype.char == 'f': x_dtype = 'float32' else: x_dtype = 'float64' x_shape = b.shape if b.ndim == a.ndim - 1: b = b[..., nlcpy.newaxis] diff = abs(a.ndim - b.ndim) if a.ndim < b.ndim: bcast_shape = [ b.shape[i] if b.shape[i] != 1 or i < diff else a.shape[i - diff] for i in range(b.ndim - 2) ] else: bcast_shape = [ a.shape[i] if a.shape[i] != 1 or i < diff else b.shape[i - diff] for i in range(a.ndim - 2) ] bcast_shape_a = bcast_shape + list(a.shape[-2:]) bcast_shape_b = bcast_shape + list(b.shape[-2:]) a = nlcpy.broadcast_to(a, bcast_shape_a) if bcast_shape_b != list(b.shape): b = nlcpy.broadcast_to(b, bcast_shape_b) x_shape = b.shape if b.size == 0: return nlcpy.empty(x_shape, dtype=x_dtype) a = nlcpy.array(nlcpy.moveaxis(a, (-1, -2), (1, 0)), dtype=dtype, order='F') b = nlcpy.array(nlcpy.moveaxis(b, (-1, -2), (1, 0)), dtype=dtype, order='F') info = numpy.empty(1, dtype='l') fpe = request._get_fpe_flag() args = ( a._ve_array, b._ve_array, veo.OnStack(info, inout=veo.INTENT_OUT), veo.OnStack(fpe, inout=veo.INTENT_OUT), ) request._push_and_flush_request('nlcpy_solve', args, callback=util._assertNotSingular(info)) if c_order: x = nlcpy.moveaxis(b, (1, 0), (-1, -2)).reshape(x_shape) return nlcpy.asarray(x, x_dtype, 'C') else: x = nlcpy.asarray(b, x_dtype) return nlcpy.moveaxis(x, (1, 0), (-1, -2)).reshape(x_shape)
def _check_ufunc_result(op, worst_dtype, v, n, in1=None, in2=None, out=None, where=None, dtype=None, ufunc_name='', n_calc=1): # nan/inf care if numpy.isscalar(n): if numpy.isinf(n) and nlcpy.isinf(v) or numpy.isnan(n) and nlcpy.isnan(v): return else: v, n = _nan_inf_care(v, n) v_array = nlcpy.asarray(v) n_array = numpy.asarray(n) atol, rtol = _guess_tolerance(op, worst_dtype, ufunc_name) if ufunc_name in ('reduce', 'accumulate', 'reduceat'): atol *= n_calc rtol *= n_calc if numpy.asarray(n).dtype.char in '?ilIL' and \ (numpy.asarray(in1).dtype.char not in '?ilIL' or numpy.dtype(dtype).char not in '?ilIL' or op in ('logaddexp', 'logaddexp2', 'arctan2', 'hypot')): atol = 1 # prepare error message msg = "\n" msg += "***** parameters when pytest raised an error *****" msg += "\nout={}, where={}, dtype={}".format( True if out is not None else False, True if where is not None else False, dtype) msg += "\nop: {}".format(op) if in1 is not None: if isinstance(in1, numpy.ndarray): msg += "\nin1: dtype={}\n{}".format(in1.dtype, in1) else: msg += "\nin1: dtype={}\n{}".format(type(in1), in1) if in2 is not None: if isinstance(in2, numpy.ndarray): msg += "\nin2: dtype={}\n{}".format(in2.dtype, in2) else: msg += "\nin2: dtype={}\n{}".format(type(in2), in2) if out is not None: msg += "\nout: dtype={}\n{}".format(out.dtype, out) if where is not None: msg += "\nwhere: dtype={}\n{}".format(where.dtype, where) msg += "\n\nnlcpy_result: dtype={}\n{}".format(v_array.dtype, v_array) msg += "\nnumpy_result: dtype={}\n{}".format(n_array.dtype, n_array) msg += "\n" # compare results try: if v_array.dtype == DT_BOOL and n_array.dtype == DT_BOOL: array.assert_array_equal(v_array, n_array, verbose=True, err_msg=msg) elif atol == 0 and rtol == 0: array.assert_array_equal(v_array, n_array, verbose=True, err_msg=msg) else: array.assert_allclose( v_array, n_array, rtol, atol, verbose=True, err_msg=msg) except Exception: raise # if contiguous_check and isinstance(n, numpy.ndarray): if isinstance(n, numpy.ndarray): if n.flags.c_contiguous and not v.flags.c_contiguous: raise AssertionError( 'The state of c_contiguous flag is false. \n\n' 'nlcpy_flags:\n{} \n\nnumpy_flags:\n{})'.format( v.flags, n.flags)) if n.flags.f_contiguous and not v.flags.f_contiguous: raise AssertionError( 'The state of f_contiguous flag is false. \n\n' 'nlcpy_flags:\n{} \n\nnumpy_flags:\n{})'.format( v.flags, n.flags))
import pytest # NOQA import numpy import numpy as np # NOQA import nlcpy from nlcpy import testing @testing.parameterize(*testing.product({ 'a': [[1, 2, 3, 4, 5], (1, 2, 3), range(10), bytearray(b'abc'), memoryview(b'abc'), numpy.asarray([1, 2]), nlcpy.asarray([1, 2]), [True, False], [1, 2, 3], [2.3, 4.5], [3. + 0.1j, 4. + 0.2j], [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]], [(1, 2, 3), (1, 2, 3)], [range(10), range(10)], [bytearray(b'abc'), bytearray(b'abc')], [memoryview(b'abc'), memoryview(b'abc')], [numpy.asarray([1, 2]), numpy.asarray([1, 2])], [nlcpy.asarray([1, 2]), nlcpy.asarray([1, 2])], (True, False), (1, 2, 3), (2.3, 4.5), (3. + 0.1j, 4. + 0.2j), ([1, 2, 3, 4, 5], [1, 2, 3, 4, 5]), ((1, 2, 3), (1, 2, 3)), (range(10), range(10)), (bytearray(b'abc'), bytearray(b'abc')), (memoryview(b'abc'), memoryview(b'abc')), (numpy.asarray([1, 2]), numpy.asarray([1, 2])), (nlcpy.asarray([1, 2]), nlcpy.asarray([1, 2]))], })) @testing.with_requires('numpy>=1.10.0') class TestFftInput(unittest.TestCase):
def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0): """Returns evenly spaced numbers over a specified interval. Returns *num* evenly spaced samples, calculated over the interval ``[start, stop]``. The endpoint of the interval can optionally be excluded. Parameters ---------- start : array_like The starting value of the sequence. stop : array_like The end value of the sequence, unless *endpoint* is set to False. In that case, the sequence consists of all but the last of ``num + 1`` evenly spaced samples, so that *stop* is excluded. Note that the step size changes when *endpoint* is False. num : int, optional Number of samples to generate. Default is 50. Must be non-negative. endpoint : bool, optional If True, *stop* is the last sample. Otherwise, it is not included. Default is True. retstep : bool, optional If True, return (*samples*, *step*) where *step* is the spacing between samples. dtype : dtype, optional The type of the output array. If *dtype* is not given, infer the data type from the other input arguments. axis : int, optional The axis in the result to store the samples. Relevant only if start or stop are array-like. By default (0), the samples will be along a new axis inserted at the beginning. Use -1 to get an axis at the end. Returns ------- samples : ndarray There are *num* equally spaced samples in the closed interval ``[start, stop]`` or the half-open interval ``[start, stop)`` (depending on whether *endpoint* is True or False). step : float, optional Only returned if *retstep* is True Size of spacing between samples. See Also -------- arange : Returns evenly spaced values within a given interval. Examples -------- >>> import nlcpy as vp >>> vp.linspace(2.0, 3.0, num=5) array([2. , 2.25, 2.5 , 2.75, 3. ]) >>> vp.linspace(2.0, 3.0, num=5, endpoint=False) array([2. , 2.2, 2.4, 2.6, 2.8]) >>> vp.linspace(2.0, 3.0, num=5, retstep=True) (array([2. , 2.25, 2.5 , 2.75, 3. ]), array([0.25])) """ num = operator.index(num) if num < 0: raise ValueError("Number of samples, %s, must be non-negative." % num) dtype_kind = numpy.dtype(dtype).kind if dtype_kind == 'V': raise NotImplementedError( 'void dtype in linspace is not implemented yet.') start = nlcpy.asarray(start) stop = nlcpy.asarray(stop) dt = numpy.result_type(start, stop, float(num)) if start.dtype.char in '?iIlL' or stop.dtype.char in '?iIlL': dt = 'D' if dt.char in 'FD' else 'd' if dtype is None: dtype = dt start = nlcpy.asarray(start, dtype=dt) stop = nlcpy.asarray(stop, dtype=dt) delta = stop - start div = (num - 1) if endpoint else num if num == 0: ret = nlcpy.empty((num, ) + delta.shape, dtype=dtype) if retstep: ret = (ret, nlcpy.NaN) return ret elif div == 0 or num == 1: ret = nlcpy.resize(start, (1, ) + delta.shape).astype(dtype) if retstep: ret = (ret, stop) return ret else: ret = nlcpy.empty((num, ) + delta.shape, dtype=dtype) retdata = ret delta = delta[nlcpy.newaxis] start = nlcpy.array(nlcpy.broadcast_to(start, delta.shape)) stop = nlcpy.array(nlcpy.broadcast_to(stop, delta.shape)) step = delta / div if div > 1 else delta if retdata._memloc in {on_VE, on_VE_VH}: denormal = nlcpy.zeros(1, dtype='l') request._push_request( "nlcpy_linspace", "creation_op", (ret, start, stop, delta, step, int(endpoint), denormal)) if axis != 0: ret = nlcpy.moveaxis(ret, 0, axis) if retstep: ret = (ret, step) if retdata._memloc in {on_VH, on_VE_VH}: del retdata.vh_data del step.vh_data typ = numpy.dtype(dtype).type if retstep: (retdata.vh_data, step.vh_data) = numpy.linspace(typ(start), typ(stop), num, endpoint, typ(retstep), dtype, axis) else: retdata.vh_data = numpy.linspace(typ(start), typ(stop), num, endpoint, typ(retstep), dtype, axis) return ret
def svd(a, full_matrices=True, compute_uv=True, hermitian=False): """Singular Value Decomposition. When *a* is a 2D array, it is factorized as ``u @ nlcpy.diag(s) @ vh = (u * s) @ vh``, where *u* and *vh* are 2D unitary arrays and *s* is a 1D array of *a*'s singular values. When *a* is higher-dimensional, SVD is applied in stacked mode as explained below. Parameters ---------- a : (..., M, N) array_like A real or complex array with a.ndim >= 2. full_matrices : bool, optional If True (default), *u* and *vh* have the shapes ``(..., M, M)`` and ``(..., N, N)``, respectively. Otherwise, the shapes are ``(..., M, K)`` and ``(..., K, N)``, respectively, where ``K = min(M, N)``. compute_uv : bool, optional Whether or not to compute *u* and *vh* in addition to *s*. True by default. hermitian : bool, optional If True, *a* is assumed to be Hermitian (symmetric if real-valued), enabling a more efficient method for finding singular values. Defaults to False. Returns ------- u : {(..., M, M), (..., M, K)} ndarray Unitary array(s). The first ``a.ndim - 2`` dimensions have the same size as those of the input *a*. The size of the last two dimensions depends on the value of *full_matrices*. Only returned when *compute_uv* is True. s : (..., K) ndarray Vector(s) with the singular values, within each vector sorted in descending order. The first ``a.ndim - 2`` dimensions have the same size as those of the input *a*. vh : {(..., N, N), (..., K, N)} ndarray Unitary array(s). The first ``a.ndim - 2`` dimensions have the same size as those of the input *a*. The size of the last two dimensions depends on the value of *full_matrices*. Only returned when *compute_uv* is True. Note ---- The decomposition is performed using LAPACK routine ``_gesdd``. SVD is usually described for the factorization of a 2D matrix :math:`A`. The higher-dimensional case will be discussed below. In the 2D case, SVD is written as :math:`A=USV^{H}`, where :math:`A = a`, :math:`U = u`, :math:`S = nlcpy.diag(s)` and :math:`V^{H} = vh`. The 1D array `s` contains the singular values of `a` and `u` and `vh` are unitary. The rows of `vh` are the eigenvectors of :math:`A^{H}A` and the columns of `u` are the eigenvectors of :math:`AA^{H}`. In both cases the corresponding (possibly non-zero) eigenvalues are given by ``s**2``. If `a` has more than two dimensions, then broadcasting rules apply, as explained in :ref:`Linear algebra on several matrices at once <linalg_several_matrices_at_once>`. This means that SVD is working in "stacked" mode: it iterates over all indices of the first ``a.ndim - 2`` dimensions and for each combination SVD is applied to the last two indices. Examples -------- >>> import nlcpy as vp >>> from nlcpy import testing >>> a = vp.random.randn(9, 6) + 1j*vp.random.randn(9, 6) Reconstruction based on full SVD, 2D case: >>> u, s, vh = vp.linalg.svd(a, full_matrices=True) >>> u.shape, s.shape, vh.shape ((9, 9), (6,), (6, 6)) >>> vp.testing.assert_allclose(a, vp.dot(u[:, :6] * s, vh)) >>> smat = vp.zeros((9, 6), dtype=complex) >>> smat[:6, :6] = vp.diag(s) >>> vp.testing.assert_allclose(a, vp.dot(u, vp.dot(smat, vh))) Reconstruction based on reduced SVD, 2D case: >>> u, s, vh = vp.linalg.svd(a, full_matrices=False) >>> u.shape, s.shape, vh.shape ((9, 6), (6,), (6, 6)) >>> vp.testing.assert_allclose(a, vp.dot(u * s, vh)) >>> smat = vp.diag(s) >>> vp.testing.assert_allclose(a, vp.dot(u, vp.dot(smat, vh))) """ a = nlcpy.asarray(a) util._assertRankAtLeast2(a) if hermitian: util._assertNdSquareness(a) # used to match the contiguous of result to numpy. c_order = a.flags.c_contiguous or sum([i > 1 for i in a.shape[:-2]]) < 2 a_complex = a.dtype.char in 'FD' if a.dtype == 'F': dtype = 'F' f_dtype = 'f' elif a.dtype == 'D': dtype = 'D' f_dtype = 'd' elif a.dtype == 'f': dtype = 'f' f_dtype = 'f' else: dtype = 'd' f_dtype = 'd' if hermitian: if compute_uv: # lapack returns eigenvalues in reverse order, so to reconsist. s, u = nlcpy.linalg.eigh(a) signs = nlcpy.sign(s) s = abs(s) sidx = nlcpy.argsort(s)[..., ::-1] signs = _take_along_axis(signs, sidx, signs.ndim - 1) s = _take_along_axis(s, sidx, s.ndim - 1) u = _take_along_axis(u, sidx[..., None, :], u.ndim - 1) # singular values are unsigned, move the sign into v vt = nlcpy.conjugate(u * signs[..., None, :]) vt = nlcpy.moveaxis(vt, -2, -1) return u, s, vt else: s = nlcpy.linalg.eigvalsh(a) s = nlcpy.sort(abs(s))[..., ::-1] return s m = a.shape[-2] n = a.shape[-1] min_mn = min(m, n) max_mn = max(m, n) if a.size == 0: s = nlcpy.empty(a.shape[:-2] + (min_mn, ), f_dtype) if compute_uv: if full_matrices: u_shape = a.shape[:-1] + (m, ) vt_shape = a.shape[:-2] + (n, n) else: u_shape = a.shape[:-1] + (min_mn, ) vt_shape = a.shape[:-2] + (min_mn, n) u = nlcpy.empty(u_shape, dtype=dtype) vt = nlcpy.empty(vt_shape, dtype=dtype) return u, s, vt else: return s a = nlcpy.array(nlcpy.moveaxis(a, (-1, -2), (1, 0)), dtype=dtype, order='F') if compute_uv: if full_matrices: u = nlcpy.empty((m, m) + a.shape[2:], dtype=dtype, order='F') vt = nlcpy.empty((n, n) + a.shape[2:], dtype=dtype, order='F') job = 'A' else: u = nlcpy.empty((m, m) + a.shape[2:], dtype=dtype, order='F') vt = nlcpy.empty((min_mn, n) + a.shape[2:], dtype=dtype, order='F') job = 'S' else: u = nlcpy.empty(1) vt = nlcpy.empty(1) job = 'N' if a_complex: mnthr1 = int(min_mn * 17.0 / 9.0) if max_mn >= mnthr1: if job == 'N': lwork = 130 * min_mn elif job == 'S': lwork = (min_mn + 130) * min_mn else: lwork = max( (min_mn + 130) * min_mn, (min_mn + 1) * min_mn + 32 * max_mn, ) else: lwork = 64 * (min_mn + max_mn) + 2 * min_mn else: mnthr = int(min_mn * 11.0 / 6.0) if m >= n: if m >= mnthr: if job == 'N': lwork = 131 * n elif job == 'S': lwork = max((131 + n) * n, (4 * n + 7) * n) else: lwork = max((n + 131) * n, (n + 1) * n + 32 * m, (4 * n + 6) * n + m) else: if job == 'N': lwork = 64 * m + 67 * n elif job == 'S': lwork = max(64 * m + 67 * n, (3 * n + 7) * n) else: lwork = (3 * n + 7) * n else: if n >= mnthr: if job == 'N': lwork = 131 * m elif job == 'S': lwork = max((m + 131) * m, (4 * m + 7) * m) else: lwork = max((m + 131) * m, (m + 1) * m + 32 * n, (4 * m + 7) * m) else: if job == 'N': lwork = 67 * m + 64 * n else: lwork = max(67 * m + 64 * n, (3 * m + 7) * m) s = nlcpy.empty((min_mn, ) + a.shape[2:], dtype=f_dtype, order='F') work = nlcpy.empty(lwork, dtype=dtype) if a_complex: if job == 'N': lrwork = 5 * min_mn else: lrwork = min_mn * max(5 * min_mn + 7, 2 * max(m, n) + 2 * min_mn + 1) else: lrwork = 1 rwork = nlcpy.empty(lrwork, dtype=f_dtype) iwork = nlcpy.empty(8 * min_mn, dtype=f_dtype) info = numpy.empty(1, dtype='l') fpe = request._get_fpe_flag() args = ( ord(job), a._ve_array, s._ve_array, u._ve_array, vt._ve_array, work._ve_array, rwork._ve_array, iwork._ve_array, veo.OnStack(info, inout=veo.INTENT_OUT), veo.OnStack(fpe, inout=veo.INTENT_OUT), ) request._push_and_flush_request( 'nlcpy_svd', args, ) if c_order: s = nlcpy.asarray(nlcpy.moveaxis(s, 0, -1), order='C') else: s = nlcpy.moveaxis(s, 0, -1) if compute_uv: u = nlcpy.moveaxis(u, (1, 0), (-1, -2)) if not full_matrices: u = u[..., :m, :min_mn] if c_order: u = nlcpy.asarray(u, dtype=dtype, order='C') vt = nlcpy.asarray(nlcpy.moveaxis(vt, (1, 0), (-1, -2)), dtype, order='C') else: vt = nlcpy.moveaxis(nlcpy.asarray(vt, dtype), (1, 0), (-1, -2)) return u, s, vt else: return s
def test_astype_type_f_contiguous_no_copy(self, dtype, order): a = testing.shaped_arange((2, 3, 4), nlcpy, dtype) a = nlcpy.asarray(a, order='F') b = a.astype(dtype, order=order, copy=False) self.assertTrue(b is a)
def _syevd(a, jobz, UPLO): a = nlcpy.asarray(a) util._assertRankAtLeast2(a) util._assertNdSquareness(a) UPLO = UPLO.upper() if UPLO not in 'UL': raise ValueError("UPLO argument must be 'L' or 'U'") # used to match the contiguous of result to numpy. c_order = a.flags.c_contiguous or sum([i > 1 for i in a.shape[:-2]]) < 2 a_complex = a.dtype.char in 'FD' if a.dtype.char == 'F': dtype = 'F' f_dtype = 'f' elif a.dtype.char == 'D': dtype = 'D' f_dtype = 'd' else: if a.dtype.char == 'f': dtype = 'f' f_dtype = 'f' else: dtype = 'd' f_dtype = 'd' if a.size == 0: w = nlcpy.empty(shape=a.shape[:-1], dtype=f_dtype) if jobz: vr = nlcpy.empty(shape=a.shape, dtype=dtype) return w, vr else: return w a = nlcpy.array(nlcpy.moveaxis(a, (-1, -2), (1, 0)), dtype=dtype, order='F') w = nlcpy.empty(a.shape[1:], dtype=f_dtype, order='F') n = a.shape[0] if a.size > 1: if a_complex: lwork = max(2 * n + n * n, n + 48) lrwork = 1 + 5 * n + 2 * n * n if jobz else n else: lwork = max(2 * n + 32, 1 + 6 * n + 2 * n * n) if jobz else 2 * n + 32 lrwork = 1 liwork = 3 + 5 * n if jobz else 1 else: lwork = 1 lrwork = 1 liwork = 1 work = nlcpy.empty(lwork, dtype=dtype) rwork = nlcpy.empty(lrwork, dtype=f_dtype) iwork = nlcpy.empty(liwork, dtype='l') info = numpy.empty(1, dtype='l') fpe = request._get_fpe_flag() args = ( a._ve_array, w._ve_array, work._ve_array, rwork._ve_array, iwork._ve_array, ord('V') if jobz else ord('N'), ord(UPLO), veo.OnStack(info, inout=veo.INTENT_OUT), veo.OnStack(fpe, inout=veo.INTENT_OUT), ) request._push_and_flush_request( 'nlcpy_eigh', args, ) if c_order: w = nlcpy.asarray(nlcpy.moveaxis(w, 0, -1), order='C') else: w = nlcpy.moveaxis(w, 0, -1) if jobz: if c_order: a = nlcpy.asarray(nlcpy.moveaxis(a, (1, 0), (-1, -2)), order='C') else: a = nlcpy.moveaxis(a, (1, 0), (-1, -2)) return w, a else: return w
def inv(a): """Computes the (multiplicative) inverse of a matrix. Given a square matrix *a*, return the matrix *ainv* satisfying :: dot(a, ainv) = dot(ainv, a) = eye(a.shape[0]). Parameters ---------- a : (..., M, M) array_like Matrix to be inverted. Returns ------- ainv : (..., M, M) ndarray (Multiplicative) inverse of the matrix *a*. Note ---- Broadcasting rules apply, see the :ref:`nlcpy.linalg <nlcpy_linalg>` documentation for details. Examples -------- >>> import nlcpy as vp >>> from nlcpy import testing >>> a = vp.array([[1., 2.], [3., 4.]]) >>> ainv = vp.linalg.inv(a) >>> vp.testing.assert_allclose(vp.dot(a, ainv), vp.eye(2), atol=1e-8, rtol=1e-5) >>> vp.testing.assert_allclose(vp.dot(ainv, a), vp.eye(2), atol=1e-8, rtol=1e-5) Inverses of several matrices can be computed at once: >>> a = vp.array([[[1., 2.], [3., 4.]], [[1, 3], [3, 5]]]) >>> vp.linalg.inv(a) # doctest: +SKIP array([[[-2. , 1. ], [ 1.5 , -0.5 ]], <BLANKLINE> [[-1.25, 0.75], [ 0.75, -0.25]]]) """ a = nlcpy.asarray(a) # used to match the contiguous of result to numpy. c_order = a.flags.c_contiguous or sum([i > 1 for i in a.shape[:-2]]) < 2 util._assertRankAtLeast2(a) util._assertNdSquareness(a) if a.dtype.char in 'FD': dtype = 'D' if a.dtype.char in 'fF': ainv_dtype = 'F' else: ainv_dtype = 'D' else: dtype = 'd' if a.dtype.char == 'f': ainv_dtype = 'f' else: ainv_dtype = 'd' if a.size == 0: return nlcpy.asarray(a, dtype=ainv_dtype) a = nlcpy.array(nlcpy.moveaxis(a, (-1, -2), (1, 0)), dtype=dtype, order='F') ipiv = nlcpy.empty(a.shape[-1]) work = nlcpy.empty(a.shape[-1] * 256) info = numpy.empty(1, dtype='l') fpe = request._get_fpe_flag() args = ( a._ve_array, ipiv._ve_array, work._ve_array, veo.OnStack(info, inout=veo.INTENT_OUT), veo.OnStack(fpe, inout=veo.INTENT_OUT), ) request._push_and_flush_request('nlcpy_inv', args, callback=util._assertNotSingular(info)) if c_order: a = nlcpy.moveaxis(a, (1, 0), (-1, -2)) return nlcpy.asarray(a, dtype=ainv_dtype, order='C') else: a = nlcpy.asarray(a, dtype=ainv_dtype) return nlcpy.moveaxis(a, (1, 0), (-1, -2))
def argsort(a, axis=-1, kind=None, order=None): """Returns the indices that would sort an array. Perform an indirect sort along the given axis using the radix sort. It returns an array of indices of the same shape as *a* that index data along the given axis in sorted order. Parameters ---------- a : array_like Array to sort. axis : int or None, optional Axis along which to sort. The default is -1 (the last axis). If None, the flattened array is used. kind : {'None','stable'}, optional Sorting algorithm. The default is 'stable', kind only supported 'stable'. ('None' is treated as 'stable'.) order : str or list of str, optional This argument is not supported. The default is 'None'. Returns ------- index_array : ndarray Array of indices that sort *a* along the specified *axis*. If a is one-dimensional, ``a[index_array]`` yields a sorted *a*. More generally, Restriction ----------- *NotImplementedError*: - If *kind* is not None and ``kind != 'stable'``. - If *order* is not None. - If 'c' is contained in *a.dtype.kind*. See Also -------- sort : Describes sorting algorithms used. ndarray.sort : Method to sort an array in-place. Examples -------- One dimensional array: >>> import nlcpy as vp >>> x = vp.array([3, 1, 2]) >>> vp.argsort(x) array([1, 2, 0]) Two-dimensional array: >>> x = vp.array([[0, 3], [2, 2]]) >>> x array([[0, 3], [2, 2]]) >>> ind = vp.argsort(x, axis=0) # sorts along first axis (down) >>> ind array([[0, 1], [1, 0]]) >>> ind = vp.argsort(x, axis=1) # sorts along last axis (across) >>> ind array([[0, 1], [0, 1]]) """ a = nlcpy.asarray(a) if kind is not None and kind not in 'stable': raise NotImplementedError('kind only supported \'stable\'.') if order is not None: raise NotImplementedError('order is not implemented.') if a.dtype.kind in ('c', ): raise NotImplementedError('Unsupported dtype %s' % a.dtype) ret = a.argsort(axis=axis, kind=kind, order=order) return ret
def delete(arr, obj, axis=None): """Returns a new array with sub-arrays along an axis deleted. For a one dimensional array, this returns those entries not returned by arr[obj]. Parameters ---------- arr : array_like Input array. obj : slice, int or array of ints Indicate indices of sub-arrays to remove along the specified axis. axis : int, optional The axis along which to delete the subarray defined by obj. If axis is None, obj is applied to the flattened array. Returns ------- out : ndarray A copy of arr with the elements specified by obj removed. Note that delete does not occur in-place. If axis is None, out is a flattened array. Note ---- Often it is preferable to use a boolean mask. For example: >>> import nlcpy as vp >>> arr = vp.arange(12) + 1 >>> mask = vp.ones(len(arr), dtype=bool) >>> mask[[0,2,4]] = False >>> result = arr[mask,...] Is equivalent to vp.delete(arr, [0,2,4], axis=0), but allows further use of mask. See Also -------- insert : Inserts values along the given axis before the given indices. append : Appends values to the end of an array. Examples -------- >>> import nlcpy as vp >>> arr = vp.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]]) >>> arr array([[ 1, 2, 3, 4], [ 5, 6, 7, 8], [ 9, 10, 11, 12]]) >>> vp.delete(arr, 1, 0) array([[ 1, 2, 3, 4], [ 9, 10, 11, 12]]) >>> vp.delete(arr, slice(None, None, 2), 1) array([[ 2, 4], [ 6, 8], [10, 12]]) >>> vp.delete(arr, [1,3,5], None) array([ 1, 3, 5, 7, 8, 9, 10, 11, 12]) """ input_arr = nlcpy.asarray(arr) ndim = input_arr.ndim if input_arr._f_contiguous and not input_arr._c_contiguous: order_out = 'F' else: order_out = 'C' if axis is None: if ndim != 1: input_arr = input_arr.ravel() ndim = input_arr.ndim axis = ndim - 1 if isinstance(axis, numpy.ndarray) or isinstance(axis, nlcpy.ndarray): axis = int(axis) elif not isinstance(axis, int): raise TypeError("an integer is required (got type " + str(type(axis).__name__) + ")") if axis < -ndim or axis > ndim - 1: raise AxisError( "axis {} is out of bounds for array of dimension {}".format(axis, ndim)) if axis < 0: axis += ndim N = input_arr.shape[axis] if isinstance(obj, slice): start, stop, step = obj.indices(N) xr = range(start, stop, step) if len(xr) == 0: return input_arr.copy(order=order_out) else: del_obj = nlcpy.arange(start, stop, step) else: del_obj = nlcpy.asarray(obj) if del_obj.ndim != 1: del_obj = del_obj.ravel() if del_obj.dtype == bool: if del_obj.ndim != 1 or del_obj.size != input_arr.shape[axis]: raise ValueError( 'boolean array argument obj to delete must be one dimensional and ' 'match the axis length of {}'.format(input_arr.shape[axis])) del_obj = del_obj.astype(nlcpy.intp) if isinstance(obj, (int, nlcpy.integer)): if (obj < -N or obj >= N): raise IndexError( "index %i is out of bounds for axis %i with " "size %i" % (obj, axis, N)) if (obj < 0): del_obj += N elif del_obj.size > 0 and del_obj.dtype != int: raise IndexError( 'arrays used as indices must be of integer (or boolean) type') if del_obj.size == 0: new = nlcpy.array(input_arr) return new else: new = nlcpy.empty(input_arr.shape, input_arr.dtype, order_out) idx = nlcpy.ones(input_arr.shape[axis], dtype=del_obj.dtype) obj_count = nlcpy.zeros([3], dtype='l') request._push_request( 'nlcpy_delete', 'manipulation_op', (input_arr, del_obj, axis, idx, new, obj_count) ) count = obj_count.get() if count[1] != 0: raise IndexError( "index out of bounds for axis {}".format(axis)) if count[2] != 0: warnings.warn( "in the future negative indices will not be ignored by " "`numpy.delete`.", FutureWarning, stacklevel=3) sl = [slice(N - count[0]) if i == axis else slice(None) for i in range(new.ndim)] return new[sl].copy()
def lstsq(a, b, rcond='warn'): """Returns the least-squares solution to a linear matrix equation. Solves the equation :math:`ax = b` by computing a vector *x* that minimizes the squared Euclidean 2-norm :math:`|b-ax|^2_2`. The equation may be under-, well-, or over-determined (i.e., the number of linearly independent rows of *a* can be less than, equal to, or greater than its number of linearly independent columns). If *a* is square and of full rank, then *x* (but for round-off error) is the "exact" solution of the equation. Parameters ---------- a : (M,N) array_like "Coefficient" matrix. b : {(M,), (M, K)} array_like Ordinate or "dependent variable" values. If *b* is two-dimensional, the least-squares solution is calculated for each of the *K* columns of *b*. rcond : float, optional Cut-off ratio for small singular values of *a*. For the purposes of rank determination, singular values are treated as zero if they are smaller than *rcond* times the largest singular value of *a*. Returns ------- x : {(N,), (N, K)} ndarray Least-squares solution. If *b* is two-dimensional, the solutions are in the *K* columns of *x*. residuals : {(1,), (K,), (0,)} ndarray Sums of residuals; squared Euclidean 2-norm for each column in ``b - a@x``. If the rank of *a* is < N or M <= N, this is an empty array. If *b* is 1-dimensional, this is a (1,) shape array. Otherwise the shape is (K,). rank : *int* Rank of matrix *a*. s : (min(M, N),) ndarray Singular values of *a*. Note ---- If `b` is a matrix, then all array results are returned as matrices. Examples -------- .. plot:: :align: center Fit a line, ``y = mx + c``, through some noisy data-points: >>> import nlcpy as vp >>> x = vp.array([0, 1, 2, 3]) >>> y = vp.array([-1, 0.2, 0.9, 2.1]) By examining the coefficients, we see that the line should have a gradient of roughly 1 and cut the y-axis at, more or less, -1. We can rewrite the line equation as ``y = Ap``, where ``A = [[x 1]]`` and ``p = [[m], [c]]``. Now use lstsq to solve for *p*: >>> A = vp.array((x, vp.ones(len(x)))).T >>> A array([[0., 1.], [1., 1.], [2., 1.], [3., 1.]]) >>> m, c = vp.linalg.lstsq(A, y, rcond=None)[0] >>> m, c # doctest: +SKIP (array(1.), array(-0.95)) # may vary Plot the data along with the fitted line: >>> import matplotlib.pyplot as plt >>> _ = plt.plot(x, y, 'o', label='Original data', markersize=15) >>> _ = plt.plot(x, m*x + c, 'r', label='Fitted line') >>> _ = plt.legend() >>> plt.show() """ a = nlcpy.asarray(a) b = nlcpy.asarray(b) b_ndim = b.ndim if b_ndim == 1: b = b[:, nlcpy.newaxis] util._assertRank2(a, b) if a.shape[-2] != b.shape[-2]: raise util.LinAlgError('Incompatible dimensions') a_complex = a.dtype.char in 'FD' b_complex = b.dtype.char in 'FD' if a_complex or b_complex: if a.dtype.char in 'fF' and b.dtype.char in 'fF': x_dtype = 'F' f_dtype = 'f' else: x_dtype = 'D' f_dtype = 'd' else: if a.dtype.char == 'f' and b.dtype.char == 'f': x_dtype = 'f' f_dtype = 'f' else: x_dtype = 'd' f_dtype = 'd' m = a.shape[-2] n = a.shape[-1] k = b.shape[-1] minmn = min(m, n) maxmn = max(m, n) k_extend = (k == 0) if k_extend: b = nlcpy.zeros([m, 1], dtype=b.dtype) k = 1 if minmn == 0: if n > 0: x = nlcpy.zeros([n, k], dtype=x_dtype) residuals = nlcpy.array([], dtype=f_dtype) else: x = nlcpy.array([], dtype=x_dtype) if b_complex: br = nlcpy.asarray(b.real, dtype='d') bi = nlcpy.asarray(b.imag, dtype='d') square_b = nlcpy.power(br, 2) + nlcpy.power(bi, 2) else: square_b = nlcpy.power(b, 2, dtype='d') residuals = nlcpy.add.reduce(square_b, dtype=f_dtype) return (x, residuals, 0, nlcpy.array([], dtype=f_dtype)) if rcond == 'warn': rcond = -1.0 if rcond is None: rcond = nlcpy.finfo(x_dtype).eps * max(m, n) rcond = nlcpy.asarray(rcond, dtype=f_dtype) a = nlcpy.array(a, dtype=x_dtype, order='F') if m < n: _b = nlcpy.empty([n, k], dtype=x_dtype, order='F') _b[:m, :] = b b = _b else: b = nlcpy.array(b, dtype=x_dtype, order='F') s = nlcpy.empty(min(m, n), dtype=f_dtype) rank = numpy.empty(1, dtype='l') nlvl = max(0, int(nlcpy.log(minmn / 26.0) / nlcpy.log(2)) + 1) mnthr = int(minmn * 1.6) mm = m lwork = 1 if a_complex: _tmp = 2 wlalsd = minmn * k lrwork = 10 * maxmn + 2 * maxmn * 25 + 8 * maxmn * nlvl + 3 * 25 * k \ + max(26 ** 2, n * (1 + k) + 2 * k) else: _tmp = 3 wlalsd = 9 * minmn + 2 * minmn * 25 + 8 * minmn * nlvl + minmn * k + 26**2 lrwork = 1 if m >= n: if m >= mnthr: mm = n lwork = max(65 * n, n + 32 * k) lwork = max(lwork, _tmp * n + (mm + n) * 64, _tmp * n + 32 * k, _tmp * n + 32 * n - 32, _tmp * n + wlalsd) else: if n >= mnthr: lwork = max(lwork, m * m + 4 * m + wlalsd, m * m + 132 * m, m * m + 4 * m + 32 * k, m * m + (k + 1) * m, m * m + n + m) else: lwork = max(lwork, 3 * m + wlalsd, 3 * m + 64 * (n + m), 3 * m + 32 * k) liwork = minmn * (11 + 3 * nlvl) work = nlcpy.empty(lwork) iwork = nlcpy.empty(liwork, dtype='l') rwork = nlcpy.empty(lrwork, dtype=f_dtype) info = numpy.empty(1, dtype='l') fpe = request._get_fpe_flag() args = ( a._ve_array, b._ve_array, s._ve_array, work._ve_array, iwork._ve_array, rwork._ve_array, rcond._ve_array, veo.OnStack(rank, inout=veo.INTENT_OUT), veo.OnStack(info, inout=veo.INTENT_OUT), veo.OnStack(fpe, inout=veo.INTENT_OUT), ) request._push_and_flush_request('nlcpy_lstsq', args, callback=_lstsq_errchk(info), sync=True) if rank < n or m <= n: residuals = nlcpy.array([], dtype=f_dtype) else: _b = b[n:] square_b = nlcpy.power(_b.real, 2) + nlcpy.power(_b.imag, 2) residuals = nlcpy.add.reduce(square_b, dtype=f_dtype) if k_extend: x = b[..., :0] residuals = residuals[..., :0] elif b_ndim == 1: x = nlcpy.asarray(b[:n, 0], dtype=x_dtype, order='C') else: x = nlcpy.asarray(b[:n, :], dtype=x_dtype, order='C') return (x, residuals, rank[0], s)
def cholesky(a): """Cholesky decomposition. Return the Cholesky decomposition, *L* * *L.H*, of the square matrix *a*, where *L* is lower-triangular and *.H* is the conjugate transpose operator (which is the ordinary transpose if *a* is real-valued). *a* must be Hermitian (symmetric if real-valued) and positive-definite. Only *L* is actually returned. Parameters ---------- a : (..., M, M) array_like Hermitian (symmetric if all elements are real), positive-definite input matrix. Returns ------- L : (..., M, M) ndarray Upper or lower-triangular Cholesky factor of *a*. Note ---- The Cholesky decomposition is often used as a fast way of solving :math:`Ax = b` (when *A* is both Hermitian/symmetric and positive-definite). First, we solve for y in :math:`Ly = b`, and then for x in :math:`L.Hx = y`. Examples -------- >>> import nlcpy as vp >>> A = vp.array([[1,-2j],[2j,5]]) >>> A array([[ 1.+0.j, -0.-2.j], [ 0.+2.j, 5.+0.j]]) >>> L = vp.linalg.cholesky(A) >>> L array([[1.+0.j, 0.+0.j], [0.+2.j, 1.+0.j]]) >>> vp.dot(L, vp.conjugate(L.T)) # verify that L * L.H = A array([[1.+0.j, 0.-2.j], [0.+2.j, 5.+0.j]]) """ a = nlcpy.asarray(a) util._assertRankAtLeast2(a) util._assertNdSquareness(a) if a.dtype == 'F': dtype = 'D' L_dtype = 'F' elif a.dtype == 'D': dtype = 'D' L_dtype = 'D' elif a.dtype == 'f': dtype = 'd' L_dtype = 'f' else: dtype = 'd' L_dtype = 'd' if a.size == 0: return nlcpy.empty(a.shape, dtype=L_dtype) # used to match the contiguous of result to numpy. c_order = a.flags.c_contiguous or sum([i > 1 for i in a.shape[:-2]]) < 2 a = nlcpy.array(nlcpy.moveaxis(a, (-1, -2), (1, 0)), dtype=dtype, order='F') info = numpy.empty(1, dtype='l') fpe = request._get_fpe_flag() args = ( a._ve_array, veo.OnStack(info, inout=veo.INTENT_OUT), veo.OnStack(fpe, inout=veo.INTENT_OUT), ) request._push_and_flush_request( 'nlcpy_cholesky', args, callback=util._assertPositiveDefinite(info)) if c_order: L = nlcpy.asarray(nlcpy.moveaxis(a, (1, 0), (-1, -2)), dtype=L_dtype, order='C') else: L = nlcpy.moveaxis(nlcpy.asarray(a, dtype=L_dtype), (1, 0), (-1, -2)) return L