def test_all(self): A = self.structure(self.n) order = np.arange(self.n) groups_1 = group_columns(A, order) np.random.shuffle(order) groups_2 = group_columns(A, order) for method, groups, l, u in product(['2-point', '3-point', 'cs'], [groups_1, groups_2], [-np.inf, self.lb], [np.inf, self.ub]): J = approx_derivative(self.fun, self.x0, method=method, bounds=(l, u), sparsity=(A, groups)) assert_(isinstance(J, csr_matrix)) assert_allclose(J.toarray(), self.J_true, rtol=1e-6) rel_step = np.full_like(self.x0, 1e-8) rel_step[::2] *= -1 J = approx_derivative(self.fun, self.x0, method=method, rel_step=rel_step, sparsity=(A, groups)) assert_allclose(J.toarray(), self.J_true, rtol=1e-5)
def test_group_columns(): structure = [ [1, 1, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0], [0, 1, 1, 1, 0, 0], [0, 0, 1, 1, 1, 0], [0, 0, 0, 1, 1, 1], [0, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0] ] for transform in [np.asarray, csr_matrix, csc_matrix, lil_matrix]: A = transform(structure) order = np.arange(6) groups_true = np.array([0, 1, 2, 0, 1, 2]) groups = group_columns(A, order) assert_equal(groups, groups_true) order = [1, 2, 4, 3, 5, 0] groups_true = np.array([2, 0, 1, 2, 0, 1]) groups = group_columns(A, order) assert_equal(groups, groups_true) # Test repeatability. groups_1 = group_columns(A) groups_2 = group_columns(A) assert_equal(groups_1, groups_2)
def test_check_derivative(self): def jac(x): return csr_matrix(self.jac(x)) accuracy = check_derivative(self.fun, jac, self.x0, bounds=(self.lb, self.ub), sparse_diff=True) assert_(accuracy < 1e-9) A = self.structure(self.n) groups = group_columns(A) accuracy = check_derivative(self.fun, jac, self.x0, bounds=(self.lb, self.ub), sparse_diff=True, sparsity=(A, groups)) assert_(accuracy < 1e-9) accuracy = check_derivative(self.fun, jac, self.x0, bounds=(self.lb, self.ub), sparse_diff=False) # Slightly worse accuracy because all elements are computed. # Floating point issues make true 0 to some smal value, then # it is divided by small step and as a result we have ~1e-9 element, # which is actually should be zero. assert_(accuracy < 1e-8)
def test_check_derivative(self): def jac(x): return csr_matrix(self.jac(x)) accuracy = check_derivative( self.fun, jac, self.x0, bounds=(self.lb, self.ub), sparse_diff=True) assert_(accuracy < 1e-9) A = self.structure(self.n) groups = group_columns(A) accuracy = check_derivative( self.fun, jac, self.x0, bounds=(self.lb, self.ub), sparse_diff=True, sparsity=(A, groups) ) assert_(accuracy < 1e-9) accuracy = check_derivative( self.fun, jac, self.x0, bounds=(self.lb, self.ub), sparse_diff=False) # Slightly worse accuracy because all elements are computed. # Floating point issues make true 0 to some smal value, then # it is divided by small step and as a result we have ~1e-9 element, # which is actually should be zero. assert_(accuracy < 1e-8)
def _validate_jac(y0, fun_vectorized, atol=1e-8, jac=None, sparsity=None): """ Taken from Scipy's Radau implementation. Returns a validated jacobian estimation function, using if possible the sparsity pattern of the Jacobian to optimize the computation""" n = y0.size f = fun_vectorized(y0) global jac_factor if not (jac_factor is None): if jac_factor.size != y0.size: # happens if we use twice the damped_newton on different size problems... jac_factor = None if jac is None: if sparsity is not None: if issparse(sparsity): sparsity = csc_matrix(sparsity) groups = group_columns(sparsity) sparsity = (sparsity, groups) def jac_wrapped(y): f = fun_vectorized(y) t = None # Scipy's numjac method assumes time is a separate variable global jac_factor # TODO: object oriented implementation of the Newton solver ? J, jac_factor = num_jac(fun=lambda t, y: fun_vectorized(y), t=t, y=y, f=f, threshold=atol, factor=jac_factor, sparsity=sparsity) return J J = jac_wrapped(y0) elif callable(jac): J = jac(y0) if issparse(J): J = csc_matrix(J) def jac_wrapped(y): return csc_matrix(jac(y), dtype=float) else: J = np.asarray(J, dtype=float) def jac_wrapped(y): return np.asarray(jac(y), dtype=float) if J.shape != (n, n): raise ValueError("`jac` is expected to have shape {}, but " "actually has {}.".format((n, n), J.shape)) else: if issparse(jac): J = csc_matrix(jac) else: J = np.asarray(jac, dtype=float) if J.shape != (n, n): raise ValueError("`jac` is expected to have shape {}, but " "actually has {}.".format((n, n), J.shape)) jac_wrapped = None return jac_wrapped, J
def test_num_jac_sparse(): def fun(t, y): e = y[1:]**3 - y[:-1]**2 z = np.zeros(y.shape[1]) return np.vstack((z, 3 * e)) + np.vstack((2 * e, z)) def structure(n): A = np.zeros((n, n), dtype=int) A[0, 0] = 1 A[0, 1] = 1 for i in range(1, n - 1): A[i, i - 1:i + 2] = 1 A[-1, -1] = 1 A[-1, -2] = 1 return A np.random.seed(0) n = 20 y = np.random.randn(n) A = structure(n) groups = group_columns(A) f = fun(0, y[:, None]).ravel() # Compare dense and sparse results, assuming that dense implementation # is correct (as it is straightforward). J_num_sparse, factor_sparse = num_jac(fun, 0, y.ravel(), f, 1e-8, None, sparsity=(A, groups)) J_num_dense, factor_dense = num_jac(fun, 0, y.ravel(), f, 1e-8, None) assert_allclose(J_num_dense, J_num_sparse.toarray(), rtol=1e-12, atol=1e-14) assert_allclose(factor_dense, factor_sparse, rtol=1e-12, atol=1e-14) # Take small factors to trigger their recomputing inside. factor = np.random.uniform(0, 1e-12, size=n) J_num_sparse, factor_sparse = num_jac(fun, 0, y.ravel(), f, 1e-8, factor, sparsity=(A, groups)) J_num_dense, factor_dense = num_jac(fun, 0, y.ravel(), f, 1e-8, factor) assert_allclose(J_num_dense, J_num_sparse.toarray(), rtol=1e-12, atol=1e-14) assert_allclose(factor_dense, factor_sparse, rtol=1e-12, atol=1e-14)
def test_all(self): A = self.structure(self.n) order = np.arange(self.n) groups_1 = group_columns(A, order) np.random.shuffle(order) groups_2 = group_columns(A, order) for method, groups, l, u in product( ['2-point', '3-point', 'cs'], [groups_1, groups_2], [-np.inf, self.lb], [np.inf, self.ub]): J = approx_derivative(self.fun, self.x0, method=method, bounds=(l, u), sparsity=(A, groups)) assert_(isinstance(J, csr_matrix)) assert_allclose(J.toarray(), self.J_true, rtol=1e-6) rel_step = 1e-8 * np.ones_like(self.x0) rel_step[::2] *= -1 J = approx_derivative(self.fun, self.x0, method=method, rel_step=rel_step, sparsity=(A, groups)) assert_allclose(J.toarray(), self.J_true, rtol=1e-5)
def check_jac_sparsity(jac_sparsity, m, n): if jac_sparsity is None: return None if not issparse(jac_sparsity): jac_sparsity = np.atleast_2d(jac_sparsity) if jac_sparsity.shape != (m, n): raise ValueError("`jac_sparsity` has wrong shape.") return jac_sparsity, group_columns(jac_sparsity)
def _validate_jac(self, jac, sparsity): t0 = self.t y0 = self.y if jac is None: if sparsity is not None: if issparse(sparsity): sparsity = csc_matrix(sparsity) groups = group_columns(sparsity) sparsity = (sparsity, groups) def jac_wrapped(t, y): self.njev += 1 f = self.fun_single(t, y) J, self.jac_factor = num_jac(self.fun_vectorized, t, y, f, self.atol, self.jac_factor, sparsity) return J J = jac_wrapped(t0, y0) elif callable(jac): J = jac(t0, y0) self.njev += 1 if issparse(J): J = csc_matrix(J, dtype=y0.dtype) def jac_wrapped(t, y): self.njev += 1 return csc_matrix(jac(t, y), dtype=y0.dtype) else: J = np.asarray(J, dtype=y0.dtype) def jac_wrapped(t, y): self.njev += 1 return np.asarray(jac(t, y), dtype=y0.dtype) if J.shape != (self.n, self.n): raise ValueError("`jac` is expected to have shape {}, but " "actually has {}.".format((self.n, self.n), J.shape)) else: if issparse(jac): J = csc_matrix(jac, dtype=y0.dtype) else: J = np.asarray(jac, dtype=y0.dtype) if J.shape != (self.n, self.n): raise ValueError("`jac` is expected to have shape {}, but " "actually has {}.".format((self.n, self.n), J.shape)) jac_wrapped = None return jac_wrapped, J
def _validate_jac(self, jac, sparsity): t0 = self.t y0 = self.y if jac is None: if sparsity is not None: if issparse(sparsity): sparsity = csc_matrix(sparsity) groups = group_columns(sparsity) sparsity = (sparsity, groups) def jac_wrapped(t, y, f): self.njev += 1 J, self.jac_factor = num_jac(self.fun_vectorized, t, y, f, self.atol, self.jac_factor, sparsity) return J J = jac_wrapped(t0, y0, self.f) elif callable(jac): J = jac(t0, y0) self.njev = 1 if issparse(J): J = csc_matrix(J) def jac_wrapped(t, y, _=None): self.njev += 1 return csc_matrix(jac(t, y), dtype=float) else: J = np.asarray(J, dtype=float) def jac_wrapped(t, y, _=None): self.njev += 1 return np.asarray(jac(t, y), dtype=float) if J.shape != (self.n, self.n): raise ValueError("`jac` is expected to have shape {}, but " "actually has {}." .format((self.n, self.n), J.shape)) else: if issparse(jac): J = csc_matrix(jac) else: J = np.asarray(jac, dtype=float) if J.shape != (self.n, self.n): raise ValueError("`jac` is expected to have shape {}, but " "actually has {}." .format((self.n, self.n), J.shape)) jac_wrapped = None return jac_wrapped, J
def check_jacobian(self): accuracy = [] if self.sparsity is not None: sparse_diff = True groups = group_columns(self.sparsity) sparsity = (self.sparsity, groups) else: sparse_diff = False sparsity = None for x0, bounds in self.specs: x = x0 + np.random.randn(self.n) acc = check_derivative(self.fun, self.jac, x, bounds=bounds, sparse_diff=sparse_diff, sparsity=sparsity) accuracy.append(acc) return accuracy
def test_num_jac_sparse(): def fun(t, y): e = y[1:]**3 - y[:-1]**2 z = np.zeros(y.shape[1]) return np.vstack((z, 3 * e)) + np.vstack((2 * e, z)) def structure(n): A = np.zeros((n, n), dtype=int) A[0, 0] = 1 A[0, 1] = 1 for i in range(1, n - 1): A[i, i - 1: i + 2] = 1 A[-1, -1] = 1 A[-1, -2] = 1 return A np.random.seed(0) n = 20 y = np.random.randn(n) A = structure(n) groups = group_columns(A) f = fun(0, y[:, None]).ravel() # Compare dense and sparse results, assuming that dense implementation # is correct (as it is straightforward). J_num_sparse, factor_sparse = num_jac(fun, 0, y.ravel(), f, 1e-8, None, sparsity=(A, groups)) J_num_dense, factor_dense = num_jac(fun, 0, y.ravel(), f, 1e-8, None) assert_allclose(J_num_dense, J_num_sparse.toarray(), rtol=1e-12, atol=1e-14) assert_allclose(factor_dense, factor_sparse, rtol=1e-12, atol=1e-14) # Take small factors to trigger their recomputing inside. factor = np.random.uniform(0, 1e-12, size=n) J_num_sparse, factor_sparse = num_jac(fun, 0, y.ravel(), f, 1e-8, factor, sparsity=(A, groups)) J_num_dense, factor_dense = num_jac(fun, 0, y.ravel(), f, 1e-8, factor) assert_allclose(J_num_dense, J_num_sparse.toarray(), rtol=1e-12, atol=1e-14) assert_allclose(factor_dense, factor_sparse, rtol=1e-12, atol=1e-14)