test__numdiff.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. from __future__ import division
  2. import math
  3. from itertools import product
  4. import numpy as np
  5. from numpy.testing import assert_allclose, assert_equal, assert_
  6. from pytest import raises as assert_raises
  7. from scipy.sparse import csr_matrix, csc_matrix, lil_matrix
  8. from scipy.optimize._numdiff import (
  9. _adjust_scheme_to_bounds, approx_derivative, check_derivative,
  10. group_columns)
  11. def test_group_columns():
  12. structure = [
  13. [1, 1, 0, 0, 0, 0],
  14. [1, 1, 1, 0, 0, 0],
  15. [0, 1, 1, 1, 0, 0],
  16. [0, 0, 1, 1, 1, 0],
  17. [0, 0, 0, 1, 1, 1],
  18. [0, 0, 0, 0, 1, 1],
  19. [0, 0, 0, 0, 0, 0]
  20. ]
  21. for transform in [np.asarray, csr_matrix, csc_matrix, lil_matrix]:
  22. A = transform(structure)
  23. order = np.arange(6)
  24. groups_true = np.array([0, 1, 2, 0, 1, 2])
  25. groups = group_columns(A, order)
  26. assert_equal(groups, groups_true)
  27. order = [1, 2, 4, 3, 5, 0]
  28. groups_true = np.array([2, 0, 1, 2, 0, 1])
  29. groups = group_columns(A, order)
  30. assert_equal(groups, groups_true)
  31. # Test repeatability.
  32. groups_1 = group_columns(A)
  33. groups_2 = group_columns(A)
  34. assert_equal(groups_1, groups_2)
  35. class TestAdjustSchemeToBounds(object):
  36. def test_no_bounds(self):
  37. x0 = np.zeros(3)
  38. h = np.ones(3) * 1e-2
  39. inf_lower = np.empty_like(x0)
  40. inf_upper = np.empty_like(x0)
  41. inf_lower.fill(-np.inf)
  42. inf_upper.fill(np.inf)
  43. h_adjusted, one_sided = _adjust_scheme_to_bounds(
  44. x0, h, 1, '1-sided', inf_lower, inf_upper)
  45. assert_allclose(h_adjusted, h)
  46. assert_(np.all(one_sided))
  47. h_adjusted, one_sided = _adjust_scheme_to_bounds(
  48. x0, h, 2, '1-sided', inf_lower, inf_upper)
  49. assert_allclose(h_adjusted, h)
  50. assert_(np.all(one_sided))
  51. h_adjusted, one_sided = _adjust_scheme_to_bounds(
  52. x0, h, 1, '2-sided', inf_lower, inf_upper)
  53. assert_allclose(h_adjusted, h)
  54. assert_(np.all(~one_sided))
  55. h_adjusted, one_sided = _adjust_scheme_to_bounds(
  56. x0, h, 2, '2-sided', inf_lower, inf_upper)
  57. assert_allclose(h_adjusted, h)
  58. assert_(np.all(~one_sided))
  59. def test_with_bound(self):
  60. x0 = np.array([0.0, 0.85, -0.85])
  61. lb = -np.ones(3)
  62. ub = np.ones(3)
  63. h = np.array([1, 1, -1]) * 1e-1
  64. h_adjusted, _ = _adjust_scheme_to_bounds(x0, h, 1, '1-sided', lb, ub)
  65. assert_allclose(h_adjusted, h)
  66. h_adjusted, _ = _adjust_scheme_to_bounds(x0, h, 2, '1-sided', lb, ub)
  67. assert_allclose(h_adjusted, np.array([1, -1, 1]) * 1e-1)
  68. h_adjusted, one_sided = _adjust_scheme_to_bounds(
  69. x0, h, 1, '2-sided', lb, ub)
  70. assert_allclose(h_adjusted, np.abs(h))
  71. assert_(np.all(~one_sided))
  72. h_adjusted, one_sided = _adjust_scheme_to_bounds(
  73. x0, h, 2, '2-sided', lb, ub)
  74. assert_allclose(h_adjusted, np.array([1, -1, 1]) * 1e-1)
  75. assert_equal(one_sided, np.array([False, True, True]))
  76. def test_tight_bounds(self):
  77. lb = np.array([-0.03, -0.03])
  78. ub = np.array([0.05, 0.05])
  79. x0 = np.array([0.0, 0.03])
  80. h = np.array([-0.1, -0.1])
  81. h_adjusted, _ = _adjust_scheme_to_bounds(x0, h, 1, '1-sided', lb, ub)
  82. assert_allclose(h_adjusted, np.array([0.05, -0.06]))
  83. h_adjusted, _ = _adjust_scheme_to_bounds(x0, h, 2, '1-sided', lb, ub)
  84. assert_allclose(h_adjusted, np.array([0.025, -0.03]))
  85. h_adjusted, one_sided = _adjust_scheme_to_bounds(
  86. x0, h, 1, '2-sided', lb, ub)
  87. assert_allclose(h_adjusted, np.array([0.03, -0.03]))
  88. assert_equal(one_sided, np.array([False, True]))
  89. h_adjusted, one_sided = _adjust_scheme_to_bounds(
  90. x0, h, 2, '2-sided', lb, ub)
  91. assert_allclose(h_adjusted, np.array([0.015, -0.015]))
  92. assert_equal(one_sided, np.array([False, True]))
  93. class TestApproxDerivativesDense(object):
  94. def fun_scalar_scalar(self, x):
  95. return np.sinh(x)
  96. def jac_scalar_scalar(self, x):
  97. return np.cosh(x)
  98. def fun_scalar_vector(self, x):
  99. return np.array([x[0]**2, np.tan(x[0]), np.exp(x[0])])
  100. def jac_scalar_vector(self, x):
  101. return np.array(
  102. [2 * x[0], np.cos(x[0]) ** -2, np.exp(x[0])]).reshape(-1, 1)
  103. def fun_vector_scalar(self, x):
  104. return np.sin(x[0] * x[1]) * np.log(x[0])
  105. def wrong_dimensions_fun(self, x):
  106. return np.array([x**2, np.tan(x), np.exp(x)])
  107. def jac_vector_scalar(self, x):
  108. return np.array([
  109. x[1] * np.cos(x[0] * x[1]) * np.log(x[0]) +
  110. np.sin(x[0] * x[1]) / x[0],
  111. x[0] * np.cos(x[0] * x[1]) * np.log(x[0])
  112. ])
  113. def fun_vector_vector(self, x):
  114. return np.array([
  115. x[0] * np.sin(x[1]),
  116. x[1] * np.cos(x[0]),
  117. x[0] ** 3 * x[1] ** -0.5
  118. ])
  119. def jac_vector_vector(self, x):
  120. return np.array([
  121. [np.sin(x[1]), x[0] * np.cos(x[1])],
  122. [-x[1] * np.sin(x[0]), np.cos(x[0])],
  123. [3 * x[0] ** 2 * x[1] ** -0.5, -0.5 * x[0] ** 3 * x[1] ** -1.5]
  124. ])
  125. def fun_parametrized(self, x, c0, c1=1.0):
  126. return np.array([np.exp(c0 * x[0]), np.exp(c1 * x[1])])
  127. def jac_parametrized(self, x, c0, c1=0.1):
  128. return np.array([
  129. [c0 * np.exp(c0 * x[0]), 0],
  130. [0, c1 * np.exp(c1 * x[1])]
  131. ])
  132. def fun_with_nan(self, x):
  133. return x if np.abs(x) <= 1e-8 else np.nan
  134. def jac_with_nan(self, x):
  135. return 1.0 if np.abs(x) <= 1e-8 else np.nan
  136. def fun_zero_jacobian(self, x):
  137. return np.array([x[0] * x[1], np.cos(x[0] * x[1])])
  138. def jac_zero_jacobian(self, x):
  139. return np.array([
  140. [x[1], x[0]],
  141. [-x[1] * np.sin(x[0] * x[1]), -x[0] * np.sin(x[0] * x[1])]
  142. ])
  143. def fun_non_numpy(self, x):
  144. return math.exp(x)
  145. def jac_non_numpy(self, x):
  146. return math.exp(x)
  147. def test_scalar_scalar(self):
  148. x0 = 1.0
  149. jac_diff_2 = approx_derivative(self.fun_scalar_scalar, x0,
  150. method='2-point')
  151. jac_diff_3 = approx_derivative(self.fun_scalar_scalar, x0)
  152. jac_diff_4 = approx_derivative(self.fun_scalar_scalar, x0,
  153. method='cs')
  154. jac_true = self.jac_scalar_scalar(x0)
  155. assert_allclose(jac_diff_2, jac_true, rtol=1e-6)
  156. assert_allclose(jac_diff_3, jac_true, rtol=1e-9)
  157. assert_allclose(jac_diff_4, jac_true, rtol=1e-12)
  158. def test_scalar_vector(self):
  159. x0 = 0.5
  160. jac_diff_2 = approx_derivative(self.fun_scalar_vector, x0,
  161. method='2-point')
  162. jac_diff_3 = approx_derivative(self.fun_scalar_vector, x0)
  163. jac_diff_4 = approx_derivative(self.fun_scalar_vector, x0,
  164. method='cs')
  165. jac_true = self.jac_scalar_vector(np.atleast_1d(x0))
  166. assert_allclose(jac_diff_2, jac_true, rtol=1e-6)
  167. assert_allclose(jac_diff_3, jac_true, rtol=1e-9)
  168. assert_allclose(jac_diff_4, jac_true, rtol=1e-12)
  169. def test_vector_scalar(self):
  170. x0 = np.array([100.0, -0.5])
  171. jac_diff_2 = approx_derivative(self.fun_vector_scalar, x0,
  172. method='2-point')
  173. jac_diff_3 = approx_derivative(self.fun_vector_scalar, x0)
  174. jac_diff_4 = approx_derivative(self.fun_vector_scalar, x0,
  175. method='cs')
  176. jac_true = self.jac_vector_scalar(x0)
  177. assert_allclose(jac_diff_2, jac_true, rtol=1e-6)
  178. assert_allclose(jac_diff_3, jac_true, rtol=1e-7)
  179. assert_allclose(jac_diff_4, jac_true, rtol=1e-12)
  180. def test_vector_vector(self):
  181. x0 = np.array([-100.0, 0.2])
  182. jac_diff_2 = approx_derivative(self.fun_vector_vector, x0,
  183. method='2-point')
  184. jac_diff_3 = approx_derivative(self.fun_vector_vector, x0)
  185. jac_diff_4 = approx_derivative(self.fun_vector_vector, x0,
  186. method='cs')
  187. jac_true = self.jac_vector_vector(x0)
  188. assert_allclose(jac_diff_2, jac_true, rtol=1e-5)
  189. assert_allclose(jac_diff_3, jac_true, rtol=1e-6)
  190. assert_allclose(jac_diff_4, jac_true, rtol=1e-12)
  191. def test_wrong_dimensions(self):
  192. x0 = 1.0
  193. assert_raises(RuntimeError, approx_derivative,
  194. self.wrong_dimensions_fun, x0)
  195. f0 = self.wrong_dimensions_fun(np.atleast_1d(x0))
  196. assert_raises(ValueError, approx_derivative,
  197. self.wrong_dimensions_fun, x0, f0=f0)
  198. def test_custom_rel_step(self):
  199. x0 = np.array([-0.1, 0.1])
  200. jac_diff_2 = approx_derivative(self.fun_vector_vector, x0,
  201. method='2-point', rel_step=1e-4)
  202. jac_diff_3 = approx_derivative(self.fun_vector_vector, x0,
  203. rel_step=1e-4)
  204. jac_true = self.jac_vector_vector(x0)
  205. assert_allclose(jac_diff_2, jac_true, rtol=1e-2)
  206. assert_allclose(jac_diff_3, jac_true, rtol=1e-4)
  207. def test_options(self):
  208. x0 = np.array([1.0, 1.0])
  209. c0 = -1.0
  210. c1 = 1.0
  211. lb = 0.0
  212. ub = 2.0
  213. f0 = self.fun_parametrized(x0, c0, c1=c1)
  214. rel_step = np.array([-1e-6, 1e-7])
  215. jac_true = self.jac_parametrized(x0, c0, c1)
  216. jac_diff_2 = approx_derivative(
  217. self.fun_parametrized, x0, method='2-point', rel_step=rel_step,
  218. f0=f0, args=(c0,), kwargs=dict(c1=c1), bounds=(lb, ub))
  219. jac_diff_3 = approx_derivative(
  220. self.fun_parametrized, x0, rel_step=rel_step,
  221. f0=f0, args=(c0,), kwargs=dict(c1=c1), bounds=(lb, ub))
  222. assert_allclose(jac_diff_2, jac_true, rtol=1e-6)
  223. assert_allclose(jac_diff_3, jac_true, rtol=1e-9)
  224. def test_with_bounds_2_point(self):
  225. lb = -np.ones(2)
  226. ub = np.ones(2)
  227. x0 = np.array([-2.0, 0.2])
  228. assert_raises(ValueError, approx_derivative,
  229. self.fun_vector_vector, x0, bounds=(lb, ub))
  230. x0 = np.array([-1.0, 1.0])
  231. jac_diff = approx_derivative(self.fun_vector_vector, x0,
  232. method='2-point', bounds=(lb, ub))
  233. jac_true = self.jac_vector_vector(x0)
  234. assert_allclose(jac_diff, jac_true, rtol=1e-6)
  235. def test_with_bounds_3_point(self):
  236. lb = np.array([1.0, 1.0])
  237. ub = np.array([2.0, 2.0])
  238. x0 = np.array([1.0, 2.0])
  239. jac_true = self.jac_vector_vector(x0)
  240. jac_diff = approx_derivative(self.fun_vector_vector, x0)
  241. assert_allclose(jac_diff, jac_true, rtol=1e-9)
  242. jac_diff = approx_derivative(self.fun_vector_vector, x0,
  243. bounds=(lb, np.inf))
  244. assert_allclose(jac_diff, jac_true, rtol=1e-9)
  245. jac_diff = approx_derivative(self.fun_vector_vector, x0,
  246. bounds=(-np.inf, ub))
  247. assert_allclose(jac_diff, jac_true, rtol=1e-9)
  248. jac_diff = approx_derivative(self.fun_vector_vector, x0,
  249. bounds=(lb, ub))
  250. assert_allclose(jac_diff, jac_true, rtol=1e-9)
  251. def test_tight_bounds(self):
  252. x0 = np.array([10.0, 10.0])
  253. lb = x0 - 3e-9
  254. ub = x0 + 2e-9
  255. jac_true = self.jac_vector_vector(x0)
  256. jac_diff = approx_derivative(
  257. self.fun_vector_vector, x0, method='2-point', bounds=(lb, ub))
  258. assert_allclose(jac_diff, jac_true, rtol=1e-6)
  259. jac_diff = approx_derivative(
  260. self.fun_vector_vector, x0, method='2-point',
  261. rel_step=1e-6, bounds=(lb, ub))
  262. assert_allclose(jac_diff, jac_true, rtol=1e-6)
  263. jac_diff = approx_derivative(
  264. self.fun_vector_vector, x0, bounds=(lb, ub))
  265. assert_allclose(jac_diff, jac_true, rtol=1e-6)
  266. jac_diff = approx_derivative(
  267. self.fun_vector_vector, x0, rel_step=1e-6, bounds=(lb, ub))
  268. assert_allclose(jac_true, jac_diff, rtol=1e-6)
  269. def test_bound_switches(self):
  270. lb = -1e-8
  271. ub = 1e-8
  272. x0 = 0.0
  273. jac_true = self.jac_with_nan(x0)
  274. jac_diff_2 = approx_derivative(
  275. self.fun_with_nan, x0, method='2-point', rel_step=1e-6,
  276. bounds=(lb, ub))
  277. jac_diff_3 = approx_derivative(
  278. self.fun_with_nan, x0, rel_step=1e-6, bounds=(lb, ub))
  279. assert_allclose(jac_diff_2, jac_true, rtol=1e-6)
  280. assert_allclose(jac_diff_3, jac_true, rtol=1e-9)
  281. x0 = 1e-8
  282. jac_true = self.jac_with_nan(x0)
  283. jac_diff_2 = approx_derivative(
  284. self.fun_with_nan, x0, method='2-point', rel_step=1e-6,
  285. bounds=(lb, ub))
  286. jac_diff_3 = approx_derivative(
  287. self.fun_with_nan, x0, rel_step=1e-6, bounds=(lb, ub))
  288. assert_allclose(jac_diff_2, jac_true, rtol=1e-6)
  289. assert_allclose(jac_diff_3, jac_true, rtol=1e-9)
  290. def test_non_numpy(self):
  291. x0 = 1.0
  292. jac_true = self.jac_non_numpy(x0)
  293. jac_diff_2 = approx_derivative(self.jac_non_numpy, x0,
  294. method='2-point')
  295. jac_diff_3 = approx_derivative(self.jac_non_numpy, x0)
  296. assert_allclose(jac_diff_2, jac_true, rtol=1e-6)
  297. assert_allclose(jac_diff_3, jac_true, rtol=1e-8)
  298. # math.exp cannot handle complex arguments, hence this raises
  299. assert_raises(TypeError, approx_derivative, self.jac_non_numpy, x0,
  300. **dict(method='cs'))
  301. def test_check_derivative(self):
  302. x0 = np.array([-10.0, 10])
  303. accuracy = check_derivative(self.fun_vector_vector,
  304. self.jac_vector_vector, x0)
  305. assert_(accuracy < 1e-9)
  306. accuracy = check_derivative(self.fun_vector_vector,
  307. self.jac_vector_vector, x0)
  308. assert_(accuracy < 1e-6)
  309. x0 = np.array([0.0, 0.0])
  310. accuracy = check_derivative(self.fun_zero_jacobian,
  311. self.jac_zero_jacobian, x0)
  312. assert_(accuracy == 0)
  313. accuracy = check_derivative(self.fun_zero_jacobian,
  314. self.jac_zero_jacobian, x0)
  315. assert_(accuracy == 0)
  316. class TestApproxDerivativeSparse(object):
  317. # Example from Numerical Optimization 2nd edition, p. 198.
  318. def setup_method(self):
  319. np.random.seed(0)
  320. self.n = 50
  321. self.lb = -0.1 * (1 + np.arange(self.n))
  322. self.ub = 0.1 * (1 + np.arange(self.n))
  323. self.x0 = np.empty(self.n)
  324. self.x0[::2] = (1 - 1e-7) * self.lb[::2]
  325. self.x0[1::2] = (1 - 1e-7) * self.ub[1::2]
  326. self.J_true = self.jac(self.x0)
  327. def fun(self, x):
  328. e = x[1:]**3 - x[:-1]**2
  329. return np.hstack((0, 3 * e)) + np.hstack((2 * e, 0))
  330. def jac(self, x):
  331. n = x.size
  332. J = np.zeros((n, n))
  333. J[0, 0] = -4 * x[0]
  334. J[0, 1] = 6 * x[1]**2
  335. for i in range(1, n - 1):
  336. J[i, i - 1] = -6 * x[i-1]
  337. J[i, i] = 9 * x[i]**2 - 4 * x[i]
  338. J[i, i + 1] = 6 * x[i+1]**2
  339. J[-1, -1] = 9 * x[-1]**2
  340. J[-1, -2] = -6 * x[-2]
  341. return J
  342. def structure(self, n):
  343. A = np.zeros((n, n), dtype=int)
  344. A[0, 0] = 1
  345. A[0, 1] = 1
  346. for i in range(1, n - 1):
  347. A[i, i - 1: i + 2] = 1
  348. A[-1, -1] = 1
  349. A[-1, -2] = 1
  350. return A
  351. def test_all(self):
  352. A = self.structure(self.n)
  353. order = np.arange(self.n)
  354. groups_1 = group_columns(A, order)
  355. np.random.shuffle(order)
  356. groups_2 = group_columns(A, order)
  357. for method, groups, l, u in product(
  358. ['2-point', '3-point', 'cs'], [groups_1, groups_2],
  359. [-np.inf, self.lb], [np.inf, self.ub]):
  360. J = approx_derivative(self.fun, self.x0, method=method,
  361. bounds=(l, u), sparsity=(A, groups))
  362. assert_(isinstance(J, csr_matrix))
  363. assert_allclose(J.toarray(), self.J_true, rtol=1e-6)
  364. rel_step = 1e-8 * np.ones_like(self.x0)
  365. rel_step[::2] *= -1
  366. J = approx_derivative(self.fun, self.x0, method=method,
  367. rel_step=rel_step, sparsity=(A, groups))
  368. assert_allclose(J.toarray(), self.J_true, rtol=1e-5)
  369. def test_no_precomputed_groups(self):
  370. A = self.structure(self.n)
  371. J = approx_derivative(self.fun, self.x0, sparsity=A)
  372. assert_allclose(J.toarray(), self.J_true, rtol=1e-6)
  373. def test_equivalence(self):
  374. structure = np.ones((self.n, self.n), dtype=int)
  375. groups = np.arange(self.n)
  376. for method in ['2-point', '3-point', 'cs']:
  377. J_dense = approx_derivative(self.fun, self.x0, method=method)
  378. J_sparse = approx_derivative(
  379. self.fun, self.x0, sparsity=(structure, groups), method=method)
  380. assert_equal(J_dense, J_sparse.toarray())
  381. def test_check_derivative(self):
  382. def jac(x):
  383. return csr_matrix(self.jac(x))
  384. accuracy = check_derivative(self.fun, jac, self.x0,
  385. bounds=(self.lb, self.ub))
  386. assert_(accuracy < 1e-9)
  387. accuracy = check_derivative(self.fun, jac, self.x0,
  388. bounds=(self.lb, self.ub))
  389. assert_(accuracy < 1e-9)
  390. class TestApproxDerivativeLinearOperator(object):
  391. def fun_scalar_scalar(self, x):
  392. return np.sinh(x)
  393. def jac_scalar_scalar(self, x):
  394. return np.cosh(x)
  395. def fun_scalar_vector(self, x):
  396. return np.array([x[0]**2, np.tan(x[0]), np.exp(x[0])])
  397. def jac_scalar_vector(self, x):
  398. return np.array(
  399. [2 * x[0], np.cos(x[0]) ** -2, np.exp(x[0])]).reshape(-1, 1)
  400. def fun_vector_scalar(self, x):
  401. return np.sin(x[0] * x[1]) * np.log(x[0])
  402. def jac_vector_scalar(self, x):
  403. return np.array([
  404. x[1] * np.cos(x[0] * x[1]) * np.log(x[0]) +
  405. np.sin(x[0] * x[1]) / x[0],
  406. x[0] * np.cos(x[0] * x[1]) * np.log(x[0])
  407. ])
  408. def fun_vector_vector(self, x):
  409. return np.array([
  410. x[0] * np.sin(x[1]),
  411. x[1] * np.cos(x[0]),
  412. x[0] ** 3 * x[1] ** -0.5
  413. ])
  414. def jac_vector_vector(self, x):
  415. return np.array([
  416. [np.sin(x[1]), x[0] * np.cos(x[1])],
  417. [-x[1] * np.sin(x[0]), np.cos(x[0])],
  418. [3 * x[0] ** 2 * x[1] ** -0.5, -0.5 * x[0] ** 3 * x[1] ** -1.5]
  419. ])
  420. def test_scalar_scalar(self):
  421. x0 = 1.0
  422. jac_diff_2 = approx_derivative(self.fun_scalar_scalar, x0,
  423. method='2-point',
  424. as_linear_operator=True)
  425. jac_diff_3 = approx_derivative(self.fun_scalar_scalar, x0,
  426. as_linear_operator=True)
  427. jac_diff_4 = approx_derivative(self.fun_scalar_scalar, x0,
  428. method='cs',
  429. as_linear_operator=True)
  430. jac_true = self.jac_scalar_scalar(x0)
  431. np.random.seed(1)
  432. for i in range(10):
  433. p = np.random.uniform(-10, 10, size=(1,))
  434. assert_allclose(jac_diff_2.dot(p), jac_true*p,
  435. rtol=1e-5)
  436. assert_allclose(jac_diff_3.dot(p), jac_true*p,
  437. rtol=5e-6)
  438. assert_allclose(jac_diff_4.dot(p), jac_true*p,
  439. rtol=5e-6)
  440. def test_scalar_vector(self):
  441. x0 = 0.5
  442. jac_diff_2 = approx_derivative(self.fun_scalar_vector, x0,
  443. method='2-point',
  444. as_linear_operator=True)
  445. jac_diff_3 = approx_derivative(self.fun_scalar_vector, x0,
  446. as_linear_operator=True)
  447. jac_diff_4 = approx_derivative(self.fun_scalar_vector, x0,
  448. method='cs',
  449. as_linear_operator=True)
  450. jac_true = self.jac_scalar_vector(np.atleast_1d(x0))
  451. np.random.seed(1)
  452. for i in range(10):
  453. p = np.random.uniform(-10, 10, size=(1,))
  454. assert_allclose(jac_diff_2.dot(p), jac_true.dot(p),
  455. rtol=1e-5)
  456. assert_allclose(jac_diff_3.dot(p), jac_true.dot(p),
  457. rtol=5e-6)
  458. assert_allclose(jac_diff_4.dot(p), jac_true.dot(p),
  459. rtol=5e-6)
  460. def test_vector_scalar(self):
  461. x0 = np.array([100.0, -0.5])
  462. jac_diff_2 = approx_derivative(self.fun_vector_scalar, x0,
  463. method='2-point',
  464. as_linear_operator=True)
  465. jac_diff_3 = approx_derivative(self.fun_vector_scalar, x0,
  466. as_linear_operator=True)
  467. jac_diff_4 = approx_derivative(self.fun_vector_scalar, x0,
  468. method='cs',
  469. as_linear_operator=True)
  470. jac_true = self.jac_vector_scalar(x0)
  471. np.random.seed(1)
  472. for i in range(10):
  473. p = np.random.uniform(-10, 10, size=x0.shape)
  474. assert_allclose(jac_diff_2.dot(p), np.atleast_1d(jac_true.dot(p)),
  475. rtol=1e-5)
  476. assert_allclose(jac_diff_3.dot(p), np.atleast_1d(jac_true.dot(p)),
  477. rtol=5e-6)
  478. assert_allclose(jac_diff_4.dot(p), np.atleast_1d(jac_true.dot(p)),
  479. rtol=1e-7)
  480. def test_vector_vector(self):
  481. x0 = np.array([-100.0, 0.2])
  482. jac_diff_2 = approx_derivative(self.fun_vector_vector, x0,
  483. method='2-point',
  484. as_linear_operator=True)
  485. jac_diff_3 = approx_derivative(self.fun_vector_vector, x0,
  486. as_linear_operator=True)
  487. jac_diff_4 = approx_derivative(self.fun_vector_vector, x0,
  488. method='cs',
  489. as_linear_operator=True)
  490. jac_true = self.jac_vector_vector(x0)
  491. np.random.seed(1)
  492. for i in range(10):
  493. p = np.random.uniform(-10, 10, size=x0.shape)
  494. assert_allclose(jac_diff_2.dot(p), jac_true.dot(p), rtol=1e-5)
  495. assert_allclose(jac_diff_3.dot(p), jac_true.dot(p), rtol=1e-6)
  496. assert_allclose(jac_diff_4.dot(p), jac_true.dot(p), rtol=1e-7)
  497. def test_exception(self):
  498. x0 = np.array([-100.0, 0.2])
  499. assert_raises(ValueError, approx_derivative,
  500. self.fun_vector_vector, x0,
  501. method='2-point', bounds=(1, np.inf))