test__shgo.py 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812
  1. import logging
  2. import numpy
  3. from numpy.testing import assert_allclose
  4. import pytest
  5. from pytest import raises as assert_raises, warns
  6. from scipy.optimize import shgo, Bounds, minimize
  7. from scipy.optimize._shgo import SHGO
  8. class StructTestFunction:
  9. def __init__(self, bounds, expected_x, expected_fun=None,
  10. expected_xl=None, expected_funl=None):
  11. self.bounds = bounds
  12. self.expected_x = expected_x
  13. self.expected_fun = expected_fun
  14. self.expected_xl = expected_xl
  15. self.expected_funl = expected_funl
  16. def wrap_constraints(g):
  17. cons = []
  18. if g is not None:
  19. if (type(g) is not tuple) and (type(g) is not list):
  20. g = (g,)
  21. else:
  22. pass
  23. for g in g:
  24. cons.append({'type': 'ineq',
  25. 'fun': g})
  26. cons = tuple(cons)
  27. else:
  28. cons = None
  29. return cons
  30. class StructTest1(StructTestFunction):
  31. def f(self, x):
  32. return x[0] ** 2 + x[1] ** 2
  33. def g(x):
  34. return -(numpy.sum(x, axis=0) - 6.0)
  35. cons = wrap_constraints(g)
  36. test1_1 = StructTest1(bounds=[(-1, 6), (-1, 6)],
  37. expected_x=[0, 0])
  38. test1_2 = StructTest1(bounds=[(0, 1), (0, 1)],
  39. expected_x=[0, 0])
  40. test1_3 = StructTest1(bounds=[(None, None), (None, None)],
  41. expected_x=[0, 0])
  42. class StructTest2(StructTestFunction):
  43. """
  44. Scalar function with several minima to test all minimizer retrievals
  45. """
  46. def f(self, x):
  47. return (x - 30) * numpy.sin(x)
  48. def g(x):
  49. return 58 - numpy.sum(x, axis=0)
  50. cons = wrap_constraints(g)
  51. test2_1 = StructTest2(bounds=[(0, 60)],
  52. expected_x=[1.53567906],
  53. expected_fun=-28.44677132,
  54. # Important: test that funl return is in the correct order
  55. expected_xl=numpy.array([[1.53567906],
  56. [55.01782167],
  57. [7.80894889],
  58. [48.74797493],
  59. [14.07445705],
  60. [42.4913859],
  61. [20.31743841],
  62. [36.28607535],
  63. [26.43039605],
  64. [30.76371366]]),
  65. expected_funl=numpy.array([-28.44677132, -24.99785984,
  66. -22.16855376, -18.72136195,
  67. -15.89423937, -12.45154942,
  68. -9.63133158, -6.20801301,
  69. -3.43727232, -0.46353338])
  70. )
  71. test2_2 = StructTest2(bounds=[(0, 4.5)],
  72. expected_x=[1.53567906],
  73. expected_fun=[-28.44677132],
  74. expected_xl=numpy.array([[1.53567906]]),
  75. expected_funl=numpy.array([-28.44677132])
  76. )
  77. class StructTest3(StructTestFunction):
  78. """
  79. Hock and Schittkowski 18 problem (HS18). Hoch and Schittkowski (1981)
  80. http://www.ai7.uni-bayreuth.de/test_problem_coll.pdf
  81. Minimize: f = 0.01 * (x_1)**2 + (x_2)**2
  82. Subject to: x_1 * x_2 - 25.0 >= 0,
  83. (x_1)**2 + (x_2)**2 - 25.0 >= 0,
  84. 2 <= x_1 <= 50,
  85. 0 <= x_2 <= 50.
  86. Approx. Answer:
  87. f([(250)**0.5 , (2.5)**0.5]) = 5.0
  88. """
  89. def f(self, x):
  90. return 0.01 * (x[0]) ** 2 + (x[1]) ** 2
  91. def g1(x):
  92. return x[0] * x[1] - 25.0
  93. def g2(x):
  94. return x[0] ** 2 + x[1] ** 2 - 25.0
  95. g = (g1, g2)
  96. cons = wrap_constraints(g)
  97. test3_1 = StructTest3(bounds=[(2, 50), (0, 50)],
  98. expected_x=[250 ** 0.5, 2.5 ** 0.5],
  99. expected_fun=5.0
  100. )
  101. class StructTest4(StructTestFunction):
  102. """
  103. Hock and Schittkowski 11 problem (HS11). Hoch and Schittkowski (1981)
  104. NOTE: Did not find in original reference to HS collection, refer to
  105. Henderson (2015) problem 7 instead. 02.03.2016
  106. """
  107. def f(self, x):
  108. return ((x[0] - 10) ** 2 + 5 * (x[1] - 12) ** 2 + x[2] ** 4
  109. + 3 * (x[3] - 11) ** 2 + 10 * x[4] ** 6 + 7 * x[5] ** 2 + x[
  110. 6] ** 4
  111. - 4 * x[5] * x[6] - 10 * x[5] - 8 * x[6]
  112. )
  113. def g1(x):
  114. return -(2 * x[0] ** 2 + 3 * x[1] ** 4 + x[2] + 4 * x[3] ** 2
  115. + 5 * x[4] - 127)
  116. def g2(x):
  117. return -(7 * x[0] + 3 * x[1] + 10 * x[2] ** 2 + x[3] - x[4] - 282.0)
  118. def g3(x):
  119. return -(23 * x[0] + x[1] ** 2 + 6 * x[5] ** 2 - 8 * x[6] - 196)
  120. def g4(x):
  121. return -(4 * x[0] ** 2 + x[1] ** 2 - 3 * x[0] * x[1] + 2 * x[2] ** 2
  122. + 5 * x[5] - 11 * x[6])
  123. g = (g1, g2, g3, g4)
  124. cons = wrap_constraints(g)
  125. test4_1 = StructTest4(bounds=[(-10, 10), ] * 7,
  126. expected_x=[2.330499, 1.951372, -0.4775414,
  127. 4.365726, -0.6244870, 1.038131, 1.594227],
  128. expected_fun=680.6300573
  129. )
  130. class StructTest5(StructTestFunction):
  131. def f(self, x):
  132. return (-(x[1] + 47.0)
  133. * numpy.sin(numpy.sqrt(abs(x[0] / 2.0 + (x[1] + 47.0))))
  134. - x[0] * numpy.sin(numpy.sqrt(abs(x[0] - (x[1] + 47.0))))
  135. )
  136. g = None
  137. cons = wrap_constraints(g)
  138. test5_1 = StructTest5(bounds=[(-512, 512), (-512, 512)],
  139. expected_fun=[-959.64066272085051],
  140. expected_x=[512., 404.23180542])
  141. class StructTestLJ(StructTestFunction):
  142. """
  143. LennardJones objective function. Used to test symmetry constraints settings.
  144. """
  145. def f(self, x, *args):
  146. self.N = args[0]
  147. k = int(self.N / 3)
  148. s = 0.0
  149. for i in range(k - 1):
  150. for j in range(i + 1, k):
  151. a = 3 * i
  152. b = 3 * j
  153. xd = x[a] - x[b]
  154. yd = x[a + 1] - x[b + 1]
  155. zd = x[a + 2] - x[b + 2]
  156. ed = xd * xd + yd * yd + zd * zd
  157. ud = ed * ed * ed
  158. if ed > 0.0:
  159. s += (1.0 / ud - 2.0) / ud
  160. return s
  161. g = None
  162. cons = wrap_constraints(g)
  163. N = 6
  164. boundsLJ = list(zip([-4.0] * 6, [4.0] * 6))
  165. testLJ = StructTestLJ(bounds=boundsLJ,
  166. expected_fun=[-1.0],
  167. expected_x=[-2.71247337e-08,
  168. -2.71247337e-08,
  169. -2.50000222e+00,
  170. -2.71247337e-08,
  171. -2.71247337e-08,
  172. -1.50000222e+00]
  173. )
  174. class StructTestTable(StructTestFunction):
  175. def f(self, x):
  176. if x[0] == 3.0 and x[1] == 3.0:
  177. return 50
  178. else:
  179. return 100
  180. g = None
  181. cons = wrap_constraints(g)
  182. test_table = StructTestTable(bounds=[(-10, 10), (-10, 10)],
  183. expected_fun=[50],
  184. expected_x=[3.0, 3.0])
  185. class StructTestInfeasible(StructTestFunction):
  186. """
  187. Test function with no feasible domain.
  188. """
  189. def f(self, x, *args):
  190. return x[0] ** 2 + x[1] ** 2
  191. def g1(x):
  192. return x[0] + x[1] - 1
  193. def g2(x):
  194. return -(x[0] + x[1] - 1)
  195. def g3(x):
  196. return -x[0] + x[1] - 1
  197. def g4(x):
  198. return -(-x[0] + x[1] - 1)
  199. g = (g1, g2, g3, g4)
  200. cons = wrap_constraints(g)
  201. test_infeasible = StructTestInfeasible(bounds=[(2, 50), (-1, 1)],
  202. expected_fun=None,
  203. expected_x=None
  204. )
  205. def run_test(test, args=(), test_atol=1e-5, n=128, iters=None,
  206. callback=None, minimizer_kwargs=None, options=None,
  207. sampling_method='sobol'):
  208. res = shgo(test.f, test.bounds, args=args, constraints=test.cons,
  209. n=n, iters=iters, callback=callback,
  210. minimizer_kwargs=minimizer_kwargs, options=options,
  211. sampling_method=sampling_method)
  212. logging.info(res)
  213. if test.expected_x is not None:
  214. numpy.testing.assert_allclose(res.x, test.expected_x,
  215. rtol=test_atol,
  216. atol=test_atol)
  217. # (Optional tests)
  218. if test.expected_fun is not None:
  219. numpy.testing.assert_allclose(res.fun,
  220. test.expected_fun,
  221. atol=test_atol)
  222. if test.expected_xl is not None:
  223. numpy.testing.assert_allclose(res.xl,
  224. test.expected_xl,
  225. atol=test_atol)
  226. if test.expected_funl is not None:
  227. numpy.testing.assert_allclose(res.funl,
  228. test.expected_funl,
  229. atol=test_atol)
  230. return
  231. # Base test functions:
  232. class TestShgoSobolTestFunctions:
  233. """
  234. Global optimization tests with Sobol sampling:
  235. """
  236. # Sobol algorithm
  237. def test_f1_1_sobol(self):
  238. """Multivariate test function 1:
  239. x[0]**2 + x[1]**2 with bounds=[(-1, 6), (-1, 6)]"""
  240. run_test(test1_1)
  241. def test_f1_2_sobol(self):
  242. """Multivariate test function 1:
  243. x[0]**2 + x[1]**2 with bounds=[(0, 1), (0, 1)]"""
  244. run_test(test1_2)
  245. def test_f1_3_sobol(self):
  246. """Multivariate test function 1:
  247. x[0]**2 + x[1]**2 with bounds=[(None, None),(None, None)]"""
  248. run_test(test1_3)
  249. def test_f2_1_sobol(self):
  250. """Univariate test function on
  251. f(x) = (x - 30) * sin(x) with bounds=[(0, 60)]"""
  252. run_test(test2_1)
  253. def test_f2_2_sobol(self):
  254. """Univariate test function on
  255. f(x) = (x - 30) * sin(x) bounds=[(0, 4.5)]"""
  256. run_test(test2_2)
  257. def test_f3_sobol(self):
  258. """NLP: Hock and Schittkowski problem 18"""
  259. run_test(test3_1)
  260. @pytest.mark.slow
  261. def test_f4_sobol(self):
  262. """NLP: (High-dimensional) Hock and Schittkowski 11 problem (HS11)"""
  263. # run_test(test4_1, n=500)
  264. # run_test(test4_1, n=800)
  265. options = {'infty_constraints': False}
  266. run_test(test4_1, n=2048, options=options)
  267. def test_f5_1_sobol(self):
  268. """NLP: Eggholder, multimodal"""
  269. run_test(test5_1, n=64)
  270. def test_f5_2_sobol(self):
  271. """NLP: Eggholder, multimodal"""
  272. # run_test(test5_1, n=60, iters=5)
  273. run_test(test5_1, n=128, iters=5)
  274. # def test_t911(self):
  275. # """1-D tabletop function"""
  276. # run_test(test11_1)
  277. class TestShgoSimplicialTestFunctions:
  278. """
  279. Global optimization tests with Simplicial sampling:
  280. """
  281. def test_f1_1_simplicial(self):
  282. """Multivariate test function 1:
  283. x[0]**2 + x[1]**2 with bounds=[(-1, 6), (-1, 6)]"""
  284. run_test(test1_1, n=1, sampling_method='simplicial')
  285. def test_f1_2_simplicial(self):
  286. """Multivariate test function 1:
  287. x[0]**2 + x[1]**2 with bounds=[(0, 1), (0, 1)]"""
  288. run_test(test1_2, n=1, sampling_method='simplicial')
  289. def test_f1_3_simplicial(self):
  290. """Multivariate test function 1: x[0]**2 + x[1]**2
  291. with bounds=[(None, None),(None, None)]"""
  292. run_test(test1_3, n=1, sampling_method='simplicial')
  293. def test_f2_1_simplicial(self):
  294. """Univariate test function on
  295. f(x) = (x - 30) * sin(x) with bounds=[(0, 60)]"""
  296. options = {'minimize_every_iter': False}
  297. run_test(test2_1, iters=7, options=options,
  298. sampling_method='simplicial')
  299. def test_f2_2_simplicial(self):
  300. """Univariate test function on
  301. f(x) = (x - 30) * sin(x) bounds=[(0, 4.5)]"""
  302. run_test(test2_2, n=1, sampling_method='simplicial')
  303. def test_f3_simplicial(self):
  304. """NLP: Hock and Schittkowski problem 18"""
  305. run_test(test3_1, n=1, sampling_method='simplicial')
  306. @pytest.mark.slow
  307. def test_f4_simplicial(self):
  308. """NLP: (High-dimensional) Hock and Schittkowski 11 problem (HS11)"""
  309. run_test(test4_1, n=1, sampling_method='simplicial')
  310. def test_lj_symmetry(self):
  311. """LJ: Symmetry-constrained test function"""
  312. options = {'symmetry': True,
  313. 'disp': True}
  314. args = (6,) # Number of atoms
  315. run_test(testLJ, args=args, n=None,
  316. options=options, iters=4,
  317. sampling_method='simplicial')
  318. # Argument test functions
  319. class TestShgoArguments:
  320. def test_1_1_simpl_iter(self):
  321. """Iterative simplicial sampling on TestFunction 1 (multivariate)"""
  322. run_test(test1_2, n=None, iters=2, sampling_method='simplicial')
  323. def test_1_2_simpl_iter(self):
  324. """Iterative simplicial on TestFunction 2 (univariate)"""
  325. options = {'minimize_every_iter': False}
  326. run_test(test2_1, n=None, iters=7, options=options,
  327. sampling_method='simplicial')
  328. def test_2_1_sobol_iter(self):
  329. """Iterative Sobol sampling on TestFunction 1 (multivariate)"""
  330. run_test(test1_2, n=None, iters=1, sampling_method='sobol')
  331. def test_2_2_sobol_iter(self):
  332. """Iterative Sobol sampling on TestFunction 2 (univariate)"""
  333. res = shgo(test2_1.f, test2_1.bounds, constraints=test2_1.cons,
  334. n=None, iters=1, sampling_method='sobol')
  335. numpy.testing.assert_allclose(res.x, test2_1.expected_x, rtol=1e-5,
  336. atol=1e-5)
  337. numpy.testing.assert_allclose(res.fun, test2_1.expected_fun, atol=1e-5)
  338. def test_3_1_disp_simplicial(self):
  339. """Iterative sampling on TestFunction 1 and 2 (multi- and univariate)"""
  340. def callback_func(x):
  341. print("Local minimization callback test")
  342. for test in [test1_1, test2_1]:
  343. shgo(test.f, test.bounds, iters=1,
  344. sampling_method='simplicial',
  345. callback=callback_func, options={'disp': True})
  346. shgo(test.f, test.bounds, n=1, sampling_method='simplicial',
  347. callback=callback_func, options={'disp': True})
  348. def test_3_2_disp_sobol(self):
  349. """Iterative sampling on TestFunction 1 and 2 (multi- and univariate)"""
  350. def callback_func(x):
  351. print("Local minimization callback test")
  352. for test in [test1_1, test2_1]:
  353. shgo(test.f, test.bounds, iters=1, sampling_method='sobol',
  354. callback=callback_func, options={'disp': True})
  355. shgo(test.f, test.bounds, n=1, sampling_method='simplicial',
  356. callback=callback_func, options={'disp': True})
  357. def test_args_gh14589(self):
  358. # Using `args` used to cause `shgo` to fail; see #14589, #15986, #16506
  359. res = shgo(func=lambda x, y, z: x*z + y, bounds=[(0, 3)], args=(1, 2))
  360. ref = shgo(func=lambda x: 2*x + 1, bounds=[(0, 3)])
  361. assert_allclose(res.fun, ref.fun)
  362. assert_allclose(res.x, ref.x)
  363. @pytest.mark.slow
  364. def test_4_1_known_f_min(self):
  365. """Test known function minima stopping criteria"""
  366. # Specify known function value
  367. options = {'f_min': test4_1.expected_fun,
  368. 'f_tol': 1e-6,
  369. 'minimize_every_iter': True}
  370. # TODO: Make default n higher for faster tests
  371. run_test(test4_1, n=None, test_atol=1e-5, options=options,
  372. sampling_method='simplicial')
  373. @pytest.mark.slow
  374. def test_4_2_known_f_min(self):
  375. """Test Global mode limiting local evalutions"""
  376. options = { # Specify known function value
  377. 'f_min': test4_1.expected_fun,
  378. 'f_tol': 1e-6,
  379. # Specify number of local iterations to perform
  380. 'minimize_every_iter': True,
  381. 'local_iter': 1}
  382. run_test(test4_1, n=None, test_atol=1e-5, options=options,
  383. sampling_method='simplicial')
  384. @pytest.mark.slow
  385. def test_4_3_known_f_min(self):
  386. """Test Global mode limiting local evalutions"""
  387. options = { # Specify known function value
  388. 'f_min': test4_1.expected_fun,
  389. 'f_tol': 1e-6,
  390. # Specify number of local iterations to perform+
  391. 'minimize_every_iter': True,
  392. 'local_iter': 1,
  393. 'infty_constraints': False}
  394. run_test(test4_1, n=1024, test_atol=1e-5, options=options,
  395. sampling_method='sobol')
  396. def test_4_4_known_f_min(self):
  397. """Test Global mode limiting local evalutions for 1-D functions"""
  398. options = { # Specify known function value
  399. 'f_min': test2_1.expected_fun,
  400. 'f_tol': 1e-6,
  401. # Specify number of local iterations to perform+
  402. 'minimize_every_iter': True,
  403. 'local_iter': 1,
  404. 'infty_constraints': False}
  405. res = shgo(test2_1.f, test2_1.bounds, constraints=test2_1.cons,
  406. n=None, iters=None, options=options,
  407. sampling_method='sobol')
  408. numpy.testing.assert_allclose(res.x, test2_1.expected_x, rtol=1e-5,
  409. atol=1e-5)
  410. def test_5_1_simplicial_argless(self):
  411. """Test Default simplicial sampling settings on TestFunction 1"""
  412. res = shgo(test1_1.f, test1_1.bounds, constraints=test1_1.cons)
  413. numpy.testing.assert_allclose(res.x, test1_1.expected_x, rtol=1e-5,
  414. atol=1e-5)
  415. def test_5_2_sobol_argless(self):
  416. """Test Default sobol sampling settings on TestFunction 1"""
  417. res = shgo(test1_1.f, test1_1.bounds, constraints=test1_1.cons,
  418. sampling_method='sobol')
  419. numpy.testing.assert_allclose(res.x, test1_1.expected_x, rtol=1e-5,
  420. atol=1e-5)
  421. def test_6_1_simplicial_max_iter(self):
  422. """Test that maximum iteration option works on TestFunction 3"""
  423. options = {'max_iter': 2}
  424. res = shgo(test3_1.f, test3_1.bounds, constraints=test3_1.cons,
  425. options=options, sampling_method='simplicial')
  426. numpy.testing.assert_allclose(res.x, test3_1.expected_x, rtol=1e-5,
  427. atol=1e-5)
  428. numpy.testing.assert_allclose(res.fun, test3_1.expected_fun, atol=1e-5)
  429. def test_6_2_simplicial_min_iter(self):
  430. """Test that maximum iteration option works on TestFunction 3"""
  431. options = {'min_iter': 2}
  432. res = shgo(test3_1.f, test3_1.bounds, constraints=test3_1.cons,
  433. options=options, sampling_method='simplicial')
  434. numpy.testing.assert_allclose(res.x, test3_1.expected_x, rtol=1e-5,
  435. atol=1e-5)
  436. numpy.testing.assert_allclose(res.fun, test3_1.expected_fun, atol=1e-5)
  437. def test_7_1_minkwargs(self):
  438. """Test the minimizer_kwargs arguments for solvers with constraints"""
  439. # Test solvers
  440. for solver in ['COBYLA', 'SLSQP']:
  441. # Note that passing global constraints to SLSQP is tested in other
  442. # unittests which run test4_1 normally
  443. minimizer_kwargs = {'method': solver,
  444. 'constraints': test3_1.cons}
  445. print("Solver = {}".format(solver))
  446. print("=" * 100)
  447. run_test(test3_1, n=128, test_atol=1e-3,
  448. minimizer_kwargs=minimizer_kwargs, sampling_method='sobol')
  449. def test_7_2_minkwargs(self):
  450. """Test the minimizer_kwargs default inits"""
  451. minimizer_kwargs = {'ftol': 1e-5}
  452. options = {'disp': True} # For coverage purposes
  453. SHGO(test3_1.f, test3_1.bounds, constraints=test3_1.cons[0],
  454. minimizer_kwargs=minimizer_kwargs, options=options)
  455. def test_7_3_minkwargs(self):
  456. """Test minimizer_kwargs arguments for solvers without constraints"""
  457. for solver in ['Nelder-Mead', 'Powell', 'CG', 'BFGS', 'Newton-CG',
  458. 'L-BFGS-B', 'TNC', 'dogleg', 'trust-ncg', 'trust-exact',
  459. 'trust-krylov']:
  460. def jac(x):
  461. return numpy.array([2 * x[0], 2 * x[1]]).T
  462. def hess(x):
  463. return numpy.array([[2, 0], [0, 2]])
  464. minimizer_kwargs = {'method': solver,
  465. 'jac': jac,
  466. 'hess': hess}
  467. logging.info("Solver = {}".format(solver))
  468. logging.info("=" * 100)
  469. run_test(test1_1, n=128, test_atol=1e-3,
  470. minimizer_kwargs=minimizer_kwargs, sampling_method='sobol')
  471. def test_8_homology_group_diff(self):
  472. options = {'minhgrd': 1,
  473. 'minimize_every_iter': True}
  474. run_test(test1_1, n=None, iters=None, options=options,
  475. sampling_method='simplicial')
  476. def test_9_cons_g(self):
  477. """Test single function constraint passing"""
  478. SHGO(test3_1.f, test3_1.bounds, constraints=test3_1.cons[0])
  479. def test_10_finite_time(self):
  480. """Test single function constraint passing"""
  481. options = {'maxtime': 1e-15}
  482. shgo(test1_1.f, test1_1.bounds, n=1, iters=None,
  483. options=options, sampling_method='sobol')
  484. def test_11_f_min_time(self):
  485. """Test to cover the case where f_lowest == 0"""
  486. options = {'maxtime': 1e-15,
  487. 'f_min': 0.0}
  488. shgo(test1_2.f, test1_2.bounds, n=1, iters=None,
  489. options=options, sampling_method='sobol')
  490. def test_12_sobol_inf_cons(self):
  491. """Test to cover the case where f_lowest == 0"""
  492. options = {'maxtime': 1e-15,
  493. 'f_min': 0.0}
  494. shgo(test1_2.f, test1_2.bounds, n=1, iters=None,
  495. options=options, sampling_method='sobol')
  496. def test_14_local_iter(self):
  497. """Test limited local iterations for a pseudo-global mode"""
  498. options = {'local_iter': 4}
  499. run_test(test5_1, n=64, options=options)
  500. def test_15_min_every_iter(self):
  501. """Test minimize every iter options and cover function cache"""
  502. options = {'minimize_every_iter': True}
  503. run_test(test1_1, n=1, iters=7, options=options,
  504. sampling_method='sobol')
  505. def test_16_disp_bounds_minimizer(self):
  506. """Test disp=True with minimizers that do not support bounds """
  507. options = {'disp': True}
  508. minimizer_kwargs = {'method': 'nelder-mead'}
  509. run_test(test1_2, sampling_method='simplicial',
  510. options=options, minimizer_kwargs=minimizer_kwargs)
  511. def test_17_custom_sampling(self):
  512. """Test the functionality to add custom sampling methods to shgo"""
  513. def sample(n, d):
  514. return numpy.random.uniform(size=(n,d))
  515. run_test(test1_1, n=30, sampling_method=sample)
  516. def test_18_bounds_class(self):
  517. # test that new and old bounds yield same result
  518. def f(x):
  519. return numpy.square(x).sum()
  520. lb = [-6., 1., -5.]
  521. ub = [-1., 3., 5.]
  522. bounds_old = list(zip(lb, ub))
  523. bounds_new = Bounds(lb, ub)
  524. res_old_bounds = shgo(f, bounds_old)
  525. res_new_bounds = shgo(f, bounds_new)
  526. assert res_new_bounds.nfev == res_old_bounds.nfev
  527. assert res_new_bounds.message == res_old_bounds.message
  528. assert res_new_bounds.success == res_old_bounds.success
  529. x_opt = numpy.array([-1., 1., 0.])
  530. numpy.testing.assert_allclose(res_new_bounds.x, x_opt)
  531. numpy.testing.assert_allclose(res_new_bounds.x,
  532. res_old_bounds.x)
  533. # Failure test functions
  534. class TestShgoFailures:
  535. def test_1_maxiter(self):
  536. """Test failure on insufficient iterations"""
  537. options = {'maxiter': 2}
  538. res = shgo(test4_1.f, test4_1.bounds, n=4, iters=None,
  539. options=options, sampling_method='sobol')
  540. numpy.testing.assert_equal(False, res.success)
  541. numpy.testing.assert_equal(4, res.nfev)
  542. def test_2_sampling(self):
  543. """Rejection of unknown sampling method"""
  544. assert_raises(ValueError, shgo, test1_1.f, test1_1.bounds,
  545. sampling_method='not_Sobol')
  546. def test_3_1_no_min_pool_sobol(self):
  547. """Check that the routine stops when no minimiser is found
  548. after maximum specified function evaluations"""
  549. options = {'maxfev': 10,
  550. 'disp': True}
  551. res = shgo(test_table.f, test_table.bounds, n=4, options=options,
  552. sampling_method='sobol')
  553. numpy.testing.assert_equal(False, res.success)
  554. numpy.testing.assert_equal(16, res.nfev)
  555. def test_3_2_no_min_pool_simplicial(self):
  556. """Check that the routine stops when no minimiser is found
  557. after maximum specified sampling evaluations"""
  558. options = {'maxev': 10,
  559. 'disp': True}
  560. res = shgo(test_table.f, test_table.bounds, n=3, options=options,
  561. sampling_method='simplicial')
  562. numpy.testing.assert_equal(False, res.success)
  563. def test_4_1_bound_err(self):
  564. """Specified bounds ub > lb"""
  565. bounds = [(6, 3), (3, 5)]
  566. assert_raises(ValueError, shgo, test1_1.f, bounds)
  567. def test_4_2_bound_err(self):
  568. """Specified bounds are of the form (lb, ub)"""
  569. bounds = [(3, 5, 5), (3, 5)]
  570. assert_raises(ValueError, shgo, test1_1.f, bounds)
  571. def test_5_1_1_infeasible_sobol(self):
  572. """Ensures the algorithm terminates on infeasible problems
  573. after maxev is exceeded. Use infty constraints option"""
  574. options = {'maxev': 64,
  575. 'disp': True}
  576. res = shgo(test_infeasible.f, test_infeasible.bounds,
  577. constraints=test_infeasible.cons, n=64, options=options,
  578. sampling_method='sobol')
  579. numpy.testing.assert_equal(False, res.success)
  580. def test_5_1_2_infeasible_sobol(self):
  581. """Ensures the algorithm terminates on infeasible problems
  582. after maxev is exceeded. Do not use infty constraints option"""
  583. options = {'maxev': 64,
  584. 'disp': True,
  585. 'infty_constraints': False}
  586. res = shgo(test_infeasible.f, test_infeasible.bounds,
  587. constraints=test_infeasible.cons, n=64, options=options,
  588. sampling_method='sobol')
  589. numpy.testing.assert_equal(False, res.success)
  590. def test_5_2_infeasible_simplicial(self):
  591. """Ensures the algorithm terminates on infeasible problems
  592. after maxev is exceeded."""
  593. options = {'maxev': 1000,
  594. 'disp': False}
  595. res = shgo(test_infeasible.f, test_infeasible.bounds,
  596. constraints=test_infeasible.cons, n=100, options=options,
  597. sampling_method='simplicial')
  598. numpy.testing.assert_equal(False, res.success)
  599. def test_6_1_lower_known_f_min(self):
  600. """Test Global mode limiting local evalutions with f* too high"""
  601. options = { # Specify known function value
  602. 'f_min': test2_1.expected_fun + 2.0,
  603. 'f_tol': 1e-6,
  604. # Specify number of local iterations to perform+
  605. 'minimize_every_iter': True,
  606. 'local_iter': 1,
  607. 'infty_constraints': False}
  608. args = (test2_1.f, test2_1.bounds)
  609. kwargs = {'constraints': test2_1.cons,
  610. 'n': None,
  611. 'iters': None,
  612. 'options': options,
  613. 'sampling_method': 'sobol'
  614. }
  615. warns(UserWarning, shgo, *args, **kwargs)
  616. @pytest.mark.parametrize('derivative', ['jac', 'hess', 'hessp'])
  617. def test_21_2_derivative_options(self, derivative):
  618. """shgo used to raise an error when passing `options` with 'jac'
  619. # see gh-12829. check that this is resolved
  620. """
  621. def objective(x):
  622. return 3 * x[0] * x[0] + 2 * x[0] + 5
  623. def gradient(x):
  624. return 6 * x[0] + 2
  625. def hess(x):
  626. return 6
  627. def hessp(x, p):
  628. return 6 * p
  629. derivative_funcs = {'jac': gradient, 'hess': hess, 'hessp': hessp}
  630. options = {derivative: derivative_funcs[derivative]}
  631. minimizer_kwargs = {'method': 'trust-constr'}
  632. bounds = [(-100, 100)]
  633. res = shgo(objective, bounds, minimizer_kwargs=minimizer_kwargs,
  634. options=options)
  635. ref = minimize(objective, x0=[0], bounds=bounds, **minimizer_kwargs,
  636. **options)
  637. assert res.success
  638. numpy.testing.assert_allclose(res.fun, ref.fun)
  639. numpy.testing.assert_allclose(res.x, ref.x)