test_cobyla.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import math
  2. import numpy as np
  3. import pytest
  4. from numpy.testing import assert_allclose, assert_, assert_array_equal
  5. from scipy.optimize import fmin_cobyla, minimize
  6. class TestCobyla:
  7. def setup_method(self):
  8. self.x0 = [4.95, 0.66]
  9. self.solution = [math.sqrt(25 - (2.0/3)**2), 2.0/3]
  10. self.opts = {'disp': False, 'rhobeg': 1, 'tol': 1e-5,
  11. 'maxiter': 100}
  12. def fun(self, x):
  13. return x[0]**2 + abs(x[1])**3
  14. def con1(self, x):
  15. return x[0]**2 + x[1]**2 - 25
  16. def con2(self, x):
  17. return -self.con1(x)
  18. def test_simple(self):
  19. # use disp=True as smoke test for gh-8118
  20. x = fmin_cobyla(self.fun, self.x0, [self.con1, self.con2], rhobeg=1,
  21. rhoend=1e-5, maxfun=100, disp=True)
  22. assert_allclose(x, self.solution, atol=1e-4)
  23. def test_minimize_simple(self):
  24. class Callback:
  25. def __init__(self):
  26. self.n_calls = 0
  27. self.last_x = None
  28. def __call__(self, x):
  29. self.n_calls += 1
  30. self.last_x = x
  31. callback = Callback()
  32. # Minimize with method='COBYLA'
  33. cons = ({'type': 'ineq', 'fun': self.con1},
  34. {'type': 'ineq', 'fun': self.con2})
  35. sol = minimize(self.fun, self.x0, method='cobyla', constraints=cons,
  36. callback=callback, options=self.opts)
  37. assert_allclose(sol.x, self.solution, atol=1e-4)
  38. assert_(sol.success, sol.message)
  39. assert_(sol.maxcv < 1e-5, sol)
  40. assert_(sol.nfev < 70, sol)
  41. assert_(sol.fun < self.fun(self.solution) + 1e-3, sol)
  42. assert_(sol.nfev == callback.n_calls,
  43. "Callback is not called exactly once for every function eval.")
  44. assert_array_equal(sol.x, callback.last_x,
  45. "Last design vector sent to the callback is not equal to returned value.")
  46. def test_minimize_constraint_violation(self):
  47. np.random.seed(1234)
  48. pb = np.random.rand(10, 10)
  49. spread = np.random.rand(10)
  50. def p(w):
  51. return pb.dot(w)
  52. def f(w):
  53. return -(w * spread).sum()
  54. def c1(w):
  55. return 500 - abs(p(w)).sum()
  56. def c2(w):
  57. return 5 - abs(p(w).sum())
  58. def c3(w):
  59. return 5 - abs(p(w)).max()
  60. cons = ({'type': 'ineq', 'fun': c1},
  61. {'type': 'ineq', 'fun': c2},
  62. {'type': 'ineq', 'fun': c3})
  63. w0 = np.zeros((10, 1))
  64. message = 'Use of `minimize` with `x0.ndim != 1` is deprecated.'
  65. with pytest.warns(DeprecationWarning, match=message):
  66. sol = minimize(f, w0, method='cobyla', constraints=cons,
  67. options={'catol': 1e-6})
  68. assert_(sol.maxcv > 1e-6)
  69. assert_(not sol.success)
  70. def test_vector_constraints():
  71. # test that fmin_cobyla and minimize can take a combination
  72. # of constraints, some returning a number and others an array
  73. def fun(x):
  74. return (x[0] - 1)**2 + (x[1] - 2.5)**2
  75. def fmin(x):
  76. return fun(x) - 1
  77. def cons1(x):
  78. a = np.array([[1, -2, 2], [-1, -2, 6], [-1, 2, 2]])
  79. return np.array([a[i, 0] * x[0] + a[i, 1] * x[1] +
  80. a[i, 2] for i in range(len(a))])
  81. def cons2(x):
  82. return x # identity, acts as bounds x > 0
  83. x0 = np.array([2, 0])
  84. cons_list = [fun, cons1, cons2]
  85. xsol = [1.4, 1.7]
  86. fsol = 0.8
  87. # testing fmin_cobyla
  88. sol = fmin_cobyla(fun, x0, cons_list, rhoend=1e-5)
  89. assert_allclose(sol, xsol, atol=1e-4)
  90. sol = fmin_cobyla(fun, x0, fmin, rhoend=1e-5)
  91. assert_allclose(fun(sol), 1, atol=1e-4)
  92. # testing minimize
  93. constraints = [{'type': 'ineq', 'fun': cons} for cons in cons_list]
  94. sol = minimize(fun, x0, constraints=constraints, tol=1e-5)
  95. assert_allclose(sol.x, xsol, atol=1e-4)
  96. assert_(sol.success, sol.message)
  97. assert_allclose(sol.fun, fsol, atol=1e-4)
  98. constraints = {'type': 'ineq', 'fun': fmin}
  99. sol = minimize(fun, x0, constraints=constraints, tol=1e-5)
  100. assert_allclose(sol.fun, 1, atol=1e-4)