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 _prep(self): NX = 10 zin = nlcpy.empty(NX, dtype='c16') zout_forward = nlcpy.empty(NX, dtype='c16') zout_backward = nlcpy.empty(NX, dtype='c16') zin.real = nlcpy.arange(NX, dtype='f8') zin.imag = nlcpy.arange(NX, dtype='f8') return NX, zin, zout_forward, zout_backward
def test_broadcast_arrays_subok(self): try: nlcpy.broadcast_arrays(nlcpy.empty([1, 3]), nlcpy.empty([2, 1]), subok=True) except NotImplementedError: return raise Exception
def _prep(self): NX = 10 M = 3 zin = nlcpy.empty((M, NX), dtype='c8') zout_forward = nlcpy.empty((M, NX), dtype='c8') zout_backward = nlcpy.empty((M, NX), dtype='c8') for im in range(M): for ix in range(NX): zin[im, ix] = (ix + im + 1) + 1j * ((ix + 1) * (im + 1)) return zin, zout_forward, zout_backward, NX, M
def _prep(self): lna = 11 n = 4 lnb = 9 m = 2 a = nlcpy.empty((lna, n), dtype='f8', order='F') b = nlcpy.empty((lnb, m), dtype='f8', order='F') ipvt = nlcpy.empty(n, dtype='i8') # coefficient matrix a[:n, :] = [[2, 4, -1, 6], [-1, -5, 4, 2], [1, 2, 3, 1], [3, 5, -1, -3]] # constant vectors b[:n, :] = [[36, 11], [15, 0], [22, 7], [-6, 4]] return lna, n, lnb, m, a, b, ipvt
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_empty_like_reshape_nlcpy_only(self, dtype, order): a = testing.shaped_arange((2, 3, 4), nlcpy, dtype) b = nlcpy.empty_like(a, shape=self.shape) b.fill(0) c = nlcpy.empty(self.shape, order=order, dtype=dtype) c.fill(0) testing.assert_array_equal(b, c)
def _prep(self): N = 100 D_M = 1.0 D_S = 0.5 val = nlcpy.empty(N, dtype='f8') seed = numpy.array(0, dtype='u4') return N, seed, D_M, D_S, val
def test_copyto_illegal_dst2(self, xp): # make opposite ndarray if xp == numpy: dst = nlcpy.empty(2, 3) else: # xp == "nlcpy" dst = numpy.empty(2, 3) src = xp.ones((2, 3)) xp.copyto(dst, src)
def test_empty_like_reshape_contiguity_nlcpy_only(self, dtype, order): a = testing.shaped_arange((2, 3, 4), nlcpy, dtype) b = nlcpy.empty_like(a, order=order, shape=self.shape) b.fill(0) c = nlcpy.empty(self.shape) c.fill(0) if order in ['f', 'F']: self.assertTrue(b.flags.f_contiguous) else: self.assertTrue(b.flags.c_contiguous) testing.assert_array_equal(b, c)
def _prep(self): lna = 11 n = 4 m = 2 ab = nlcpy.empty((lna, n + m), dtype='f8', order='F') ipvt = nlcpy.empty(n, dtype='i8') # coefficient matrix ab[:n, :n] = [ [2, 4, -1, 6], [-1, -5, 4, 2], [1, 2, 3, 1], [3, 5, -1, -3] ] # constant vectors ab[:n, n:n + m] = [ [36, 11], [15, 0], [22, 7], [-6, 4] ] return lna, n, m, ab, ipvt
def tri(N, M=None, k=0, dtype=float): """An array with ones at and below the given diagonal and zeros elsewhere. Parameters ---------- N : int Number of rows in the array. M : int, optional Number of columns in the array. By default, *M* is taken equal to *N*. k : int, optional The sub-diagonal at and below which the array is filled. *k* = 0 is the main diagonal, while *k* < 0 is below it, and *k* > 0 is above. The default is 0. dtype : dtype, optional Data type of the returned array. The default is float. Returns ------- tri : ndarray Array with its lower triangle filled with ones and zero elsewhere; in other words ``T[i,j] == 1`` for ``i <= j + k``, 0 otherwise. Examples -------- >>> import nlcpy as vp >>> vp.tri(3, 5, 2, dtype=int) array([[1, 1, 1, 0, 0], [1, 1, 1, 1, 0], [1, 1, 1, 1, 1]]) >>> vp.tri(3, 5, -1) array([[0., 0., 0., 0., 0.], [1., 0., 0., 0., 0.], [1., 1., 0., 0., 0.]]) """ if N < 0: N = 0 else: N = int(N) if M is None: M = N elif M < 0: M = 0 else: M = int(M) k = int(k) out = nlcpy.empty([N, M], dtype=dtype) if out.size: request._push_request('nlcpy_tri', 'creation_op', (out, k)) return out
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 dot(a, b, out=None): """Computes a dot product of two arrays. - If both *a* and *b* are 1-D arrays, it is inner product of vectors (without complex conjugation). - If both *a* and *b* are 2-D arrays, it is matrix multiplication, but using :func:`nlcpy.matmul` or ``a @ b`` is preferred. - If either *a* or *b* is 0-D (scalar), it is equivalent to multiply and using ``nlcpy.multiply(a,b)`` or ``a * b`` is preferred. - If *a* is an N-D array and *b* is a 1-D array, it is a sum product over the last axis of *a* and *b*. - If *a* is an N-D array and *b* is an M-D array (where ``M>=2``), it is a sum product over the last axis of *a* and the second-to-last axis of *b*: ``dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m])`` Parameters ---------- a : array_like Input arrays or scalars. b : array_like Input arrays or scalars. out : ndarray, optional Output argument. This must have the exact kind that would be returned if it was not used. In particular, *out.dtype* must be the dtype that would be returned for *dot(a,b)*. Returns ------- output : ndarray Returns the dot product of *a* and *b*. If *a* and *b* are both scalars or both 1-D arrays then this function returns the result as a 0-dimention array. Examples -------- >>> import nlcpy as vp >>> vp.dot(3, 4) array(12) Neither argument is complex-conjugated: >>> vp.dot([2j, 3j], [2j, 3j]) array(-13.+0.j) For 2-D arrays it is the matrix product: >>> a = [[1, 0], [0, 1]] >>> b = [[4, 1], [2, 2]] >>> vp.dot(a,b) array([[4, 1], [2, 2]]) >>> a = vp.arange(3*4*5*6).reshape((3, 4, 5, 6)) >>> b = vp.arange(3*4*5*6)[::-1].reshape((5, 4, 6, 3)) >>> vp.dot(a, b)[2, 3, 2, 1, 2, 2] array(499128) >>> sum(a[2, 3, 2, :] * b[1, 2, :, 2]) array(499128) """ a = nlcpy.asanyarray(a) b = nlcpy.asanyarray(b) dtype_out = numpy.result_type(a.dtype, b.dtype) if out is not None: if not isinstance(out, nlcpy.ndarray): raise TypeError("'out' must be an array") if dtype_out != out.dtype: raise ValueError('output array is incorrect dtype') # if either a or b is 0-D array, it is equivalent to nlcpy.multiply if a.ndim == 0 or b.ndim == 0: return nlcpy.asanyarray(ufunc_op.multiply(a, b, out=out), order='C') # if both a and b are 1-D arrays, it is inner product of vectors if a.ndim == 1 and b.ndim == 1: return cblas_wrapper.cblas_dot(a, b, out=out) # if both a and b are 2-D arrays, it is matrix multiplication if a.ndim == 2 and b.ndim == 2: return cblas_wrapper.cblas_gemm(a, b, out=out, dtype=numpy.result_type( a.dtype, b.dtype)) # if either a or b are N-D array, it is sum product over the # last(or second-last) axis. if b.ndim > 1: if a.shape[-1] != b.shape[-2]: raise ValueError('mismatch input shape') shape_out = a.shape[:-1] + b.shape[:-2] + (b.shape[-1], ) else: if a.shape[-1] != b.shape[-1]: raise ValueError('mismatch input shape') shape_out = a.shape[:-1] if out is None: out = nlcpy.empty(shape_out, dtype=dtype_out) if out.dtype in (numpy.int8, numpy.int16, numpy.uint8, numpy.uint16, numpy.float16): raise TypeError('output dtype \'%s\' is not supported' % dtype_out) elif out.shape != shape_out or not out.flags.c_contiguous: raise ValueError( 'output array is not acceptable (must have the right datatype, ' 'number of dimensions, and be a C-Array)') out.fill(0) if a.size > 0 and b.size > 0: request._push_request( "nlcpy_dot", "linalg_op", (a, b, out), ) return out
def _prep(self): NX = 30 rng = nlcpy.random.default_rng(seed=0) kyi = rng.random(size=NX, dtype='f4') kyo = nlcpy.empty(NX, dtype='f4') return NX, kyi, kyo
def unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None): """Finds the unique elements of an array. Returns the sorted unique elements of an array. There are three optional outputs in addition to the unique elements: - the indices of the input array that give the unique values - the indices of the unique array that reconstruct the input array - the number of times each unique value comes up in the input array Parameters ---------- ar : array_like Input array. Unless *axis* is specified, this will be flattened if it is not already 1-D. return_index : bool, optional If True, also return the indices of *ar* (along the specified axis, if provided, or in the flattened array) that result in the unique array. return_inverse : bool, optional If True, also return the indices of the unique array (for the specified axis, if provided) that can be used to reconstruct *ar*. return_counts : bool, optional If True, also return the number of times each unique item appears in *ar*. axis : int or None, optional The axis to operate on. If None, *ar* will be flattened. If an integer, the subarrays indexed by the given axis will be flattened and treated as the elements of a 1-D array with the dimension of the given axis, see the notes for more details. Object arrays or structured arrays that contain objects are not supported if the *axis* kwarg is used. The default is None. Returns ------- unique : ndarray The sorted unique values. unique_indices : ndarray, optional The indices of the first occurrences of the unique values in the original array. Only provided if *return_index* is True. unique_inverse : ndarray, optional The indices to reconstruct the original array from the unique array. Only provided if *return_inverse* is True. unique_count : ndarray, optional The number of times each of the unique values comes up in the original array. Only provided if *return_counts* is True. Restriction ----------- *NotImplementedError*: - If 'c' is contained in *ar.dtype.kind*. Note ---- When an axis is specified the subarrays indexed by the axis are sorted. This is done by making the specified axis the first dimension of the array and then flattening the subarrays in C order. The flattened subarrays are then viewed as a structured type with each element given a label, with the effect that we end up with a 1-D array of structured types that can be treated in the same way as any other 1-D array. The result is that the flattened subarrays are sorted in lexicographic order starting with the first element. Examples -------- >>> import nlcpy as vp >>> vp.unique([1, 1, 2, 2, 3, 3]) array([1, 2, 3]) >>> a =vp.array([[1, 1], [2, 3]]) >>> vp.unique(a) array([1, 2, 3]) Return the unique rows of a 2D array >>> a = vp.array([[1, 0, 0], [1, 0, 0], [2, 3, 4]]) >>> vp.unique(a, axis=0) array([[1, 0, 0], [2, 3, 4]]) Return the indices of the original array that give the unique values: >>> a = vp.array([1, 2, 2, 3, 1]) >>> u, indices = vp.unique(a, return_index=True) >>> u array([1, 2, 3]) >>> indices array([0, 1, 3]) >>> a[indices] array([1, 2, 3]) Reconstruct the input array from the unique values: >>> a = vp.array([1, 2, 6, 4, 2, 3, 2]) >>> u, indices = vp.unique(a, return_inverse=True) >>> u array([1, 2, 3, 4, 6]) >>> indices array([0, 1, 4, 3, 1, 2, 1]) >>> u[indices] array([1, 2, 6, 4, 2, 3, 2]) """ ar = nlcpy.asanyarray(ar) if axis is not None: if axis < 0: axis = axis + ar.ndim if axis < 0 or axis >= ar.ndim: raise AxisError('Axis out of range') if ar.ndim > 1 and axis is not None: if ar.size == 0: if axis is None: shape = () else: shape = list(ar.shape) shape[axis] = int(shape[axis] / 2) return nlcpy.empty(shape, dtype=ar.dtype) ar = nlcpy.moveaxis(ar, axis, 0) orig_shape = ar.shape ar = ar.reshape(orig_shape[0], -1) aux = nlcpy.array(ar) perm = nlcpy.empty(ar.shape[0], dtype='l') request._push_request( 'nlcpy_sort_multi', 'sorting_op', (ar, aux, perm, return_index) ) mask = nlcpy.empty(aux.shape[0], dtype='?') mask[0] = True mask[1:] = nlcpy.any(aux[1:] != aux[:-1], axis=1) ret = aux[mask] ret = ret.reshape(-1, *orig_shape[1:]) ret = nlcpy.moveaxis(ret, 0, axis) else: ar = ar.flatten() if return_index or return_inverse: perm = ar.argsort(kind='stable' if return_index else None) aux = ar[perm] else: ar.sort() aux = ar mask = nlcpy.empty(aux.shape[0], dtype='?') if mask.size: mask[0] = True mask[1:] = aux[1:] != aux[:-1] ret = aux[mask] if not return_index and not return_inverse and not return_counts: return ret ret = (ret,) if return_index: ret += (perm[mask],) if return_inverse: imask = nlcpy.cumsum(mask) - 1 inv_idx = nlcpy.empty(mask.shape, dtype=nlcpy.intp) inv_idx[perm] = imask ret += (inv_idx,) if return_counts: nonzero = nlcpy.nonzero(mask)[0] idx = nlcpy.empty((nonzero.size + 1,), nonzero.dtype) idx[:-1] = nonzero idx[-1] = mask.size ret += (idx[1:] - idx[:-1],) 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 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 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_concatenate_wrong_shape(self): a = nlcpy.empty((2, 3, 4)) b = nlcpy.empty((3, 3, 4)) c = nlcpy.empty((4, 4, 4)) with self.assertRaises(ValueError): nlcpy.concatenate((a, b, c))
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 test_empty_zero_sized_array_strides(self, order): a = numpy.empty((1, 0, 2), dtype='d', order=order) b = nlcpy.empty((1, 0, 2), dtype='d', order=order) self.assertEqual(b.strides, a.strides)
def test_sum_out_wrong_shape(self): a = testing.shaped_arange((2, 3, 4)) b = nlcpy.empty((2, 3)) with self.assertRaises(NotImplementedError): nlcpy.sum(a, axis=1, out=b)
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 _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 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
def test_concatenate_wrong_ndim(self): a = nlcpy.empty((2, 3)) b = nlcpy.empty((2, )) with self.assertRaises(ValueError): nlcpy.concatenate((a, b))
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 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 arange(start, stop=None, step=1, dtype=None): """Returns evenly spaced values within a given interval. Values are generated within the half-open interval ``[start, stop)`` (in other words, the interval including *start* but excluding *stop*). If stop is None, values are ganerated within ``[0, start)``. For integer arguments the function is equivalent to the Python built-in *range* function, but returns an ndarray rather than a list. When using a non-integer step, such as 0.1, the results will often not be consistent. It is better to use :func:`linspace` for these cases. Parameters ---------- start : number Start of interval. The interval includes this value. stop : number, optional End of interval. The interval does not include this value, except in some cases where step is not an integer and floating point round-off affects the length of *out*. step : number, optional Spacing between values. For any output *out*, this is the distance between two adjacent values, ``out[i+1] - out[i]``. The default step size is 1. If *step* is specified as a position argument, *start* must also be given. dtype : dtype, optional The type of the output array. If *dtype* is not given, infer the data type from the other input arguments. Returns ------- arange : ndarray Array of evenly spaced values. For floating point arguments, the length of the result is ``ceil((stop - start)/step)``. Because of floating point overflow, this rule may result in the last element of *out* being greater than *stop*. See Also -------- linspace : Returns evenly spaced numbers over a specified interval. Examples -------- >>> import nlcpy as vp >>> vp.arange(3) array([0, 1, 2]) >>> vp.arange(3.0) array([0., 1., 2.]) >>> vp.arange(3,7) array([3, 4, 5, 6]) >>> vp.arange(3,7,2) array([3, 5]) """ if dtype is None: if any( numpy.dtype(type(val)).kind == 'f' for val in (start, stop, step)): dtype = float else: dtype = int if stop is None: stop = start start = 0 if step is None: step = 1 size = int(numpy.ceil((stop - start) / step)) # size = int(numpy.ceil(numpy.ceil(stop - start) / step)) if size <= 0: return nlcpy.empty((0, ), dtype=dtype) if numpy.dtype(dtype).type == numpy.bool_: if size > 2: raise ValueError('no fill-function for data-type.') if size == 2: return nlcpy.array([start, start - step], dtype=numpy.bool_) else: return nlcpy.array([start], dtype=numpy.bool_) ret = nlcpy.empty((size, ), dtype=dtype) if numpy.dtype(dtype).kind == 'f': typ = numpy.dtype('f8').type elif numpy.dtype(dtype).kind == 'c': typ = numpy.dtype('c16').type elif numpy.dtype(dtype).kind == 'u': typ = numpy.dtype('u8').type elif numpy.dtype(dtype).kind == 'i': typ = numpy.dtype('i8').type elif numpy.dtype(dtype).kind == 'b': typ = numpy.dtype('bool').type else: raise TypeError('detected invalid dtype.') if ret._memloc in {on_VE, on_VE_VH}: request._push_request( "nlcpy_arange", "creation_op", (typ(start), typ(step), ret), ) if ret._memloc in {on_VH, on_VE_VH}: del ret.vh_data ret.vh_data = numpy.arange(typ(start), typ(stop), typ(step), dtype=ret.dtype) return ret