def test_batched_inv(self, dtype): for xp in (numpy, cupy): a = xp.array([[[1, 2], [2, 4]]]).astype(dtype) assert a.ndim >= 3 # CuPy internally uses a batched function. with cupyx.errstate(linalg='raise'): with pytest.raises(numpy.linalg.LinAlgError): xp.linalg.inv(a)
def test_slogdet_singular_errstate(self, xp, dtype): a = xp.zeros((3, 3), dtype) with cupyx.errstate(linalg='raise'): # `cupy.linalg.slogdet` internally catches `dev_info < 0` from # cuSOLVER, which should not affect `dev_info > 0` cases. sign, logdet = xp.linalg.slogdet(a) return xp.array([sign, logdet], dtype)
def test_slogdet_fail(self, xp, dtype): a = xp.zeros((3, 3), dtype) with cupyx.errstate(linalg='raise'): # `cupy.linalg.slogdet` internally catches a raised error from # cuSOLVER, but yield a valid output to mimic NumPy. sign, logdet = xp.linalg.slogdet(a) return xp.array([sign, logdet], dtype)
def test_errstate(self): orig = cupyx.geterr() with cupyx.errstate(divide=self.divide): state = cupyx.geterr() assert state.pop('divide') == self.divide orig.pop('divide') assert state == orig
def test_invh(self): if not cusolver.check_availability('potrsBatched'): pytest.skip('potrsBatched is not available') a = self._create_symmetric_matrix(self.shape, self.dtype) with cupyx.errstate(linalg='ignore'): with self.assertRaises(cupy.cuda.cusolver.CUSOLVERError): cupyx.linalg.solve._batched_invh(a)
def test_invh(self): if not cusolver.check_availability('potrsBatched'): pytest.skip('potrsBatched is not available') a = self._create_symmetric_matrix(self.shape, self.dtype) with cupyx.errstate(linalg='raise'): with self.assertRaises(numpy.linalg.LinAlgError): cupyx.linalg.invh(a)
def test_posv(self): if not cupy.cusolver.check_availability('potrsBatched'): pytest.skip('potrsBatched is not available') a = self._create_posdef_matrix(cupy, self.shape, self.dtype) n = a.shape[-1] identity_matrix = cupy.eye(n, dtype=a.dtype) b = cupy.empty(a.shape, a.dtype) b[...] = identity_matrix with cupyx.errstate(linalg='ignore'): with pytest.raises(cupy.cuda.cusolver.CUSOLVERError): lapack.posv(a, b)
def multivariate_normal(self, mean, cov, size=None, check_valid='ignore', tol=1e-08, method='cholesky', dtype=float): """Returns an array of samples drawn from the multivariate normal distribution. .. warning:: This function calls one or more cuSOLVER routine(s) which may yield invalid results if input conditions are not met. To detect these invalid results, you can set the `linalg` configuration to a value that is not `ignore` in :func:`cupyx.errstate` or :func:`cupyx.seterr`. .. seealso:: :func:`cupy.random.multivariate_normal` for full documentation, :meth:`numpy.random.RandomState.multivariate_normal <numpy.random.mtrand.RandomState.multivariate_normal>` """ util.experimental('cupy.random.RandomState.multivariate_normal') mean = cupy.asarray(mean, dtype=dtype) cov = cupy.asarray(cov, dtype=dtype) if size is None: shape = [] elif isinstance(size, (int, cupy.integer)): shape = [size] else: shape = size if len(mean.shape) != 1: raise ValueError('mean must be 1 dimensional') if (len(cov.shape) != 2) or (cov.shape[0] != cov.shape[1]): raise ValueError('cov must be 2 dimensional and square') if mean.shape[0] != cov.shape[0]: raise ValueError('mean and cov must have same length') final_shape = list(shape[:]) final_shape.append(mean.shape[0]) if method not in {'eigh', 'svd', 'cholesky'}: raise ValueError( "method must be one of {'eigh', 'svd', 'cholesky'}") if check_valid != 'ignore': if check_valid != 'warn' and check_valid != 'raise': raise ValueError( "check_valid must equal 'warn', 'raise', or 'ignore'") if check_valid == 'warn': with cupyx.errstate(linalg='raise'): try: decomp = cupy.linalg.cholesky(cov) except LinAlgError: with cupyx.errstate(linalg='ignore'): if method != 'cholesky': if method == 'eigh': (s, u) = cupy.linalg.eigh(cov) psd = not cupy.any(s < -tol) if method == 'svd': (u, s, vh) = cupy.linalg.svd(cov) psd = cupy.allclose(cupy.dot(vh.T * s, vh), cov, rtol=tol, atol=tol) decomp = u * cupy.sqrt(cupy.abs(s)) if not psd: warnings.warn( "covariance is not positive-" + "semidefinite, output may be " + "invalid.", RuntimeWarning) else: warnings.warn( "covariance is not positive-" + "semidefinite, output *is* " + "invalid.", RuntimeWarning) decomp = cupy.linalg.cholesky(cov) else: with cupyx.errstate(linalg=check_valid): try: if method == 'cholesky': decomp = cupy.linalg.cholesky(cov) elif method == 'eigh': (s, u) = cupy.linalg.eigh(cov) decomp = u * cupy.sqrt(cupy.abs(s)) elif method == 'svd': (u, s, vh) = cupy.linalg.svd(cov) decomp = u * cupy.sqrt(cupy.abs(s)) except LinAlgError: raise LinAlgError("Matrix is not positive definite; if " + "matrix is positive-semidefinite, set" + "'check_valid' to 'warn'") x = self.standard_normal(final_shape, dtype=dtype).reshape(-1, mean.shape[0]) x = cupy.dot(decomp, x.T) x = x.T x += mean x.shape = tuple(final_shape) return x
def test_inv(self, dtype): for xp in (numpy, cupy): a = xp.array([[1, 2], [2, 4]]).astype(dtype) with cupyx.errstate(linalg='raise'): with pytest.raises(numpy.linalg.LinAlgError): xp.linalg.inv(a)
def check_L(self, array): for xp in (numpy, cupy): a = xp.asarray(array) with cupyx.errstate(linalg='raise'): with pytest.raises(numpy.linalg.LinAlgError): xp.linalg.cholesky(a)
def test_batched_inv(self, dtype, xp): a = xp.array([[[1, 2], [2, 4]]]).astype(dtype) assert a.ndim >= 3 # CuPy internally uses a batched function. with cupyx.errstate(linalg='raise'): xp.linalg.inv(a)
def test_inv(self, dtype, xp): a = xp.array([[1, 2], [2, 4]]).astype(dtype) with cupyx.errstate(linalg='raise'): xp.linalg.inv(a)
def test_errstate(self): with cupyx.errstate(divide=self.divide): state = cupyx.geterr() assert state['divide'] == self.divide
def _incremental_mean_and_var(X, last_mean, last_variance, last_sample_count): """Calculate mean update and a Youngs and Cramer variance update. last_mean and last_variance are statistics computed at the last step by the function. Both must be initialized to 0.0. In case no scaling is required last_variance can be None. The mean is always required and returned because necessary for the calculation of the variance. last_n_samples_seen is the number of samples encountered until now. From the paper "Algorithms for computing the sample variance: analysis and recommendations", by Chan, Golub, and LeVeque. Parameters ---------- X : array-like, shape (n_samples, n_features) Data to use for variance update last_mean : array-like, shape: (n_features,) last_variance : array-like, shape: (n_features,) last_sample_count : array-like, shape (n_features,) Returns ------- updated_mean : array, shape (n_features,) updated_variance : array, shape (n_features,) If None, only mean is computed updated_sample_count : array, shape (n_features,) Notes ----- NaNs are ignored during the algorithm. References ---------- T. Chan, G. Golub, R. LeVeque. Algorithms for computing the sample variance: recommendations, The American Statistician, Vol. 37, No. 3, pp. 242-247 Also, see the sparse implementation of this in `utils.sparsefuncs.incr_mean_variance_axis` and `utils.sparsefuncs_fast.incr_mean_variance_axis0` """ # old = stats until now # new = the current increment # updated = the aggregated stats last_sum = last_mean * last_sample_count new_sum = _safe_accumulator_op(np.nansum, X, axis=0) new_sample_count = np.sum(~np.isnan(X), axis=0) updated_sample_count = last_sample_count + new_sample_count updated_mean = (last_sum + new_sum) / updated_sample_count if last_variance is None: updated_variance = None else: new_unnormalized_variance = ( _safe_accumulator_op(np.nanvar, X, axis=0) * new_sample_count) last_unnormalized_variance = last_variance * last_sample_count with cupyx.errstate(divide=None, invalid=None): last_over_new_count = last_sample_count / new_sample_count updated_unnormalized_variance = ( last_unnormalized_variance + new_unnormalized_variance + last_over_new_count / updated_sample_count * (last_sum / last_over_new_count - new_sum)**2) zeros = last_sample_count == 0 updated_unnormalized_variance[zeros] = new_unnormalized_variance[zeros] updated_variance = updated_unnormalized_variance / updated_sample_count return updated_mean, updated_variance, updated_sample_count
def check_L(self, array, xp): a = xp.asarray(array) with cupyx.errstate(linalg='raise'): xp.linalg.cholesky(a)
def test_invh(self): a = self._create_symmetric_matrix(self.size, self.dtype) with cupyx.errstate(linalg='raise'): with self.assertRaises(numpy.linalg.LinAlgError): cupyx.linalg.invh(a)