Coverage for /usr/lib/python3/dist-packages/scipy/optimize/_optimize.py: 6%

1413 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1#__docformat__ = "restructuredtext en" 

2# ******NOTICE*************** 

3# optimize.py module by Travis E. Oliphant 

4# 

5# You may copy and use this module as you see fit with no 

6# guarantee implied provided you keep this notice in all copies. 

7# *****END NOTICE************ 

8 

9# A collection of optimization algorithms. Version 0.5 

10# CHANGES 

11# Added fminbound (July 2001) 

12# Added brute (Aug. 2002) 

13# Finished line search satisfying strong Wolfe conditions (Mar. 2004) 

14# Updated strong Wolfe conditions line search to use 

15# cubic-interpolation (Mar. 2004) 

16 

17 

18# Minimization routines 

19 

20__all__ = ['fmin', 'fmin_powell', 'fmin_bfgs', 'fmin_ncg', 'fmin_cg', 

21 'fminbound', 'brent', 'golden', 'bracket', 'rosen', 'rosen_der', 

22 'rosen_hess', 'rosen_hess_prod', 'brute', 'approx_fprime', 

23 'line_search', 'check_grad', 'OptimizeResult', 'show_options', 

24 'OptimizeWarning'] 

25 

26__docformat__ = "restructuredtext en" 

27 

28import warnings 

29import sys 

30import inspect 

31from numpy import (atleast_1d, eye, argmin, zeros, shape, squeeze, 

32 asarray, sqrt, Inf) 

33import numpy as np 

34from scipy.sparse.linalg import LinearOperator 

35from ._linesearch import (line_search_wolfe1, line_search_wolfe2, 

36 line_search_wolfe2 as line_search, 

37 LineSearchWarning) 

38from ._numdiff import approx_derivative 

39from ._hessian_update_strategy import HessianUpdateStrategy 

40from scipy._lib._util import getfullargspec_no_self as _getfullargspec 

41from scipy._lib._util import MapWrapper, check_random_state 

42from scipy.optimize._differentiable_functions import ScalarFunction, FD_METHODS 

43 

44 

45# standard status messages of optimizers 

46_status_message = {'success': 'Optimization terminated successfully.', 

47 'maxfev': 'Maximum number of function evaluations has ' 

48 'been exceeded.', 

49 'maxiter': 'Maximum number of iterations has been ' 

50 'exceeded.', 

51 'pr_loss': 'Desired error not necessarily achieved due ' 

52 'to precision loss.', 

53 'nan': 'NaN result encountered.', 

54 'out_of_bounds': 'The result is outside of the provided ' 

55 'bounds.'} 

56 

57 

58class MemoizeJac: 

59 """ Decorator that caches the return values of a function returning `(fun, grad)` 

60 each time it is called. """ 

61 

62 def __init__(self, fun): 

63 self.fun = fun 

64 self.jac = None 

65 self._value = None 

66 self.x = None 

67 

68 def _compute_if_needed(self, x, *args): 

69 if not np.all(x == self.x) or self._value is None or self.jac is None: 

70 self.x = np.asarray(x).copy() 

71 fg = self.fun(x, *args) 

72 self.jac = fg[1] 

73 self._value = fg[0] 

74 

75 def __call__(self, x, *args): 

76 """ returns the function value """ 

77 self._compute_if_needed(x, *args) 

78 return self._value 

79 

80 def derivative(self, x, *args): 

81 self._compute_if_needed(x, *args) 

82 return self.jac 

83 

84 

85def _indenter(s, n=0): 

86 """ 

87 Ensures that lines after the first are indented by the specified amount 

88 """ 

89 split = s.split("\n") 

90 indent = " "*n 

91 return ("\n" + indent).join(split) 

92 

93 

94def _float_formatter_10(x): 

95 """ 

96 Returns a string representation of a float with exactly ten characters 

97 """ 

98 if np.isposinf(x): 

99 return " inf" 

100 elif np.isneginf(x): 

101 return " -inf" 

102 elif np.isnan(x): 

103 return " nan" 

104 return np.format_float_scientific(x, precision=3, pad_left=2, unique=False) 

105 

106 

107def _dict_formatter(d, n=0, mplus=1, sorter=None): 

108 """ 

109 Pretty printer for dictionaries 

110 

111 `n` keeps track of the starting indentation; 

112 lines are indented by this much after a line break. 

113 `mplus` is additional left padding applied to keys 

114 """ 

115 if isinstance(d, dict): 

116 m = max(map(len, list(d.keys()))) + mplus # width to print keys 

117 s = '\n'.join([k.rjust(m) + ': ' + # right justified, width m 

118 _indenter(_dict_formatter(v, m+n+2, 0, sorter), m+2) 

119 for k, v in sorter(d)]) # +2 for ': ' 

120 else: 

121 # By default, NumPy arrays print with linewidth=76. `n` is 

122 # the indent at which a line begins printing, so it is subtracted 

123 # from the default to avoid exceeding 76 characters total. 

124 # `edgeitems` is the number of elements to include before and after 

125 # ellipses when arrays are not shown in full. 

126 # `threshold` is the maximum number of elements for which an 

127 # array is shown in full. 

128 # These values tend to work well for use with OptimizeResult. 

129 with np.printoptions(linewidth=76-n, edgeitems=2, threshold=12, 

130 formatter={'float_kind': _float_formatter_10}): 

131 s = str(d) 

132 return s 

133 

134 

135def _wrap_callback(callback, method=None): 

136 """Wrap a user-provided callback so that attributes can be attached.""" 

137 if callback is None or method in {'tnc', 'slsqp', 'cobyla'}: 

138 return callback # don't wrap 

139 

140 sig = inspect.signature(callback) 

141 

142 if set(sig.parameters) == {'intermediate_result'}: 

143 def wrapped_callback(res): 

144 return callback(intermediate_result=res) 

145 elif method == 'trust-constr': 

146 def wrapped_callback(res): 

147 return callback(np.copy(res.x), res) 

148 else: 

149 def wrapped_callback(res): 

150 return callback(np.copy(res.x)) 

151 

152 wrapped_callback.stop_iteration = False 

153 return wrapped_callback 

154 

155 

156def _call_callback_maybe_halt(callback, res): 

157 """Call wrapped callback; return True if minimization should stop. 

158 

159 Parameters 

160 ---------- 

161 callback : callable or None 

162 A user-provided callback wrapped with `_wrap_callback` 

163 res : OptimizeResult 

164 Information about the current iterate 

165 

166 Returns 

167 ------- 

168 halt : bool 

169 True if minimization should stop 

170 

171 """ 

172 if callback is None: 

173 return False 

174 try: 

175 callback(res) 

176 return False 

177 except StopIteration: 

178 callback.stop_iteration = True # make `minimize` override status/msg 

179 return True 

180 

181 

182class OptimizeResult(dict): 

183 """ Represents the optimization result. 

184 

185 Attributes 

186 ---------- 

187 x : ndarray 

188 The solution of the optimization. 

189 success : bool 

190 Whether or not the optimizer exited successfully. 

191 status : int 

192 Termination status of the optimizer. Its value depends on the 

193 underlying solver. Refer to `message` for details. 

194 message : str 

195 Description of the cause of the termination. 

196 fun, jac, hess: ndarray 

197 Values of objective function, its Jacobian and its Hessian (if 

198 available). The Hessians may be approximations, see the documentation 

199 of the function in question. 

200 hess_inv : object 

201 Inverse of the objective function's Hessian; may be an approximation. 

202 Not available for all solvers. The type of this attribute may be 

203 either np.ndarray or scipy.sparse.linalg.LinearOperator. 

204 nfev, njev, nhev : int 

205 Number of evaluations of the objective functions and of its 

206 Jacobian and Hessian. 

207 nit : int 

208 Number of iterations performed by the optimizer. 

209 maxcv : float 

210 The maximum constraint violation. 

211 

212 Notes 

213 ----- 

214 Depending on the specific solver being used, `OptimizeResult` may 

215 not have all attributes listed here, and they may have additional 

216 attributes not listed here. Since this class is essentially a 

217 subclass of dict with attribute accessors, one can see which 

218 attributes are available using the `OptimizeResult.keys` method. 

219 """ 

220 

221 def __getattr__(self, name): 

222 try: 

223 return self[name] 

224 except KeyError as e: 

225 raise AttributeError(name) from e 

226 

227 __setattr__ = dict.__setitem__ 

228 __delattr__ = dict.__delitem__ 

229 

230 def __repr__(self): 

231 order_keys = ['message', 'success', 'status', 'fun', 'funl', 'x', 'xl', 

232 'col_ind', 'nit', 'lower', 'upper', 'eqlin', 'ineqlin', 

233 'converged', 'flag', 'function_calls', 'iterations', 

234 'root'] 

235 # 'slack', 'con' are redundant with residuals 

236 # 'crossover_nit' is probably not interesting to most users 

237 omit_keys = {'slack', 'con', 'crossover_nit'} 

238 

239 def key(item): 

240 try: 

241 return order_keys.index(item[0].lower()) 

242 except ValueError: # item not in list 

243 return np.inf 

244 

245 def omit_redundant(items): 

246 for item in items: 

247 if item[0] in omit_keys: 

248 continue 

249 yield item 

250 

251 def item_sorter(d): 

252 return sorted(omit_redundant(d.items()), key=key) 

253 

254 if self.keys(): 

255 return _dict_formatter(self, sorter=item_sorter) 

256 else: 

257 return self.__class__.__name__ + "()" 

258 

259 def __dir__(self): 

260 return list(self.keys()) 

261 

262 

263class OptimizeWarning(UserWarning): 

264 pass 

265 

266 

267def _check_unknown_options(unknown_options): 

268 if unknown_options: 

269 msg = ", ".join(map(str, unknown_options.keys())) 

270 # Stack level 4: this is called from _minimize_*, which is 

271 # called from another function in SciPy. Level 4 is the first 

272 # level in user code. 

273 warnings.warn("Unknown solver options: %s" % msg, OptimizeWarning, 4) 

274 

275 

276def is_finite_scalar(x): 

277 """Test whether `x` is either a finite scalar or a finite array scalar. 

278 

279 """ 

280 return np.size(x) == 1 and np.isfinite(x) 

281 

282 

283_epsilon = sqrt(np.finfo(float).eps) 

284 

285 

286def vecnorm(x, ord=2): 

287 if ord == Inf: 

288 return np.amax(np.abs(x)) 

289 elif ord == -Inf: 

290 return np.amin(np.abs(x)) 

291 else: 

292 return np.sum(np.abs(x)**ord, axis=0)**(1.0 / ord) 

293 

294 

295def _prepare_scalar_function(fun, x0, jac=None, args=(), bounds=None, 

296 epsilon=None, finite_diff_rel_step=None, 

297 hess=None): 

298 """ 

299 Creates a ScalarFunction object for use with scalar minimizers 

300 (BFGS/LBFGSB/SLSQP/TNC/CG/etc). 

301 

302 Parameters 

303 ---------- 

304 fun : callable 

305 The objective function to be minimized. 

306 

307 ``fun(x, *args) -> float`` 

308 

309 where ``x`` is an 1-D array with shape (n,) and ``args`` 

310 is a tuple of the fixed parameters needed to completely 

311 specify the function. 

312 x0 : ndarray, shape (n,) 

313 Initial guess. Array of real elements of size (n,), 

314 where 'n' is the number of independent variables. 

315 jac : {callable, '2-point', '3-point', 'cs', None}, optional 

316 Method for computing the gradient vector. If it is a callable, it 

317 should be a function that returns the gradient vector: 

318 

319 ``jac(x, *args) -> array_like, shape (n,)`` 

320 

321 If one of `{'2-point', '3-point', 'cs'}` is selected then the gradient 

322 is calculated with a relative step for finite differences. If `None`, 

323 then two-point finite differences with an absolute step is used. 

324 args : tuple, optional 

325 Extra arguments passed to the objective function and its 

326 derivatives (`fun`, `jac` functions). 

327 bounds : sequence, optional 

328 Bounds on variables. 'new-style' bounds are required. 

329 eps : float or ndarray 

330 If `jac is None` the absolute step size used for numerical 

331 approximation of the jacobian via forward differences. 

332 finite_diff_rel_step : None or array_like, optional 

333 If `jac in ['2-point', '3-point', 'cs']` the relative step size to 

334 use for numerical approximation of the jacobian. The absolute step 

335 size is computed as ``h = rel_step * sign(x0) * max(1, abs(x0))``, 

336 possibly adjusted to fit into the bounds. For ``method='3-point'`` 

337 the sign of `h` is ignored. If None (default) then step is selected 

338 automatically. 

339 hess : {callable, '2-point', '3-point', 'cs', None} 

340 Computes the Hessian matrix. If it is callable, it should return the 

341 Hessian matrix: 

342 

343 ``hess(x, *args) -> {LinearOperator, spmatrix, array}, (n, n)`` 

344 

345 Alternatively, the keywords {'2-point', '3-point', 'cs'} select a 

346 finite difference scheme for numerical estimation. 

347 Whenever the gradient is estimated via finite-differences, the Hessian 

348 cannot be estimated with options {'2-point', '3-point', 'cs'} and needs 

349 to be estimated using one of the quasi-Newton strategies. 

350 

351 Returns 

352 ------- 

353 sf : ScalarFunction 

354 """ 

355 if callable(jac): 

356 grad = jac 

357 elif jac in FD_METHODS: 

358 # epsilon is set to None so that ScalarFunction is made to use 

359 # rel_step 

360 epsilon = None 

361 grad = jac 

362 else: 

363 # default (jac is None) is to do 2-point finite differences with 

364 # absolute step size. ScalarFunction has to be provided an 

365 # epsilon value that is not None to use absolute steps. This is 

366 # normally the case from most _minimize* methods. 

367 grad = '2-point' 

368 epsilon = epsilon 

369 

370 if hess is None: 

371 # ScalarFunction requires something for hess, so we give a dummy 

372 # implementation here if nothing is provided, return a value of None 

373 # so that downstream minimisers halt. The results of `fun.hess` 

374 # should not be used. 

375 def hess(x, *args): 

376 return None 

377 

378 if bounds is None: 

379 bounds = (-np.inf, np.inf) 

380 

381 # ScalarFunction caches. Reuse of fun(x) during grad 

382 # calculation reduces overall function evaluations. 

383 sf = ScalarFunction(fun, x0, args, grad, hess, 

384 finite_diff_rel_step, bounds, epsilon=epsilon) 

385 

386 return sf 

387 

388 

389def _clip_x_for_func(func, bounds): 

390 # ensures that x values sent to func are clipped to bounds 

391 

392 # this is used as a mitigation for gh11403, slsqp/tnc sometimes 

393 # suggest a move that is outside the limits by 1 or 2 ULP. This 

394 # unclean fix makes sure x is strictly within bounds. 

395 def eval(x): 

396 x = _check_clip_x(x, bounds) 

397 return func(x) 

398 

399 return eval 

400 

401 

402def _check_clip_x(x, bounds): 

403 if (x < bounds[0]).any() or (x > bounds[1]).any(): 

404 warnings.warn("Values in x were outside bounds during a " 

405 "minimize step, clipping to bounds", RuntimeWarning) 

406 x = np.clip(x, bounds[0], bounds[1]) 

407 return x 

408 

409 return x 

410 

411 

412def rosen(x): 

413 """ 

414 The Rosenbrock function. 

415 

416 The function computed is:: 

417 

418 sum(100.0*(x[1:] - x[:-1]**2.0)**2.0 + (1 - x[:-1])**2.0) 

419 

420 Parameters 

421 ---------- 

422 x : array_like 

423 1-D array of points at which the Rosenbrock function is to be computed. 

424 

425 Returns 

426 ------- 

427 f : float 

428 The value of the Rosenbrock function. 

429 

430 See Also 

431 -------- 

432 rosen_der, rosen_hess, rosen_hess_prod 

433 

434 Examples 

435 -------- 

436 >>> import numpy as np 

437 >>> from scipy.optimize import rosen 

438 >>> X = 0.1 * np.arange(10) 

439 >>> rosen(X) 

440 76.56 

441 

442 For higher-dimensional input ``rosen`` broadcasts. 

443 In the following example, we use this to plot a 2D landscape. 

444 Note that ``rosen_hess`` does not broadcast in this manner. 

445 

446 >>> import matplotlib.pyplot as plt 

447 >>> from mpl_toolkits.mplot3d import Axes3D 

448 >>> x = np.linspace(-1, 1, 50) 

449 >>> X, Y = np.meshgrid(x, x) 

450 >>> ax = plt.subplot(111, projection='3d') 

451 >>> ax.plot_surface(X, Y, rosen([X, Y])) 

452 >>> plt.show() 

453 """ 

454 x = asarray(x) 

455 r = np.sum(100.0 * (x[1:] - x[:-1]**2.0)**2.0 + (1 - x[:-1])**2.0, 

456 axis=0) 

457 return r 

458 

459 

460def rosen_der(x): 

461 """ 

462 The derivative (i.e. gradient) of the Rosenbrock function. 

463 

464 Parameters 

465 ---------- 

466 x : array_like 

467 1-D array of points at which the derivative is to be computed. 

468 

469 Returns 

470 ------- 

471 rosen_der : (N,) ndarray 

472 The gradient of the Rosenbrock function at `x`. 

473 

474 See Also 

475 -------- 

476 rosen, rosen_hess, rosen_hess_prod 

477 

478 Examples 

479 -------- 

480 >>> import numpy as np 

481 >>> from scipy.optimize import rosen_der 

482 >>> X = 0.1 * np.arange(9) 

483 >>> rosen_der(X) 

484 array([ -2. , 10.6, 15.6, 13.4, 6.4, -3. , -12.4, -19.4, 62. ]) 

485 

486 """ 

487 x = asarray(x) 

488 xm = x[1:-1] 

489 xm_m1 = x[:-2] 

490 xm_p1 = x[2:] 

491 der = np.zeros_like(x) 

492 der[1:-1] = (200 * (xm - xm_m1**2) - 

493 400 * (xm_p1 - xm**2) * xm - 2 * (1 - xm)) 

494 der[0] = -400 * x[0] * (x[1] - x[0]**2) - 2 * (1 - x[0]) 

495 der[-1] = 200 * (x[-1] - x[-2]**2) 

496 return der 

497 

498 

499def rosen_hess(x): 

500 """ 

501 The Hessian matrix of the Rosenbrock function. 

502 

503 Parameters 

504 ---------- 

505 x : array_like 

506 1-D array of points at which the Hessian matrix is to be computed. 

507 

508 Returns 

509 ------- 

510 rosen_hess : ndarray 

511 The Hessian matrix of the Rosenbrock function at `x`. 

512 

513 See Also 

514 -------- 

515 rosen, rosen_der, rosen_hess_prod 

516 

517 Examples 

518 -------- 

519 >>> import numpy as np 

520 >>> from scipy.optimize import rosen_hess 

521 >>> X = 0.1 * np.arange(4) 

522 >>> rosen_hess(X) 

523 array([[-38., 0., 0., 0.], 

524 [ 0., 134., -40., 0.], 

525 [ 0., -40., 130., -80.], 

526 [ 0., 0., -80., 200.]]) 

527 

528 """ 

529 x = atleast_1d(x) 

530 H = np.diag(-400 * x[:-1], 1) - np.diag(400 * x[:-1], -1) 

531 diagonal = np.zeros(len(x), dtype=x.dtype) 

532 diagonal[0] = 1200 * x[0]**2 - 400 * x[1] + 2 

533 diagonal[-1] = 200 

534 diagonal[1:-1] = 202 + 1200 * x[1:-1]**2 - 400 * x[2:] 

535 H = H + np.diag(diagonal) 

536 return H 

537 

538 

539def rosen_hess_prod(x, p): 

540 """ 

541 Product of the Hessian matrix of the Rosenbrock function with a vector. 

542 

543 Parameters 

544 ---------- 

545 x : array_like 

546 1-D array of points at which the Hessian matrix is to be computed. 

547 p : array_like 

548 1-D array, the vector to be multiplied by the Hessian matrix. 

549 

550 Returns 

551 ------- 

552 rosen_hess_prod : ndarray 

553 The Hessian matrix of the Rosenbrock function at `x` multiplied 

554 by the vector `p`. 

555 

556 See Also 

557 -------- 

558 rosen, rosen_der, rosen_hess 

559 

560 Examples 

561 -------- 

562 >>> import numpy as np 

563 >>> from scipy.optimize import rosen_hess_prod 

564 >>> X = 0.1 * np.arange(9) 

565 >>> p = 0.5 * np.arange(9) 

566 >>> rosen_hess_prod(X, p) 

567 array([ -0., 27., -10., -95., -192., -265., -278., -195., -180.]) 

568 

569 """ 

570 x = atleast_1d(x) 

571 Hp = np.zeros(len(x), dtype=x.dtype) 

572 Hp[0] = (1200 * x[0]**2 - 400 * x[1] + 2) * p[0] - 400 * x[0] * p[1] 

573 Hp[1:-1] = (-400 * x[:-2] * p[:-2] + 

574 (202 + 1200 * x[1:-1]**2 - 400 * x[2:]) * p[1:-1] - 

575 400 * x[1:-1] * p[2:]) 

576 Hp[-1] = -400 * x[-2] * p[-2] + 200*p[-1] 

577 return Hp 

578 

579 

580def _wrap_scalar_function(function, args): 

581 # wraps a minimizer function to count number of evaluations 

582 # and to easily provide an args kwd. 

583 ncalls = [0] 

584 if function is None: 

585 return ncalls, None 

586 

587 def function_wrapper(x, *wrapper_args): 

588 ncalls[0] += 1 

589 # A copy of x is sent to the user function (gh13740) 

590 fx = function(np.copy(x), *(wrapper_args + args)) 

591 # Ideally, we'd like to a have a true scalar returned from f(x). For 

592 # backwards-compatibility, also allow np.array([1.3]), np.array([[1.3]]) etc. 

593 if not np.isscalar(fx): 

594 try: 

595 fx = np.asarray(fx).item() 

596 except (TypeError, ValueError) as e: 

597 raise ValueError("The user-provided objective function " 

598 "must return a scalar value.") from e 

599 return fx 

600 

601 return ncalls, function_wrapper 

602 

603 

604class _MaxFuncCallError(RuntimeError): 

605 pass 

606 

607 

608def _wrap_scalar_function_maxfun_validation(function, args, maxfun): 

609 # wraps a minimizer function to count number of evaluations 

610 # and to easily provide an args kwd. 

611 ncalls = [0] 

612 if function is None: 

613 return ncalls, None 

614 

615 def function_wrapper(x, *wrapper_args): 

616 if ncalls[0] >= maxfun: 

617 raise _MaxFuncCallError("Too many function calls") 

618 ncalls[0] += 1 

619 # A copy of x is sent to the user function (gh13740) 

620 fx = function(np.copy(x), *(wrapper_args + args)) 

621 # Ideally, we'd like to a have a true scalar returned from f(x). For 

622 # backwards-compatibility, also allow np.array([1.3]), 

623 # np.array([[1.3]]) etc. 

624 if not np.isscalar(fx): 

625 try: 

626 fx = np.asarray(fx).item() 

627 except (TypeError, ValueError) as e: 

628 raise ValueError("The user-provided objective function " 

629 "must return a scalar value.") from e 

630 return fx 

631 

632 return ncalls, function_wrapper 

633 

634 

635def fmin(func, x0, args=(), xtol=1e-4, ftol=1e-4, maxiter=None, maxfun=None, 

636 full_output=0, disp=1, retall=0, callback=None, initial_simplex=None): 

637 """ 

638 Minimize a function using the downhill simplex algorithm. 

639 

640 This algorithm only uses function values, not derivatives or second 

641 derivatives. 

642 

643 Parameters 

644 ---------- 

645 func : callable func(x,*args) 

646 The objective function to be minimized. 

647 x0 : ndarray 

648 Initial guess. 

649 args : tuple, optional 

650 Extra arguments passed to func, i.e., ``f(x,*args)``. 

651 xtol : float, optional 

652 Absolute error in xopt between iterations that is acceptable for 

653 convergence. 

654 ftol : number, optional 

655 Absolute error in func(xopt) between iterations that is acceptable for 

656 convergence. 

657 maxiter : int, optional 

658 Maximum number of iterations to perform. 

659 maxfun : number, optional 

660 Maximum number of function evaluations to make. 

661 full_output : bool, optional 

662 Set to True if fopt and warnflag outputs are desired. 

663 disp : bool, optional 

664 Set to True to print convergence messages. 

665 retall : bool, optional 

666 Set to True to return list of solutions at each iteration. 

667 callback : callable, optional 

668 Called after each iteration, as callback(xk), where xk is the 

669 current parameter vector. 

670 initial_simplex : array_like of shape (N + 1, N), optional 

671 Initial simplex. If given, overrides `x0`. 

672 ``initial_simplex[j,:]`` should contain the coordinates of 

673 the jth vertex of the ``N+1`` vertices in the simplex, where 

674 ``N`` is the dimension. 

675 

676 Returns 

677 ------- 

678 xopt : ndarray 

679 Parameter that minimizes function. 

680 fopt : float 

681 Value of function at minimum: ``fopt = func(xopt)``. 

682 iter : int 

683 Number of iterations performed. 

684 funcalls : int 

685 Number of function calls made. 

686 warnflag : int 

687 1 : Maximum number of function evaluations made. 

688 2 : Maximum number of iterations reached. 

689 allvecs : list 

690 Solution at each iteration. 

691 

692 See also 

693 -------- 

694 minimize: Interface to minimization algorithms for multivariate 

695 functions. See the 'Nelder-Mead' `method` in particular. 

696 

697 Notes 

698 ----- 

699 Uses a Nelder-Mead simplex algorithm to find the minimum of function of 

700 one or more variables. 

701 

702 This algorithm has a long history of successful use in applications. 

703 But it will usually be slower than an algorithm that uses first or 

704 second derivative information. In practice, it can have poor 

705 performance in high-dimensional problems and is not robust to 

706 minimizing complicated functions. Additionally, there currently is no 

707 complete theory describing when the algorithm will successfully 

708 converge to the minimum, or how fast it will if it does. Both the ftol and 

709 xtol criteria must be met for convergence. 

710 

711 Examples 

712 -------- 

713 >>> def f(x): 

714 ... return x**2 

715 

716 >>> from scipy import optimize 

717 

718 >>> minimum = optimize.fmin(f, 1) 

719 Optimization terminated successfully. 

720 Current function value: 0.000000 

721 Iterations: 17 

722 Function evaluations: 34 

723 >>> minimum[0] 

724 -8.8817841970012523e-16 

725 

726 References 

727 ---------- 

728 .. [1] Nelder, J.A. and Mead, R. (1965), "A simplex method for function 

729 minimization", The Computer Journal, 7, pp. 308-313 

730 

731 .. [2] Wright, M.H. (1996), "Direct Search Methods: Once Scorned, Now 

732 Respectable", in Numerical Analysis 1995, Proceedings of the 

733 1995 Dundee Biennial Conference in Numerical Analysis, D.F. 

734 Griffiths and G.A. Watson (Eds.), Addison Wesley Longman, 

735 Harlow, UK, pp. 191-208. 

736 

737 """ 

738 opts = {'xatol': xtol, 

739 'fatol': ftol, 

740 'maxiter': maxiter, 

741 'maxfev': maxfun, 

742 'disp': disp, 

743 'return_all': retall, 

744 'initial_simplex': initial_simplex} 

745 

746 callback = _wrap_callback(callback) 

747 res = _minimize_neldermead(func, x0, args, callback=callback, **opts) 

748 if full_output: 

749 retlist = res['x'], res['fun'], res['nit'], res['nfev'], res['status'] 

750 if retall: 

751 retlist += (res['allvecs'], ) 

752 return retlist 

753 else: 

754 if retall: 

755 return res['x'], res['allvecs'] 

756 else: 

757 return res['x'] 

758 

759 

760def _minimize_neldermead(func, x0, args=(), callback=None, 

761 maxiter=None, maxfev=None, disp=False, 

762 return_all=False, initial_simplex=None, 

763 xatol=1e-4, fatol=1e-4, adaptive=False, bounds=None, 

764 **unknown_options): 

765 """ 

766 Minimization of scalar function of one or more variables using the 

767 Nelder-Mead algorithm. 

768 

769 Options 

770 ------- 

771 disp : bool 

772 Set to True to print convergence messages. 

773 maxiter, maxfev : int 

774 Maximum allowed number of iterations and function evaluations. 

775 Will default to ``N*200``, where ``N`` is the number of 

776 variables, if neither `maxiter` or `maxfev` is set. If both 

777 `maxiter` and `maxfev` are set, minimization will stop at the 

778 first reached. 

779 return_all : bool, optional 

780 Set to True to return a list of the best solution at each of the 

781 iterations. 

782 initial_simplex : array_like of shape (N + 1, N) 

783 Initial simplex. If given, overrides `x0`. 

784 ``initial_simplex[j,:]`` should contain the coordinates of 

785 the jth vertex of the ``N+1`` vertices in the simplex, where 

786 ``N`` is the dimension. 

787 xatol : float, optional 

788 Absolute error in xopt between iterations that is acceptable for 

789 convergence. 

790 fatol : number, optional 

791 Absolute error in func(xopt) between iterations that is acceptable for 

792 convergence. 

793 adaptive : bool, optional 

794 Adapt algorithm parameters to dimensionality of problem. Useful for 

795 high-dimensional minimization [1]_. 

796 bounds : sequence or `Bounds`, optional 

797 Bounds on variables. There are two ways to specify the bounds: 

798 

799 1. Instance of `Bounds` class. 

800 2. Sequence of ``(min, max)`` pairs for each element in `x`. None 

801 is used to specify no bound. 

802 

803 Note that this just clips all vertices in simplex based on 

804 the bounds. 

805 

806 References 

807 ---------- 

808 .. [1] Gao, F. and Han, L. 

809 Implementing the Nelder-Mead simplex algorithm with adaptive 

810 parameters. 2012. Computational Optimization and Applications. 

811 51:1, pp. 259-277 

812 

813 """ 

814 _check_unknown_options(unknown_options) 

815 maxfun = maxfev 

816 retall = return_all 

817 

818 x0 = np.atleast_1d(x0).flatten() 

819 x0 = np.asfarray(x0, x0.dtype) 

820 

821 if adaptive: 

822 dim = float(len(x0)) 

823 rho = 1 

824 chi = 1 + 2/dim 

825 psi = 0.75 - 1/(2*dim) 

826 sigma = 1 - 1/dim 

827 else: 

828 rho = 1 

829 chi = 2 

830 psi = 0.5 

831 sigma = 0.5 

832 

833 nonzdelt = 0.05 

834 zdelt = 0.00025 

835 

836 if bounds is not None: 

837 lower_bound, upper_bound = bounds.lb, bounds.ub 

838 # check bounds 

839 if (lower_bound > upper_bound).any(): 

840 raise ValueError("Nelder Mead - one of the lower bounds is greater than an upper bound.") 

841 if np.any(lower_bound > x0) or np.any(x0 > upper_bound): 

842 warnings.warn("Initial guess is not within the specified bounds", 

843 OptimizeWarning, 3) 

844 

845 if bounds is not None: 

846 x0 = np.clip(x0, lower_bound, upper_bound) 

847 

848 if initial_simplex is None: 

849 N = len(x0) 

850 

851 sim = np.empty((N + 1, N), dtype=x0.dtype) 

852 sim[0] = x0 

853 for k in range(N): 

854 y = np.array(x0, copy=True) 

855 if y[k] != 0: 

856 y[k] = (1 + nonzdelt)*y[k] 

857 else: 

858 y[k] = zdelt 

859 sim[k + 1] = y 

860 else: 

861 sim = np.atleast_2d(initial_simplex).copy() 

862 sim = np.asfarray(sim, sim.dtype) 

863 if sim.ndim != 2 or sim.shape[0] != sim.shape[1] + 1: 

864 raise ValueError("`initial_simplex` should be an array of shape (N+1,N)") 

865 if len(x0) != sim.shape[1]: 

866 raise ValueError("Size of `initial_simplex` is not consistent with `x0`") 

867 N = sim.shape[1] 

868 

869 if retall: 

870 allvecs = [sim[0]] 

871 

872 # If neither are set, then set both to default 

873 if maxiter is None and maxfun is None: 

874 maxiter = N * 200 

875 maxfun = N * 200 

876 elif maxiter is None: 

877 # Convert remaining Nones, to np.inf, unless the other is np.inf, in 

878 # which case use the default to avoid unbounded iteration 

879 if maxfun == np.inf: 

880 maxiter = N * 200 

881 else: 

882 maxiter = np.inf 

883 elif maxfun is None: 

884 if maxiter == np.inf: 

885 maxfun = N * 200 

886 else: 

887 maxfun = np.inf 

888 

889 if bounds is not None: 

890 sim = np.clip(sim, lower_bound, upper_bound) 

891 

892 one2np1 = list(range(1, N + 1)) 

893 fsim = np.full((N + 1,), np.inf, dtype=float) 

894 

895 fcalls, func = _wrap_scalar_function_maxfun_validation(func, args, maxfun) 

896 

897 try: 

898 for k in range(N + 1): 

899 fsim[k] = func(sim[k]) 

900 except _MaxFuncCallError: 

901 pass 

902 finally: 

903 ind = np.argsort(fsim) 

904 sim = np.take(sim, ind, 0) 

905 fsim = np.take(fsim, ind, 0) 

906 

907 ind = np.argsort(fsim) 

908 fsim = np.take(fsim, ind, 0) 

909 # sort so sim[0,:] has the lowest function value 

910 sim = np.take(sim, ind, 0) 

911 

912 iterations = 1 

913 

914 while (fcalls[0] < maxfun and iterations < maxiter): 

915 try: 

916 if (np.max(np.ravel(np.abs(sim[1:] - sim[0]))) <= xatol and 

917 np.max(np.abs(fsim[0] - fsim[1:])) <= fatol): 

918 break 

919 

920 xbar = np.add.reduce(sim[:-1], 0) / N 

921 xr = (1 + rho) * xbar - rho * sim[-1] 

922 if bounds is not None: 

923 xr = np.clip(xr, lower_bound, upper_bound) 

924 fxr = func(xr) 

925 doshrink = 0 

926 

927 if fxr < fsim[0]: 

928 xe = (1 + rho * chi) * xbar - rho * chi * sim[-1] 

929 if bounds is not None: 

930 xe = np.clip(xe, lower_bound, upper_bound) 

931 fxe = func(xe) 

932 

933 if fxe < fxr: 

934 sim[-1] = xe 

935 fsim[-1] = fxe 

936 else: 

937 sim[-1] = xr 

938 fsim[-1] = fxr 

939 else: # fsim[0] <= fxr 

940 if fxr < fsim[-2]: 

941 sim[-1] = xr 

942 fsim[-1] = fxr 

943 else: # fxr >= fsim[-2] 

944 # Perform contraction 

945 if fxr < fsim[-1]: 

946 xc = (1 + psi * rho) * xbar - psi * rho * sim[-1] 

947 if bounds is not None: 

948 xc = np.clip(xc, lower_bound, upper_bound) 

949 fxc = func(xc) 

950 

951 if fxc <= fxr: 

952 sim[-1] = xc 

953 fsim[-1] = fxc 

954 else: 

955 doshrink = 1 

956 else: 

957 # Perform an inside contraction 

958 xcc = (1 - psi) * xbar + psi * sim[-1] 

959 if bounds is not None: 

960 xcc = np.clip(xcc, lower_bound, upper_bound) 

961 fxcc = func(xcc) 

962 

963 if fxcc < fsim[-1]: 

964 sim[-1] = xcc 

965 fsim[-1] = fxcc 

966 else: 

967 doshrink = 1 

968 

969 if doshrink: 

970 for j in one2np1: 

971 sim[j] = sim[0] + sigma * (sim[j] - sim[0]) 

972 if bounds is not None: 

973 sim[j] = np.clip( 

974 sim[j], lower_bound, upper_bound) 

975 fsim[j] = func(sim[j]) 

976 iterations += 1 

977 except _MaxFuncCallError: 

978 pass 

979 finally: 

980 ind = np.argsort(fsim) 

981 sim = np.take(sim, ind, 0) 

982 fsim = np.take(fsim, ind, 0) 

983 if retall: 

984 allvecs.append(sim[0]) 

985 intermediate_result = OptimizeResult(x=sim[0], fun=fsim[0]) 

986 if _call_callback_maybe_halt(callback, intermediate_result): 

987 break 

988 

989 x = sim[0] 

990 fval = np.min(fsim) 

991 warnflag = 0 

992 

993 if fcalls[0] >= maxfun: 

994 warnflag = 1 

995 msg = _status_message['maxfev'] 

996 if disp: 

997 warnings.warn(msg, RuntimeWarning, 3) 

998 elif iterations >= maxiter: 

999 warnflag = 2 

1000 msg = _status_message['maxiter'] 

1001 if disp: 

1002 warnings.warn(msg, RuntimeWarning, 3) 

1003 else: 

1004 msg = _status_message['success'] 

1005 if disp: 

1006 print(msg) 

1007 print(" Current function value: %f" % fval) 

1008 print(" Iterations: %d" % iterations) 

1009 print(" Function evaluations: %d" % fcalls[0]) 

1010 

1011 result = OptimizeResult(fun=fval, nit=iterations, nfev=fcalls[0], 

1012 status=warnflag, success=(warnflag == 0), 

1013 message=msg, x=x, final_simplex=(sim, fsim)) 

1014 if retall: 

1015 result['allvecs'] = allvecs 

1016 return result 

1017 

1018 

1019def approx_fprime(xk, f, epsilon=_epsilon, *args): 

1020 """Finite difference approximation of the derivatives of a 

1021 scalar or vector-valued function. 

1022 

1023 If a function maps from :math:`R^n` to :math:`R^m`, its derivatives form 

1024 an m-by-n matrix 

1025 called the Jacobian, where an element :math:`(i, j)` is a partial 

1026 derivative of f[i] with respect to ``xk[j]``. 

1027 

1028 Parameters 

1029 ---------- 

1030 xk : array_like 

1031 The coordinate vector at which to determine the gradient of `f`. 

1032 f : callable 

1033 Function of which to estimate the derivatives of. Has the signature 

1034 ``f(xk, *args)`` where `xk` is the argument in the form of a 1-D array 

1035 and `args` is a tuple of any additional fixed parameters needed to 

1036 completely specify the function. The argument `xk` passed to this 

1037 function is an ndarray of shape (n,) (never a scalar even if n=1). 

1038 It must return a 1-D array_like of shape (m,) or a scalar. 

1039 

1040 .. versionchanged:: 1.9.0 

1041 `f` is now able to return a 1-D array-like, with the :math:`(m, n)` 

1042 Jacobian being estimated. 

1043 

1044 epsilon : {float, array_like}, optional 

1045 Increment to `xk` to use for determining the function gradient. 

1046 If a scalar, uses the same finite difference delta for all partial 

1047 derivatives. If an array, should contain one value per element of 

1048 `xk`. Defaults to ``sqrt(np.finfo(float).eps)``, which is approximately 

1049 1.49e-08. 

1050 \\*args : args, optional 

1051 Any other arguments that are to be passed to `f`. 

1052 

1053 Returns 

1054 ------- 

1055 jac : ndarray 

1056 The partial derivatives of `f` to `xk`. 

1057 

1058 See Also 

1059 -------- 

1060 check_grad : Check correctness of gradient function against approx_fprime. 

1061 

1062 Notes 

1063 ----- 

1064 The function gradient is determined by the forward finite difference 

1065 formula:: 

1066 

1067 f(xk[i] + epsilon[i]) - f(xk[i]) 

1068 f'[i] = --------------------------------- 

1069 epsilon[i] 

1070 

1071 Examples 

1072 -------- 

1073 >>> import numpy as np 

1074 >>> from scipy import optimize 

1075 >>> def func(x, c0, c1): 

1076 ... "Coordinate vector `x` should be an array of size two." 

1077 ... return c0 * x[0]**2 + c1*x[1]**2 

1078 

1079 >>> x = np.ones(2) 

1080 >>> c0, c1 = (1, 200) 

1081 >>> eps = np.sqrt(np.finfo(float).eps) 

1082 >>> optimize.approx_fprime(x, func, [eps, np.sqrt(200) * eps], c0, c1) 

1083 array([ 2. , 400.00004198]) 

1084 

1085 """ 

1086 xk = np.asarray(xk, float) 

1087 f0 = f(xk, *args) 

1088 

1089 return approx_derivative(f, xk, method='2-point', abs_step=epsilon, 

1090 args=args, f0=f0) 

1091 

1092 

1093def check_grad(func, grad, x0, *args, epsilon=_epsilon, 

1094 direction='all', seed=None): 

1095 """Check the correctness of a gradient function by comparing it against a 

1096 (forward) finite-difference approximation of the gradient. 

1097 

1098 Parameters 

1099 ---------- 

1100 func : callable ``func(x0, *args)`` 

1101 Function whose derivative is to be checked. 

1102 grad : callable ``grad(x0, *args)`` 

1103 Jacobian of `func`. 

1104 x0 : ndarray 

1105 Points to check `grad` against forward difference approximation of grad 

1106 using `func`. 

1107 args : \\*args, optional 

1108 Extra arguments passed to `func` and `grad`. 

1109 epsilon : float, optional 

1110 Step size used for the finite difference approximation. It defaults to 

1111 ``sqrt(np.finfo(float).eps)``, which is approximately 1.49e-08. 

1112 direction : str, optional 

1113 If set to ``'random'``, then gradients along a random vector 

1114 are used to check `grad` against forward difference approximation 

1115 using `func`. By default it is ``'all'``, in which case, all 

1116 the one hot direction vectors are considered to check `grad`. 

1117 If `func` is a vector valued function then only ``'all'`` can be used. 

1118 seed : {None, int, `numpy.random.Generator`, `numpy.random.RandomState`}, optional 

1119 If `seed` is None (or `np.random`), the `numpy.random.RandomState` 

1120 singleton is used. 

1121 If `seed` is an int, a new ``RandomState`` instance is used, 

1122 seeded with `seed`. 

1123 If `seed` is already a ``Generator`` or ``RandomState`` instance then 

1124 that instance is used. 

1125 Specify `seed` for reproducing the return value from this function. 

1126 The random numbers generated with this seed affect the random vector 

1127 along which gradients are computed to check ``grad``. Note that `seed` 

1128 is only used when `direction` argument is set to `'random'`. 

1129 

1130 Returns 

1131 ------- 

1132 err : float 

1133 The square root of the sum of squares (i.e., the 2-norm) of the 

1134 difference between ``grad(x0, *args)`` and the finite difference 

1135 approximation of `grad` using func at the points `x0`. 

1136 

1137 See Also 

1138 -------- 

1139 approx_fprime 

1140 

1141 Examples 

1142 -------- 

1143 >>> import numpy as np 

1144 >>> def func(x): 

1145 ... return x[0]**2 - 0.5 * x[1]**3 

1146 >>> def grad(x): 

1147 ... return [2 * x[0], -1.5 * x[1]**2] 

1148 >>> from scipy.optimize import check_grad 

1149 >>> check_grad(func, grad, [1.5, -1.5]) 

1150 2.9802322387695312e-08 # may vary 

1151 >>> rng = np.random.default_rng() 

1152 >>> check_grad(func, grad, [1.5, -1.5], 

1153 ... direction='random', seed=rng) 

1154 2.9802322387695312e-08 

1155 

1156 """ 

1157 step = epsilon 

1158 x0 = np.asarray(x0) 

1159 

1160 def g(w, func, x0, v, *args): 

1161 return func(x0 + w*v, *args) 

1162 

1163 if direction == 'random': 

1164 _grad = np.asanyarray(grad(x0, *args)) 

1165 if _grad.ndim > 1: 

1166 raise ValueError("'random' can only be used with scalar valued" 

1167 " func") 

1168 random_state = check_random_state(seed) 

1169 v = random_state.normal(0, 1, size=(x0.shape)) 

1170 _args = (func, x0, v) + args 

1171 _func = g 

1172 vars = np.zeros((1,)) 

1173 analytical_grad = np.dot(_grad, v) 

1174 elif direction == 'all': 

1175 _args = args 

1176 _func = func 

1177 vars = x0 

1178 analytical_grad = grad(x0, *args) 

1179 else: 

1180 raise ValueError("{} is not a valid string for " 

1181 "``direction`` argument".format(direction)) 

1182 

1183 return np.sqrt(np.sum(np.abs( 

1184 (analytical_grad - approx_fprime(vars, _func, step, *_args))**2 

1185 ))) 

1186 

1187 

1188def approx_fhess_p(x0, p, fprime, epsilon, *args): 

1189 # calculate fprime(x0) first, as this may be cached by ScalarFunction 

1190 f1 = fprime(*((x0,) + args)) 

1191 f2 = fprime(*((x0 + epsilon*p,) + args)) 

1192 return (f2 - f1) / epsilon 

1193 

1194 

1195class _LineSearchError(RuntimeError): 

1196 pass 

1197 

1198 

1199def _line_search_wolfe12(f, fprime, xk, pk, gfk, old_fval, old_old_fval, 

1200 **kwargs): 

1201 """ 

1202 Same as line_search_wolfe1, but fall back to line_search_wolfe2 if 

1203 suitable step length is not found, and raise an exception if a 

1204 suitable step length is not found. 

1205 

1206 Raises 

1207 ------ 

1208 _LineSearchError 

1209 If no suitable step size is found 

1210 

1211 """ 

1212 

1213 extra_condition = kwargs.pop('extra_condition', None) 

1214 

1215 ret = line_search_wolfe1(f, fprime, xk, pk, gfk, 

1216 old_fval, old_old_fval, 

1217 **kwargs) 

1218 

1219 if ret[0] is not None and extra_condition is not None: 

1220 xp1 = xk + ret[0] * pk 

1221 if not extra_condition(ret[0], xp1, ret[3], ret[5]): 

1222 # Reject step if extra_condition fails 

1223 ret = (None,) 

1224 

1225 if ret[0] is None: 

1226 # line search failed: try different one. 

1227 with warnings.catch_warnings(): 

1228 warnings.simplefilter('ignore', LineSearchWarning) 

1229 kwargs2 = {} 

1230 for key in ('c1', 'c2', 'amax'): 

1231 if key in kwargs: 

1232 kwargs2[key] = kwargs[key] 

1233 ret = line_search_wolfe2(f, fprime, xk, pk, gfk, 

1234 old_fval, old_old_fval, 

1235 extra_condition=extra_condition, 

1236 **kwargs2) 

1237 

1238 if ret[0] is None: 

1239 raise _LineSearchError() 

1240 

1241 return ret 

1242 

1243 

1244def fmin_bfgs(f, x0, fprime=None, args=(), gtol=1e-5, norm=Inf, 

1245 epsilon=_epsilon, maxiter=None, full_output=0, disp=1, 

1246 retall=0, callback=None, xrtol=0): 

1247 """ 

1248 Minimize a function using the BFGS algorithm. 

1249 

1250 Parameters 

1251 ---------- 

1252 f : callable ``f(x,*args)`` 

1253 Objective function to be minimized. 

1254 x0 : ndarray 

1255 Initial guess. 

1256 fprime : callable ``f'(x,*args)``, optional 

1257 Gradient of f. 

1258 args : tuple, optional 

1259 Extra arguments passed to f and fprime. 

1260 gtol : float, optional 

1261 Terminate successfully if gradient norm is less than `gtol` 

1262 norm : float, optional 

1263 Order of norm (Inf is max, -Inf is min) 

1264 epsilon : int or ndarray, optional 

1265 If `fprime` is approximated, use this value for the step size. 

1266 callback : callable, optional 

1267 An optional user-supplied function to call after each 

1268 iteration. Called as ``callback(xk)``, where ``xk`` is the 

1269 current parameter vector. 

1270 maxiter : int, optional 

1271 Maximum number of iterations to perform. 

1272 full_output : bool, optional 

1273 If True, return ``fopt``, ``func_calls``, ``grad_calls``, and 

1274 ``warnflag`` in addition to ``xopt``. 

1275 disp : bool, optional 

1276 Print convergence message if True. 

1277 retall : bool, optional 

1278 Return a list of results at each iteration if True. 

1279 xrtol : float, default: 0 

1280 Relative tolerance for `x`. Terminate successfully if step 

1281 size is less than ``xk * xrtol`` where ``xk`` is the current 

1282 parameter vector. 

1283 

1284 Returns 

1285 ------- 

1286 xopt : ndarray 

1287 Parameters which minimize f, i.e., ``f(xopt) == fopt``. 

1288 fopt : float 

1289 Minimum value. 

1290 gopt : ndarray 

1291 Value of gradient at minimum, f'(xopt), which should be near 0. 

1292 Bopt : ndarray 

1293 Value of 1/f''(xopt), i.e., the inverse Hessian matrix. 

1294 func_calls : int 

1295 Number of function_calls made. 

1296 grad_calls : int 

1297 Number of gradient calls made. 

1298 warnflag : integer 

1299 1 : Maximum number of iterations exceeded. 

1300 2 : Gradient and/or function calls not changing. 

1301 3 : NaN result encountered. 

1302 allvecs : list 

1303 The value of `xopt` at each iteration. Only returned if `retall` is 

1304 True. 

1305 

1306 Notes 

1307 ----- 

1308 Optimize the function, `f`, whose gradient is given by `fprime` 

1309 using the quasi-Newton method of Broyden, Fletcher, Goldfarb, 

1310 and Shanno (BFGS). 

1311 

1312 See Also 

1313 -------- 

1314 minimize: Interface to minimization algorithms for multivariate 

1315 functions. See ``method='BFGS'`` in particular. 

1316 

1317 References 

1318 ---------- 

1319 Wright, and Nocedal 'Numerical Optimization', 1999, p. 198. 

1320 

1321 Examples 

1322 -------- 

1323 >>> import numpy as np 

1324 >>> from scipy.optimize import fmin_bfgs 

1325 >>> def quadratic_cost(x, Q): 

1326 ... return x @ Q @ x 

1327 ... 

1328 >>> x0 = np.array([-3, -4]) 

1329 >>> cost_weight = np.diag([1., 10.]) 

1330 >>> # Note that a trailing comma is necessary for a tuple with single element 

1331 >>> fmin_bfgs(quadratic_cost, x0, args=(cost_weight,)) 

1332 Optimization terminated successfully. 

1333 Current function value: 0.000000 

1334 Iterations: 7 # may vary 

1335 Function evaluations: 24 # may vary 

1336 Gradient evaluations: 8 # may vary 

1337 array([ 2.85169950e-06, -4.61820139e-07]) 

1338 

1339 >>> def quadratic_cost_grad(x, Q): 

1340 ... return 2 * Q @ x 

1341 ... 

1342 >>> fmin_bfgs(quadratic_cost, x0, quadratic_cost_grad, args=(cost_weight,)) 

1343 Optimization terminated successfully. 

1344 Current function value: 0.000000 

1345 Iterations: 7 

1346 Function evaluations: 8 

1347 Gradient evaluations: 8 

1348 array([ 2.85916637e-06, -4.54371951e-07]) 

1349 

1350 """ 

1351 opts = {'gtol': gtol, 

1352 'norm': norm, 

1353 'eps': epsilon, 

1354 'disp': disp, 

1355 'maxiter': maxiter, 

1356 'return_all': retall, 

1357 'xrtol': xrtol} 

1358 

1359 callback = _wrap_callback(callback) 

1360 res = _minimize_bfgs(f, x0, args, fprime, callback=callback, **opts) 

1361 

1362 if full_output: 

1363 retlist = (res['x'], res['fun'], res['jac'], res['hess_inv'], 

1364 res['nfev'], res['njev'], res['status']) 

1365 if retall: 

1366 retlist += (res['allvecs'], ) 

1367 return retlist 

1368 else: 

1369 if retall: 

1370 return res['x'], res['allvecs'] 

1371 else: 

1372 return res['x'] 

1373 

1374 

1375def _minimize_bfgs(fun, x0, args=(), jac=None, callback=None, 

1376 gtol=1e-5, norm=Inf, eps=_epsilon, maxiter=None, 

1377 disp=False, return_all=False, finite_diff_rel_step=None, 

1378 xrtol=0, **unknown_options): 

1379 """ 

1380 Minimization of scalar function of one or more variables using the 

1381 BFGS algorithm. 

1382 

1383 Options 

1384 ------- 

1385 disp : bool 

1386 Set to True to print convergence messages. 

1387 maxiter : int 

1388 Maximum number of iterations to perform. 

1389 gtol : float 

1390 Terminate successfully if gradient norm is less than `gtol`. 

1391 norm : float 

1392 Order of norm (Inf is max, -Inf is min). 

1393 eps : float or ndarray 

1394 If `jac is None` the absolute step size used for numerical 

1395 approximation of the jacobian via forward differences. 

1396 return_all : bool, optional 

1397 Set to True to return a list of the best solution at each of the 

1398 iterations. 

1399 finite_diff_rel_step : None or array_like, optional 

1400 If `jac in ['2-point', '3-point', 'cs']` the relative step size to 

1401 use for numerical approximation of the jacobian. The absolute step 

1402 size is computed as ``h = rel_step * sign(x) * max(1, abs(x))``, 

1403 possibly adjusted to fit into the bounds. For ``method='3-point'`` 

1404 the sign of `h` is ignored. If None (default) then step is selected 

1405 automatically. 

1406 xrtol : float, default: 0 

1407 Relative tolerance for `x`. Terminate successfully if step size is 

1408 less than ``xk * xrtol`` where ``xk`` is the current parameter vector. 

1409 """ 

1410 _check_unknown_options(unknown_options) 

1411 retall = return_all 

1412 

1413 x0 = asarray(x0).flatten() 

1414 if x0.ndim == 0: 

1415 x0.shape = (1,) 

1416 if maxiter is None: 

1417 maxiter = len(x0) * 200 

1418 

1419 sf = _prepare_scalar_function(fun, x0, jac, args=args, epsilon=eps, 

1420 finite_diff_rel_step=finite_diff_rel_step) 

1421 

1422 f = sf.fun 

1423 myfprime = sf.grad 

1424 

1425 old_fval = f(x0) 

1426 gfk = myfprime(x0) 

1427 

1428 k = 0 

1429 N = len(x0) 

1430 I = np.eye(N, dtype=int) 

1431 Hk = I 

1432 

1433 # Sets the initial step guess to dx ~ 1 

1434 old_old_fval = old_fval + np.linalg.norm(gfk) / 2 

1435 

1436 xk = x0 

1437 if retall: 

1438 allvecs = [x0] 

1439 warnflag = 0 

1440 gnorm = vecnorm(gfk, ord=norm) 

1441 while (gnorm > gtol) and (k < maxiter): 

1442 pk = -np.dot(Hk, gfk) 

1443 try: 

1444 alpha_k, fc, gc, old_fval, old_old_fval, gfkp1 = \ 

1445 _line_search_wolfe12(f, myfprime, xk, pk, gfk, 

1446 old_fval, old_old_fval, amin=1e-100, amax=1e100) 

1447 except _LineSearchError: 

1448 # Line search failed to find a better solution. 

1449 warnflag = 2 

1450 break 

1451 

1452 sk = alpha_k * pk 

1453 xkp1 = xk + sk 

1454 

1455 if retall: 

1456 allvecs.append(xkp1) 

1457 xk = xkp1 

1458 if gfkp1 is None: 

1459 gfkp1 = myfprime(xkp1) 

1460 

1461 yk = gfkp1 - gfk 

1462 gfk = gfkp1 

1463 k += 1 

1464 intermediate_result = OptimizeResult(x=xk, fun=old_fval) 

1465 if _call_callback_maybe_halt(callback, intermediate_result): 

1466 break 

1467 gnorm = vecnorm(gfk, ord=norm) 

1468 if (gnorm <= gtol): 

1469 break 

1470 

1471 # See Chapter 5 in P.E. Frandsen, K. Jonasson, H.B. Nielsen, 

1472 # O. Tingleff: "Unconstrained Optimization", IMM, DTU. 1999. 

1473 # These notes are available here: 

1474 # http://www2.imm.dtu.dk/documents/ftp/publlec.html 

1475 if (alpha_k*vecnorm(pk) <= xrtol*(xrtol + vecnorm(xk))): 

1476 break 

1477 

1478 if not np.isfinite(old_fval): 

1479 # We correctly found +-Inf as optimal value, or something went 

1480 # wrong. 

1481 warnflag = 2 

1482 break 

1483 

1484 rhok_inv = np.dot(yk, sk) 

1485 # this was handled in numeric, let it remaines for more safety 

1486 # Cryptic comment above is preserved for posterity. Future reader: 

1487 # consider change to condition below proposed in gh-1261/gh-17345. 

1488 if rhok_inv == 0.: 

1489 rhok = 1000.0 

1490 if disp: 

1491 msg = "Divide-by-zero encountered: rhok assumed large" 

1492 _print_success_message_or_warn(True, msg) 

1493 else: 

1494 rhok = 1. / rhok_inv 

1495 

1496 A1 = I - sk[:, np.newaxis] * yk[np.newaxis, :] * rhok 

1497 A2 = I - yk[:, np.newaxis] * sk[np.newaxis, :] * rhok 

1498 Hk = np.dot(A1, np.dot(Hk, A2)) + (rhok * sk[:, np.newaxis] * 

1499 sk[np.newaxis, :]) 

1500 

1501 fval = old_fval 

1502 

1503 if warnflag == 2: 

1504 msg = _status_message['pr_loss'] 

1505 elif k >= maxiter: 

1506 warnflag = 1 

1507 msg = _status_message['maxiter'] 

1508 elif np.isnan(gnorm) or np.isnan(fval) or np.isnan(xk).any(): 

1509 warnflag = 3 

1510 msg = _status_message['nan'] 

1511 else: 

1512 msg = _status_message['success'] 

1513 

1514 if disp: 

1515 _print_success_message_or_warn(warnflag, msg) 

1516 print(" Current function value: %f" % fval) 

1517 print(" Iterations: %d" % k) 

1518 print(" Function evaluations: %d" % sf.nfev) 

1519 print(" Gradient evaluations: %d" % sf.ngev) 

1520 

1521 result = OptimizeResult(fun=fval, jac=gfk, hess_inv=Hk, nfev=sf.nfev, 

1522 njev=sf.ngev, status=warnflag, 

1523 success=(warnflag == 0), message=msg, x=xk, 

1524 nit=k) 

1525 if retall: 

1526 result['allvecs'] = allvecs 

1527 return result 

1528 

1529 

1530def _print_success_message_or_warn(warnflag, message, warntype=None): 

1531 if not warnflag: 

1532 print(message) 

1533 else: 

1534 warnings.warn(message, warntype or OptimizeWarning, stacklevel=3) 

1535 

1536 

1537def fmin_cg(f, x0, fprime=None, args=(), gtol=1e-5, norm=Inf, epsilon=_epsilon, 

1538 maxiter=None, full_output=0, disp=1, retall=0, callback=None): 

1539 """ 

1540 Minimize a function using a nonlinear conjugate gradient algorithm. 

1541 

1542 Parameters 

1543 ---------- 

1544 f : callable, ``f(x, *args)`` 

1545 Objective function to be minimized. Here `x` must be a 1-D array of 

1546 the variables that are to be changed in the search for a minimum, and 

1547 `args` are the other (fixed) parameters of `f`. 

1548 x0 : ndarray 

1549 A user-supplied initial estimate of `xopt`, the optimal value of `x`. 

1550 It must be a 1-D array of values. 

1551 fprime : callable, ``fprime(x, *args)``, optional 

1552 A function that returns the gradient of `f` at `x`. Here `x` and `args` 

1553 are as described above for `f`. The returned value must be a 1-D array. 

1554 Defaults to None, in which case the gradient is approximated 

1555 numerically (see `epsilon`, below). 

1556 args : tuple, optional 

1557 Parameter values passed to `f` and `fprime`. Must be supplied whenever 

1558 additional fixed parameters are needed to completely specify the 

1559 functions `f` and `fprime`. 

1560 gtol : float, optional 

1561 Stop when the norm of the gradient is less than `gtol`. 

1562 norm : float, optional 

1563 Order to use for the norm of the gradient 

1564 (``-np.inf`` is min, ``np.inf`` is max). 

1565 epsilon : float or ndarray, optional 

1566 Step size(s) to use when `fprime` is approximated numerically. Can be a 

1567 scalar or a 1-D array. Defaults to ``sqrt(eps)``, with eps the 

1568 floating point machine precision. Usually ``sqrt(eps)`` is about 

1569 1.5e-8. 

1570 maxiter : int, optional 

1571 Maximum number of iterations to perform. Default is ``200 * len(x0)``. 

1572 full_output : bool, optional 

1573 If True, return `fopt`, `func_calls`, `grad_calls`, and `warnflag` in 

1574 addition to `xopt`. See the Returns section below for additional 

1575 information on optional return values. 

1576 disp : bool, optional 

1577 If True, return a convergence message, followed by `xopt`. 

1578 retall : bool, optional 

1579 If True, add to the returned values the results of each iteration. 

1580 callback : callable, optional 

1581 An optional user-supplied function, called after each iteration. 

1582 Called as ``callback(xk)``, where ``xk`` is the current value of `x0`. 

1583 

1584 Returns 

1585 ------- 

1586 xopt : ndarray 

1587 Parameters which minimize f, i.e., ``f(xopt) == fopt``. 

1588 fopt : float, optional 

1589 Minimum value found, f(xopt). Only returned if `full_output` is True. 

1590 func_calls : int, optional 

1591 The number of function_calls made. Only returned if `full_output` 

1592 is True. 

1593 grad_calls : int, optional 

1594 The number of gradient calls made. Only returned if `full_output` is 

1595 True. 

1596 warnflag : int, optional 

1597 Integer value with warning status, only returned if `full_output` is 

1598 True. 

1599 

1600 0 : Success. 

1601 

1602 1 : The maximum number of iterations was exceeded. 

1603 

1604 2 : Gradient and/or function calls were not changing. May indicate 

1605 that precision was lost, i.e., the routine did not converge. 

1606 

1607 3 : NaN result encountered. 

1608 

1609 allvecs : list of ndarray, optional 

1610 List of arrays, containing the results at each iteration. 

1611 Only returned if `retall` is True. 

1612 

1613 See Also 

1614 -------- 

1615 minimize : common interface to all `scipy.optimize` algorithms for 

1616 unconstrained and constrained minimization of multivariate 

1617 functions. It provides an alternative way to call 

1618 ``fmin_cg``, by specifying ``method='CG'``. 

1619 

1620 Notes 

1621 ----- 

1622 This conjugate gradient algorithm is based on that of Polak and Ribiere 

1623 [1]_. 

1624 

1625 Conjugate gradient methods tend to work better when: 

1626 

1627 1. `f` has a unique global minimizing point, and no local minima or 

1628 other stationary points, 

1629 2. `f` is, at least locally, reasonably well approximated by a 

1630 quadratic function of the variables, 

1631 3. `f` is continuous and has a continuous gradient, 

1632 4. `fprime` is not too large, e.g., has a norm less than 1000, 

1633 5. The initial guess, `x0`, is reasonably close to `f` 's global 

1634 minimizing point, `xopt`. 

1635 

1636 References 

1637 ---------- 

1638 .. [1] Wright & Nocedal, "Numerical Optimization", 1999, pp. 120-122. 

1639 

1640 Examples 

1641 -------- 

1642 Example 1: seek the minimum value of the expression 

1643 ``a*u**2 + b*u*v + c*v**2 + d*u + e*v + f`` for given values 

1644 of the parameters and an initial guess ``(u, v) = (0, 0)``. 

1645 

1646 >>> import numpy as np 

1647 >>> args = (2, 3, 7, 8, 9, 10) # parameter values 

1648 >>> def f(x, *args): 

1649 ... u, v = x 

1650 ... a, b, c, d, e, f = args 

1651 ... return a*u**2 + b*u*v + c*v**2 + d*u + e*v + f 

1652 >>> def gradf(x, *args): 

1653 ... u, v = x 

1654 ... a, b, c, d, e, f = args 

1655 ... gu = 2*a*u + b*v + d # u-component of the gradient 

1656 ... gv = b*u + 2*c*v + e # v-component of the gradient 

1657 ... return np.asarray((gu, gv)) 

1658 >>> x0 = np.asarray((0, 0)) # Initial guess. 

1659 >>> from scipy import optimize 

1660 >>> res1 = optimize.fmin_cg(f, x0, fprime=gradf, args=args) 

1661 Optimization terminated successfully. 

1662 Current function value: 1.617021 

1663 Iterations: 4 

1664 Function evaluations: 8 

1665 Gradient evaluations: 8 

1666 >>> res1 

1667 array([-1.80851064, -0.25531915]) 

1668 

1669 Example 2: solve the same problem using the `minimize` function. 

1670 (This `myopts` dictionary shows all of the available options, 

1671 although in practice only non-default values would be needed. 

1672 The returned value will be a dictionary.) 

1673 

1674 >>> opts = {'maxiter' : None, # default value. 

1675 ... 'disp' : True, # non-default value. 

1676 ... 'gtol' : 1e-5, # default value. 

1677 ... 'norm' : np.inf, # default value. 

1678 ... 'eps' : 1.4901161193847656e-08} # default value. 

1679 >>> res2 = optimize.minimize(f, x0, jac=gradf, args=args, 

1680 ... method='CG', options=opts) 

1681 Optimization terminated successfully. 

1682 Current function value: 1.617021 

1683 Iterations: 4 

1684 Function evaluations: 8 

1685 Gradient evaluations: 8 

1686 >>> res2.x # minimum found 

1687 array([-1.80851064, -0.25531915]) 

1688 

1689 """ 

1690 opts = {'gtol': gtol, 

1691 'norm': norm, 

1692 'eps': epsilon, 

1693 'disp': disp, 

1694 'maxiter': maxiter, 

1695 'return_all': retall} 

1696 

1697 callback = _wrap_callback(callback) 

1698 res = _minimize_cg(f, x0, args, fprime, callback=callback, **opts) 

1699 

1700 if full_output: 

1701 retlist = res['x'], res['fun'], res['nfev'], res['njev'], res['status'] 

1702 if retall: 

1703 retlist += (res['allvecs'], ) 

1704 return retlist 

1705 else: 

1706 if retall: 

1707 return res['x'], res['allvecs'] 

1708 else: 

1709 return res['x'] 

1710 

1711 

1712def _minimize_cg(fun, x0, args=(), jac=None, callback=None, 

1713 gtol=1e-5, norm=Inf, eps=_epsilon, maxiter=None, 

1714 disp=False, return_all=False, finite_diff_rel_step=None, 

1715 **unknown_options): 

1716 """ 

1717 Minimization of scalar function of one or more variables using the 

1718 conjugate gradient algorithm. 

1719 

1720 Options 

1721 ------- 

1722 disp : bool 

1723 Set to True to print convergence messages. 

1724 maxiter : int 

1725 Maximum number of iterations to perform. 

1726 gtol : float 

1727 Gradient norm must be less than `gtol` before successful 

1728 termination. 

1729 norm : float 

1730 Order of norm (Inf is max, -Inf is min). 

1731 eps : float or ndarray 

1732 If `jac is None` the absolute step size used for numerical 

1733 approximation of the jacobian via forward differences. 

1734 return_all : bool, optional 

1735 Set to True to return a list of the best solution at each of the 

1736 iterations. 

1737 finite_diff_rel_step : None or array_like, optional 

1738 If `jac in ['2-point', '3-point', 'cs']` the relative step size to 

1739 use for numerical approximation of the jacobian. The absolute step 

1740 size is computed as ``h = rel_step * sign(x) * max(1, abs(x))``, 

1741 possibly adjusted to fit into the bounds. For ``method='3-point'`` 

1742 the sign of `h` is ignored. If None (default) then step is selected 

1743 automatically. 

1744 """ 

1745 _check_unknown_options(unknown_options) 

1746 

1747 retall = return_all 

1748 

1749 x0 = asarray(x0).flatten() 

1750 if maxiter is None: 

1751 maxiter = len(x0) * 200 

1752 

1753 sf = _prepare_scalar_function(fun, x0, jac=jac, args=args, epsilon=eps, 

1754 finite_diff_rel_step=finite_diff_rel_step) 

1755 

1756 f = sf.fun 

1757 myfprime = sf.grad 

1758 

1759 old_fval = f(x0) 

1760 gfk = myfprime(x0) 

1761 

1762 k = 0 

1763 xk = x0 

1764 # Sets the initial step guess to dx ~ 1 

1765 old_old_fval = old_fval + np.linalg.norm(gfk) / 2 

1766 

1767 if retall: 

1768 allvecs = [xk] 

1769 warnflag = 0 

1770 pk = -gfk 

1771 gnorm = vecnorm(gfk, ord=norm) 

1772 

1773 sigma_3 = 0.01 

1774 

1775 while (gnorm > gtol) and (k < maxiter): 

1776 deltak = np.dot(gfk, gfk) 

1777 

1778 cached_step = [None] 

1779 

1780 def polak_ribiere_powell_step(alpha, gfkp1=None): 

1781 xkp1 = xk + alpha * pk 

1782 if gfkp1 is None: 

1783 gfkp1 = myfprime(xkp1) 

1784 yk = gfkp1 - gfk 

1785 beta_k = max(0, np.dot(yk, gfkp1) / deltak) 

1786 pkp1 = -gfkp1 + beta_k * pk 

1787 gnorm = vecnorm(gfkp1, ord=norm) 

1788 return (alpha, xkp1, pkp1, gfkp1, gnorm) 

1789 

1790 def descent_condition(alpha, xkp1, fp1, gfkp1): 

1791 # Polak-Ribiere+ needs an explicit check of a sufficient 

1792 # descent condition, which is not guaranteed by strong Wolfe. 

1793 # 

1794 # See Gilbert & Nocedal, "Global convergence properties of 

1795 # conjugate gradient methods for optimization", 

1796 # SIAM J. Optimization 2, 21 (1992). 

1797 cached_step[:] = polak_ribiere_powell_step(alpha, gfkp1) 

1798 alpha, xk, pk, gfk, gnorm = cached_step 

1799 

1800 # Accept step if it leads to convergence. 

1801 if gnorm <= gtol: 

1802 return True 

1803 

1804 # Accept step if sufficient descent condition applies. 

1805 return np.dot(pk, gfk) <= -sigma_3 * np.dot(gfk, gfk) 

1806 

1807 try: 

1808 alpha_k, fc, gc, old_fval, old_old_fval, gfkp1 = \ 

1809 _line_search_wolfe12(f, myfprime, xk, pk, gfk, old_fval, 

1810 old_old_fval, c2=0.4, amin=1e-100, amax=1e100, 

1811 extra_condition=descent_condition) 

1812 except _LineSearchError: 

1813 # Line search failed to find a better solution. 

1814 warnflag = 2 

1815 break 

1816 

1817 # Reuse already computed results if possible 

1818 if alpha_k == cached_step[0]: 

1819 alpha_k, xk, pk, gfk, gnorm = cached_step 

1820 else: 

1821 alpha_k, xk, pk, gfk, gnorm = polak_ribiere_powell_step(alpha_k, gfkp1) 

1822 

1823 if retall: 

1824 allvecs.append(xk) 

1825 k += 1 

1826 intermediate_result = OptimizeResult(x=xk, fun=old_fval) 

1827 if _call_callback_maybe_halt(callback, intermediate_result): 

1828 break 

1829 

1830 fval = old_fval 

1831 if warnflag == 2: 

1832 msg = _status_message['pr_loss'] 

1833 elif k >= maxiter: 

1834 warnflag = 1 

1835 msg = _status_message['maxiter'] 

1836 elif np.isnan(gnorm) or np.isnan(fval) or np.isnan(xk).any(): 

1837 warnflag = 3 

1838 msg = _status_message['nan'] 

1839 else: 

1840 msg = _status_message['success'] 

1841 

1842 if disp: 

1843 _print_success_message_or_warn(warnflag, msg) 

1844 print(" Current function value: %f" % fval) 

1845 print(" Iterations: %d" % k) 

1846 print(" Function evaluations: %d" % sf.nfev) 

1847 print(" Gradient evaluations: %d" % sf.ngev) 

1848 

1849 result = OptimizeResult(fun=fval, jac=gfk, nfev=sf.nfev, 

1850 njev=sf.ngev, status=warnflag, 

1851 success=(warnflag == 0), message=msg, x=xk, 

1852 nit=k) 

1853 if retall: 

1854 result['allvecs'] = allvecs 

1855 return result 

1856 

1857 

1858def fmin_ncg(f, x0, fprime, fhess_p=None, fhess=None, args=(), avextol=1e-5, 

1859 epsilon=_epsilon, maxiter=None, full_output=0, disp=1, retall=0, 

1860 callback=None): 

1861 """ 

1862 Unconstrained minimization of a function using the Newton-CG method. 

1863 

1864 Parameters 

1865 ---------- 

1866 f : callable ``f(x, *args)`` 

1867 Objective function to be minimized. 

1868 x0 : ndarray 

1869 Initial guess. 

1870 fprime : callable ``f'(x, *args)`` 

1871 Gradient of f. 

1872 fhess_p : callable ``fhess_p(x, p, *args)``, optional 

1873 Function which computes the Hessian of f times an 

1874 arbitrary vector, p. 

1875 fhess : callable ``fhess(x, *args)``, optional 

1876 Function to compute the Hessian matrix of f. 

1877 args : tuple, optional 

1878 Extra arguments passed to f, fprime, fhess_p, and fhess 

1879 (the same set of extra arguments is supplied to all of 

1880 these functions). 

1881 epsilon : float or ndarray, optional 

1882 If fhess is approximated, use this value for the step size. 

1883 callback : callable, optional 

1884 An optional user-supplied function which is called after 

1885 each iteration. Called as callback(xk), where xk is the 

1886 current parameter vector. 

1887 avextol : float, optional 

1888 Convergence is assumed when the average relative error in 

1889 the minimizer falls below this amount. 

1890 maxiter : int, optional 

1891 Maximum number of iterations to perform. 

1892 full_output : bool, optional 

1893 If True, return the optional outputs. 

1894 disp : bool, optional 

1895 If True, print convergence message. 

1896 retall : bool, optional 

1897 If True, return a list of results at each iteration. 

1898 

1899 Returns 

1900 ------- 

1901 xopt : ndarray 

1902 Parameters which minimize f, i.e., ``f(xopt) == fopt``. 

1903 fopt : float 

1904 Value of the function at xopt, i.e., ``fopt = f(xopt)``. 

1905 fcalls : int 

1906 Number of function calls made. 

1907 gcalls : int 

1908 Number of gradient calls made. 

1909 hcalls : int 

1910 Number of Hessian calls made. 

1911 warnflag : int 

1912 Warnings generated by the algorithm. 

1913 1 : Maximum number of iterations exceeded. 

1914 2 : Line search failure (precision loss). 

1915 3 : NaN result encountered. 

1916 allvecs : list 

1917 The result at each iteration, if retall is True (see below). 

1918 

1919 See also 

1920 -------- 

1921 minimize: Interface to minimization algorithms for multivariate 

1922 functions. See the 'Newton-CG' `method` in particular. 

1923 

1924 Notes 

1925 ----- 

1926 Only one of `fhess_p` or `fhess` need to be given. If `fhess` 

1927 is provided, then `fhess_p` will be ignored. If neither `fhess` 

1928 nor `fhess_p` is provided, then the hessian product will be 

1929 approximated using finite differences on `fprime`. `fhess_p` 

1930 must compute the hessian times an arbitrary vector. If it is not 

1931 given, finite-differences on `fprime` are used to compute 

1932 it. 

1933 

1934 Newton-CG methods are also called truncated Newton methods. This 

1935 function differs from scipy.optimize.fmin_tnc because 

1936 

1937 1. scipy.optimize.fmin_ncg is written purely in Python using NumPy 

1938 and scipy while scipy.optimize.fmin_tnc calls a C function. 

1939 2. scipy.optimize.fmin_ncg is only for unconstrained minimization 

1940 while scipy.optimize.fmin_tnc is for unconstrained minimization 

1941 or box constrained minimization. (Box constraints give 

1942 lower and upper bounds for each variable separately.) 

1943 

1944 References 

1945 ---------- 

1946 Wright & Nocedal, 'Numerical Optimization', 1999, p. 140. 

1947 

1948 """ 

1949 opts = {'xtol': avextol, 

1950 'eps': epsilon, 

1951 'maxiter': maxiter, 

1952 'disp': disp, 

1953 'return_all': retall} 

1954 

1955 callback = _wrap_callback(callback) 

1956 res = _minimize_newtoncg(f, x0, args, fprime, fhess, fhess_p, 

1957 callback=callback, **opts) 

1958 

1959 if full_output: 

1960 retlist = (res['x'], res['fun'], res['nfev'], res['njev'], 

1961 res['nhev'], res['status']) 

1962 if retall: 

1963 retlist += (res['allvecs'], ) 

1964 return retlist 

1965 else: 

1966 if retall: 

1967 return res['x'], res['allvecs'] 

1968 else: 

1969 return res['x'] 

1970 

1971 

1972def _minimize_newtoncg(fun, x0, args=(), jac=None, hess=None, hessp=None, 

1973 callback=None, xtol=1e-5, eps=_epsilon, maxiter=None, 

1974 disp=False, return_all=False, 

1975 **unknown_options): 

1976 """ 

1977 Minimization of scalar function of one or more variables using the 

1978 Newton-CG algorithm. 

1979 

1980 Note that the `jac` parameter (Jacobian) is required. 

1981 

1982 Options 

1983 ------- 

1984 disp : bool 

1985 Set to True to print convergence messages. 

1986 xtol : float 

1987 Average relative error in solution `xopt` acceptable for 

1988 convergence. 

1989 maxiter : int 

1990 Maximum number of iterations to perform. 

1991 eps : float or ndarray 

1992 If `hessp` is approximated, use this value for the step size. 

1993 return_all : bool, optional 

1994 Set to True to return a list of the best solution at each of the 

1995 iterations. 

1996 """ 

1997 _check_unknown_options(unknown_options) 

1998 if jac is None: 

1999 raise ValueError('Jacobian is required for Newton-CG method') 

2000 fhess_p = hessp 

2001 fhess = hess 

2002 avextol = xtol 

2003 epsilon = eps 

2004 retall = return_all 

2005 

2006 x0 = asarray(x0).flatten() 

2007 # TODO: add hessp (callable or FD) to ScalarFunction? 

2008 sf = _prepare_scalar_function( 

2009 fun, x0, jac, args=args, epsilon=eps, hess=hess 

2010 ) 

2011 f = sf.fun 

2012 fprime = sf.grad 

2013 _h = sf.hess(x0) 

2014 

2015 # Logic for hess/hessp 

2016 # - If a callable(hess) is provided, then use that 

2017 # - If hess is a FD_METHOD, or the output fom hess(x) is a LinearOperator 

2018 # then create a hessp function using those. 

2019 # - If hess is None but you have callable(hessp) then use the hessp. 

2020 # - If hess and hessp are None then approximate hessp using the grad/jac. 

2021 

2022 if (hess in FD_METHODS or isinstance(_h, LinearOperator)): 

2023 fhess = None 

2024 

2025 def _hessp(x, p, *args): 

2026 return sf.hess(x).dot(p) 

2027 

2028 fhess_p = _hessp 

2029 

2030 def terminate(warnflag, msg): 

2031 if disp: 

2032 _print_success_message_or_warn(warnflag, msg) 

2033 print(" Current function value: %f" % old_fval) 

2034 print(" Iterations: %d" % k) 

2035 print(" Function evaluations: %d" % sf.nfev) 

2036 print(" Gradient evaluations: %d" % sf.ngev) 

2037 print(" Hessian evaluations: %d" % hcalls) 

2038 fval = old_fval 

2039 result = OptimizeResult(fun=fval, jac=gfk, nfev=sf.nfev, 

2040 njev=sf.ngev, nhev=hcalls, status=warnflag, 

2041 success=(warnflag == 0), message=msg, x=xk, 

2042 nit=k) 

2043 if retall: 

2044 result['allvecs'] = allvecs 

2045 return result 

2046 

2047 hcalls = 0 

2048 if maxiter is None: 

2049 maxiter = len(x0)*200 

2050 cg_maxiter = 20*len(x0) 

2051 

2052 xtol = len(x0) * avextol 

2053 update = [2 * xtol] 

2054 xk = x0 

2055 if retall: 

2056 allvecs = [xk] 

2057 k = 0 

2058 gfk = None 

2059 old_fval = f(x0) 

2060 old_old_fval = None 

2061 float64eps = np.finfo(np.float64).eps 

2062 while np.add.reduce(np.abs(update)) > xtol: 

2063 if k >= maxiter: 

2064 msg = "Warning: " + _status_message['maxiter'] 

2065 return terminate(1, msg) 

2066 # Compute a search direction pk by applying the CG method to 

2067 # del2 f(xk) p = - grad f(xk) starting from 0. 

2068 b = -fprime(xk) 

2069 maggrad = np.add.reduce(np.abs(b)) 

2070 eta = np.min([0.5, np.sqrt(maggrad)]) 

2071 termcond = eta * maggrad 

2072 xsupi = zeros(len(x0), dtype=x0.dtype) 

2073 ri = -b 

2074 psupi = -ri 

2075 i = 0 

2076 dri0 = np.dot(ri, ri) 

2077 

2078 if fhess is not None: # you want to compute hessian once. 

2079 A = sf.hess(xk) 

2080 hcalls = hcalls + 1 

2081 

2082 for k2 in range(cg_maxiter): 

2083 if np.add.reduce(np.abs(ri)) <= termcond: 

2084 break 

2085 if fhess is None: 

2086 if fhess_p is None: 

2087 Ap = approx_fhess_p(xk, psupi, fprime, epsilon) 

2088 else: 

2089 Ap = fhess_p(xk, psupi, *args) 

2090 hcalls = hcalls + 1 

2091 else: 

2092 if isinstance(A, HessianUpdateStrategy): 

2093 # if hess was supplied as a HessianUpdateStrategy 

2094 Ap = A.dot(psupi) 

2095 else: 

2096 Ap = np.dot(A, psupi) 

2097 # check curvature 

2098 Ap = asarray(Ap).squeeze() # get rid of matrices... 

2099 curv = np.dot(psupi, Ap) 

2100 if 0 <= curv <= 3 * float64eps: 

2101 break 

2102 elif curv < 0: 

2103 if (i > 0): 

2104 break 

2105 else: 

2106 # fall back to steepest descent direction 

2107 xsupi = dri0 / (-curv) * b 

2108 break 

2109 alphai = dri0 / curv 

2110 xsupi = xsupi + alphai * psupi 

2111 ri = ri + alphai * Ap 

2112 dri1 = np.dot(ri, ri) 

2113 betai = dri1 / dri0 

2114 psupi = -ri + betai * psupi 

2115 i = i + 1 

2116 dri0 = dri1 # update np.dot(ri,ri) for next time. 

2117 else: 

2118 # curvature keeps increasing, bail out 

2119 msg = ("Warning: CG iterations didn't converge. The Hessian is not " 

2120 "positive definite.") 

2121 return terminate(3, msg) 

2122 

2123 pk = xsupi # search direction is solution to system. 

2124 gfk = -b # gradient at xk 

2125 

2126 try: 

2127 alphak, fc, gc, old_fval, old_old_fval, gfkp1 = \ 

2128 _line_search_wolfe12(f, fprime, xk, pk, gfk, 

2129 old_fval, old_old_fval) 

2130 except _LineSearchError: 

2131 # Line search failed to find a better solution. 

2132 msg = "Warning: " + _status_message['pr_loss'] 

2133 return terminate(2, msg) 

2134 

2135 update = alphak * pk 

2136 xk = xk + update # upcast if necessary 

2137 if retall: 

2138 allvecs.append(xk) 

2139 k += 1 

2140 intermediate_result = OptimizeResult(x=xk, fun=old_fval) 

2141 if _call_callback_maybe_halt(callback, intermediate_result): 

2142 return terminate(5, "") 

2143 

2144 else: 

2145 if np.isnan(old_fval) or np.isnan(update).any(): 

2146 return terminate(3, _status_message['nan']) 

2147 

2148 msg = _status_message['success'] 

2149 return terminate(0, msg) 

2150 

2151 

2152def fminbound(func, x1, x2, args=(), xtol=1e-5, maxfun=500, 

2153 full_output=0, disp=1): 

2154 """Bounded minimization for scalar functions. 

2155 

2156 Parameters 

2157 ---------- 

2158 func : callable f(x,*args) 

2159 Objective function to be minimized (must accept and return scalars). 

2160 x1, x2 : float or array scalar 

2161 Finite optimization bounds. 

2162 args : tuple, optional 

2163 Extra arguments passed to function. 

2164 xtol : float, optional 

2165 The convergence tolerance. 

2166 maxfun : int, optional 

2167 Maximum number of function evaluations allowed. 

2168 full_output : bool, optional 

2169 If True, return optional outputs. 

2170 disp : int, optional 

2171 If non-zero, print messages. 

2172 0 : no message printing. 

2173 1 : non-convergence notification messages only. 

2174 2 : print a message on convergence too. 

2175 3 : print iteration results. 

2176 

2177 

2178 Returns 

2179 ------- 

2180 xopt : ndarray 

2181 Parameters (over given interval) which minimize the 

2182 objective function. 

2183 fval : number 

2184 (Optional output) The function value evaluated at the minimizer. 

2185 ierr : int 

2186 (Optional output) An error flag (0 if converged, 1 if maximum number of 

2187 function calls reached). 

2188 numfunc : int 

2189 (Optional output) The number of function calls made. 

2190 

2191 See also 

2192 -------- 

2193 minimize_scalar: Interface to minimization algorithms for scalar 

2194 univariate functions. See the 'Bounded' `method` in particular. 

2195 

2196 Notes 

2197 ----- 

2198 Finds a local minimizer of the scalar function `func` in the 

2199 interval x1 < xopt < x2 using Brent's method. (See `brent` 

2200 for auto-bracketing.) 

2201 

2202 References 

2203 ---------- 

2204 .. [1] Forsythe, G.E., M. A. Malcolm, and C. B. Moler. "Computer Methods 

2205 for Mathematical Computations." Prentice-Hall Series in Automatic 

2206 Computation 259 (1977). 

2207 .. [2] Brent, Richard P. Algorithms for Minimization Without Derivatives. 

2208 Courier Corporation, 2013. 

2209 

2210 Examples 

2211 -------- 

2212 `fminbound` finds the minimizer of the function in the given range. 

2213 The following examples illustrate this. 

2214 

2215 >>> from scipy import optimize 

2216 >>> def f(x): 

2217 ... return (x-1)**2 

2218 >>> minimizer = optimize.fminbound(f, -4, 4) 

2219 >>> minimizer 

2220 1.0 

2221 >>> minimum = f(minimizer) 

2222 >>> minimum 

2223 0.0 

2224 >>> res = optimize.fminbound(f, 3, 4, full_output=True) 

2225 >>> minimizer, fval, ierr, numfunc = res 

2226 >>> minimizer 

2227 3.000005960860986 

2228 >>> minimum = f(minimizer) 

2229 >>> minimum, fval 

2230 (4.000023843479476, 4.000023843479476) 

2231 """ 

2232 options = {'xatol': xtol, 

2233 'maxiter': maxfun, 

2234 'disp': disp} 

2235 

2236 res = _minimize_scalar_bounded(func, (x1, x2), args, **options) 

2237 if full_output: 

2238 return res['x'], res['fun'], res['status'], res['nfev'] 

2239 else: 

2240 return res['x'] 

2241 

2242 

2243def _minimize_scalar_bounded(func, bounds, args=(), 

2244 xatol=1e-5, maxiter=500, disp=0, 

2245 **unknown_options): 

2246 """ 

2247 Options 

2248 ------- 

2249 maxiter : int 

2250 Maximum number of iterations to perform. 

2251 disp: int, optional 

2252 If non-zero, print messages. 

2253 0 : no message printing. 

2254 1 : non-convergence notification messages only. 

2255 2 : print a message on convergence too. 

2256 3 : print iteration results. 

2257 xatol : float 

2258 Absolute error in solution `xopt` acceptable for convergence. 

2259 

2260 """ 

2261 _check_unknown_options(unknown_options) 

2262 maxfun = maxiter 

2263 # Test bounds are of correct form 

2264 if len(bounds) != 2: 

2265 raise ValueError('bounds must have two elements.') 

2266 x1, x2 = bounds 

2267 

2268 if not (is_finite_scalar(x1) and is_finite_scalar(x2)): 

2269 raise ValueError("Optimization bounds must be finite scalars.") 

2270 

2271 if x1 > x2: 

2272 raise ValueError("The lower bound exceeds the upper bound.") 

2273 

2274 flag = 0 

2275 header = ' Func-count x f(x) Procedure' 

2276 step = ' initial' 

2277 

2278 sqrt_eps = sqrt(2.2e-16) 

2279 golden_mean = 0.5 * (3.0 - sqrt(5.0)) 

2280 a, b = x1, x2 

2281 fulc = a + golden_mean * (b - a) 

2282 nfc, xf = fulc, fulc 

2283 rat = e = 0.0 

2284 x = xf 

2285 fx = func(x, *args) 

2286 num = 1 

2287 fmin_data = (1, xf, fx) 

2288 fu = np.inf 

2289 

2290 ffulc = fnfc = fx 

2291 xm = 0.5 * (a + b) 

2292 tol1 = sqrt_eps * np.abs(xf) + xatol / 3.0 

2293 tol2 = 2.0 * tol1 

2294 

2295 if disp > 2: 

2296 print(" ") 

2297 print(header) 

2298 print("%5.0f %12.6g %12.6g %s" % (fmin_data + (step,))) 

2299 

2300 while (np.abs(xf - xm) > (tol2 - 0.5 * (b - a))): 

2301 golden = 1 

2302 # Check for parabolic fit 

2303 if np.abs(e) > tol1: 

2304 golden = 0 

2305 r = (xf - nfc) * (fx - ffulc) 

2306 q = (xf - fulc) * (fx - fnfc) 

2307 p = (xf - fulc) * q - (xf - nfc) * r 

2308 q = 2.0 * (q - r) 

2309 if q > 0.0: 

2310 p = -p 

2311 q = np.abs(q) 

2312 r = e 

2313 e = rat 

2314 

2315 # Check for acceptability of parabola 

2316 if ((np.abs(p) < np.abs(0.5*q*r)) and (p > q*(a - xf)) and 

2317 (p < q * (b - xf))): 

2318 rat = (p + 0.0) / q 

2319 x = xf + rat 

2320 step = ' parabolic' 

2321 

2322 if ((x - a) < tol2) or ((b - x) < tol2): 

2323 si = np.sign(xm - xf) + ((xm - xf) == 0) 

2324 rat = tol1 * si 

2325 else: # do a golden-section step 

2326 golden = 1 

2327 

2328 if golden: # do a golden-section step 

2329 if xf >= xm: 

2330 e = a - xf 

2331 else: 

2332 e = b - xf 

2333 rat = golden_mean*e 

2334 step = ' golden' 

2335 

2336 si = np.sign(rat) + (rat == 0) 

2337 x = xf + si * np.maximum(np.abs(rat), tol1) 

2338 fu = func(x, *args) 

2339 num += 1 

2340 fmin_data = (num, x, fu) 

2341 if disp > 2: 

2342 print("%5.0f %12.6g %12.6g %s" % (fmin_data + (step,))) 

2343 

2344 if fu <= fx: 

2345 if x >= xf: 

2346 a = xf 

2347 else: 

2348 b = xf 

2349 fulc, ffulc = nfc, fnfc 

2350 nfc, fnfc = xf, fx 

2351 xf, fx = x, fu 

2352 else: 

2353 if x < xf: 

2354 a = x 

2355 else: 

2356 b = x 

2357 if (fu <= fnfc) or (nfc == xf): 

2358 fulc, ffulc = nfc, fnfc 

2359 nfc, fnfc = x, fu 

2360 elif (fu <= ffulc) or (fulc == xf) or (fulc == nfc): 

2361 fulc, ffulc = x, fu 

2362 

2363 xm = 0.5 * (a + b) 

2364 tol1 = sqrt_eps * np.abs(xf) + xatol / 3.0 

2365 tol2 = 2.0 * tol1 

2366 

2367 if num >= maxfun: 

2368 flag = 1 

2369 break 

2370 

2371 if np.isnan(xf) or np.isnan(fx) or np.isnan(fu): 

2372 flag = 2 

2373 

2374 fval = fx 

2375 if disp > 0: 

2376 _endprint(x, flag, fval, maxfun, xatol, disp) 

2377 

2378 result = OptimizeResult(fun=fval, status=flag, success=(flag == 0), 

2379 message={0: 'Solution found.', 

2380 1: 'Maximum number of function calls ' 

2381 'reached.', 

2382 2: _status_message['nan']}.get(flag, ''), 

2383 x=xf, nfev=num, nit=num) 

2384 

2385 return result 

2386 

2387 

2388class Brent: 

2389 #need to rethink design of __init__ 

2390 def __init__(self, func, args=(), tol=1.48e-8, maxiter=500, 

2391 full_output=0, disp=0): 

2392 self.func = func 

2393 self.args = args 

2394 self.tol = tol 

2395 self.maxiter = maxiter 

2396 self._mintol = 1.0e-11 

2397 self._cg = 0.3819660 

2398 self.xmin = None 

2399 self.fval = None 

2400 self.iter = 0 

2401 self.funcalls = 0 

2402 self.disp = disp 

2403 

2404 # need to rethink design of set_bracket (new options, etc.) 

2405 def set_bracket(self, brack=None): 

2406 self.brack = brack 

2407 

2408 def get_bracket_info(self): 

2409 #set up 

2410 func = self.func 

2411 args = self.args 

2412 brack = self.brack 

2413 ### BEGIN core bracket_info code ### 

2414 ### carefully DOCUMENT any CHANGES in core ## 

2415 if brack is None: 

2416 xa, xb, xc, fa, fb, fc, funcalls = bracket(func, args=args) 

2417 elif len(brack) == 2: 

2418 xa, xb, xc, fa, fb, fc, funcalls = bracket(func, xa=brack[0], 

2419 xb=brack[1], args=args) 

2420 elif len(brack) == 3: 

2421 xa, xb, xc = brack 

2422 if (xa > xc): # swap so xa < xc can be assumed 

2423 xc, xa = xa, xc 

2424 if not ((xa < xb) and (xb < xc)): 

2425 raise ValueError( 

2426 "Bracketing values (xa, xb, xc) do not" 

2427 " fulfill this requirement: (xa < xb) and (xb < xc)" 

2428 ) 

2429 fa = func(*((xa,) + args)) 

2430 fb = func(*((xb,) + args)) 

2431 fc = func(*((xc,) + args)) 

2432 if not ((fb < fa) and (fb < fc)): 

2433 raise ValueError( 

2434 "Bracketing values (xa, xb, xc) do not fulfill" 

2435 " this requirement: (f(xb) < f(xa)) and (f(xb) < f(xc))" 

2436 ) 

2437 

2438 funcalls = 3 

2439 else: 

2440 raise ValueError("Bracketing interval must be " 

2441 "length 2 or 3 sequence.") 

2442 ### END core bracket_info code ### 

2443 

2444 return xa, xb, xc, fa, fb, fc, funcalls 

2445 

2446 def optimize(self): 

2447 # set up for optimization 

2448 func = self.func 

2449 xa, xb, xc, fa, fb, fc, funcalls = self.get_bracket_info() 

2450 _mintol = self._mintol 

2451 _cg = self._cg 

2452 ################################# 

2453 #BEGIN CORE ALGORITHM 

2454 ################################# 

2455 x = w = v = xb 

2456 fw = fv = fx = fb 

2457 if (xa < xc): 

2458 a = xa 

2459 b = xc 

2460 else: 

2461 a = xc 

2462 b = xa 

2463 deltax = 0.0 

2464 iter = 0 

2465 

2466 if self.disp > 2: 

2467 print(" ") 

2468 print(f"{'Func-count':^12} {'x':^12} {'f(x)': ^12}") 

2469 print(f"{funcalls:^12g} {x:^12.6g} {fx:^12.6g}") 

2470 

2471 while (iter < self.maxiter): 

2472 tol1 = self.tol * np.abs(x) + _mintol 

2473 tol2 = 2.0 * tol1 

2474 xmid = 0.5 * (a + b) 

2475 # check for convergence 

2476 if np.abs(x - xmid) < (tol2 - 0.5 * (b - a)): 

2477 break 

2478 # XXX In the first iteration, rat is only bound in the true case 

2479 # of this conditional. This used to cause an UnboundLocalError 

2480 # (gh-4140). It should be set before the if (but to what?). 

2481 if (np.abs(deltax) <= tol1): 

2482 if (x >= xmid): 

2483 deltax = a - x # do a golden section step 

2484 else: 

2485 deltax = b - x 

2486 rat = _cg * deltax 

2487 else: # do a parabolic step 

2488 tmp1 = (x - w) * (fx - fv) 

2489 tmp2 = (x - v) * (fx - fw) 

2490 p = (x - v) * tmp2 - (x - w) * tmp1 

2491 tmp2 = 2.0 * (tmp2 - tmp1) 

2492 if (tmp2 > 0.0): 

2493 p = -p 

2494 tmp2 = np.abs(tmp2) 

2495 dx_temp = deltax 

2496 deltax = rat 

2497 # check parabolic fit 

2498 if ((p > tmp2 * (a - x)) and (p < tmp2 * (b - x)) and 

2499 (np.abs(p) < np.abs(0.5 * tmp2 * dx_temp))): 

2500 rat = p * 1.0 / tmp2 # if parabolic step is useful. 

2501 u = x + rat 

2502 if ((u - a) < tol2 or (b - u) < tol2): 

2503 if xmid - x >= 0: 

2504 rat = tol1 

2505 else: 

2506 rat = -tol1 

2507 else: 

2508 if (x >= xmid): 

2509 deltax = a - x # if it's not do a golden section step 

2510 else: 

2511 deltax = b - x 

2512 rat = _cg * deltax 

2513 

2514 if (np.abs(rat) < tol1): # update by at least tol1 

2515 if rat >= 0: 

2516 u = x + tol1 

2517 else: 

2518 u = x - tol1 

2519 else: 

2520 u = x + rat 

2521 fu = func(*((u,) + self.args)) # calculate new output value 

2522 funcalls += 1 

2523 

2524 if (fu > fx): # if it's bigger than current 

2525 if (u < x): 

2526 a = u 

2527 else: 

2528 b = u 

2529 if (fu <= fw) or (w == x): 

2530 v = w 

2531 w = u 

2532 fv = fw 

2533 fw = fu 

2534 elif (fu <= fv) or (v == x) or (v == w): 

2535 v = u 

2536 fv = fu 

2537 else: 

2538 if (u >= x): 

2539 a = x 

2540 else: 

2541 b = x 

2542 v = w 

2543 w = x 

2544 x = u 

2545 fv = fw 

2546 fw = fx 

2547 fx = fu 

2548 

2549 if self.disp > 2: 

2550 print(f"{funcalls:^12g} {x:^12.6g} {fx:^12.6g}") 

2551 

2552 iter += 1 

2553 ################################# 

2554 #END CORE ALGORITHM 

2555 ################################# 

2556 

2557 self.xmin = x 

2558 self.fval = fx 

2559 self.iter = iter 

2560 self.funcalls = funcalls 

2561 

2562 def get_result(self, full_output=False): 

2563 if full_output: 

2564 return self.xmin, self.fval, self.iter, self.funcalls 

2565 else: 

2566 return self.xmin 

2567 

2568 

2569def brent(func, args=(), brack=None, tol=1.48e-8, full_output=0, maxiter=500): 

2570 """ 

2571 Given a function of one variable and a possible bracket, return 

2572 a local minimizer of the function isolated to a fractional precision 

2573 of tol. 

2574 

2575 Parameters 

2576 ---------- 

2577 func : callable f(x,*args) 

2578 Objective function. 

2579 args : tuple, optional 

2580 Additional arguments (if present). 

2581 brack : tuple, optional 

2582 Either a triple ``(xa, xb, xc)`` satisfying ``xa < xb < xc`` and 

2583 ``func(xb) < func(xa) and func(xb) < func(xc)``, or a pair 

2584 ``(xa, xb)`` to be used as initial points for a downhill bracket search 

2585 (see `scipy.optimize.bracket`). 

2586 The minimizer ``x`` will not necessarily satisfy ``xa <= x <= xb``. 

2587 tol : float, optional 

2588 Relative error in solution `xopt` acceptable for convergence. 

2589 full_output : bool, optional 

2590 If True, return all output args (xmin, fval, iter, 

2591 funcalls). 

2592 maxiter : int, optional 

2593 Maximum number of iterations in solution. 

2594 

2595 Returns 

2596 ------- 

2597 xmin : ndarray 

2598 Optimum point. 

2599 fval : float 

2600 (Optional output) Optimum function value. 

2601 iter : int 

2602 (Optional output) Number of iterations. 

2603 funcalls : int 

2604 (Optional output) Number of objective function evaluations made. 

2605 

2606 See also 

2607 -------- 

2608 minimize_scalar: Interface to minimization algorithms for scalar 

2609 univariate functions. See the 'Brent' `method` in particular. 

2610 

2611 Notes 

2612 ----- 

2613 Uses inverse parabolic interpolation when possible to speed up 

2614 convergence of golden section method. 

2615 

2616 Does not ensure that the minimum lies in the range specified by 

2617 `brack`. See `scipy.optimize.fminbound`. 

2618 

2619 Examples 

2620 -------- 

2621 We illustrate the behaviour of the function when `brack` is of 

2622 size 2 and 3 respectively. In the case where `brack` is of the 

2623 form ``(xa, xb)``, we can see for the given values, the output does 

2624 not necessarily lie in the range ``(xa, xb)``. 

2625 

2626 >>> def f(x): 

2627 ... return (x-1)**2 

2628 

2629 >>> from scipy import optimize 

2630 

2631 >>> minimizer = optimize.brent(f, brack=(1, 2)) 

2632 >>> minimizer 

2633 1 

2634 >>> res = optimize.brent(f, brack=(-1, 0.5, 2), full_output=True) 

2635 >>> xmin, fval, iter, funcalls = res 

2636 >>> f(xmin), fval 

2637 (0.0, 0.0) 

2638 

2639 """ 

2640 options = {'xtol': tol, 

2641 'maxiter': maxiter} 

2642 res = _minimize_scalar_brent(func, brack, args, **options) 

2643 if full_output: 

2644 return res['x'], res['fun'], res['nit'], res['nfev'] 

2645 else: 

2646 return res['x'] 

2647 

2648 

2649def _minimize_scalar_brent(func, brack=None, args=(), xtol=1.48e-8, 

2650 maxiter=500, disp=0, 

2651 **unknown_options): 

2652 """ 

2653 Options 

2654 ------- 

2655 maxiter : int 

2656 Maximum number of iterations to perform. 

2657 xtol : float 

2658 Relative error in solution `xopt` acceptable for convergence. 

2659 disp: int, optional 

2660 If non-zero, print messages. 

2661 0 : no message printing. 

2662 1 : non-convergence notification messages only. 

2663 2 : print a message on convergence too. 

2664 3 : print iteration results. 

2665 Notes 

2666 ----- 

2667 Uses inverse parabolic interpolation when possible to speed up 

2668 convergence of golden section method. 

2669 

2670 """ 

2671 _check_unknown_options(unknown_options) 

2672 tol = xtol 

2673 if tol < 0: 

2674 raise ValueError('tolerance should be >= 0, got %r' % tol) 

2675 

2676 brent = Brent(func=func, args=args, tol=tol, 

2677 full_output=True, maxiter=maxiter, disp=disp) 

2678 brent.set_bracket(brack) 

2679 brent.optimize() 

2680 x, fval, nit, nfev = brent.get_result(full_output=True) 

2681 

2682 success = nit < maxiter and not (np.isnan(x) or np.isnan(fval)) 

2683 

2684 if success: 

2685 message = ("\nOptimization terminated successfully;\n" 

2686 "The returned value satisfies the termination criteria\n" 

2687 f"(using xtol = {xtol} )") 

2688 else: 

2689 if nit >= maxiter: 

2690 message = "\nMaximum number of iterations exceeded" 

2691 if np.isnan(x) or np.isnan(fval): 

2692 message = f"{_status_message['nan']}" 

2693 

2694 if disp: 

2695 _print_success_message_or_warn(not success, message) 

2696 

2697 return OptimizeResult(fun=fval, x=x, nit=nit, nfev=nfev, 

2698 success=success, message=message) 

2699 

2700 

2701def golden(func, args=(), brack=None, tol=_epsilon, 

2702 full_output=0, maxiter=5000): 

2703 """ 

2704 Return the minimizer of a function of one variable using the golden section 

2705 method. 

2706 

2707 Given a function of one variable and a possible bracketing interval, 

2708 return a minimizer of the function isolated to a fractional precision of 

2709 tol. 

2710 

2711 Parameters 

2712 ---------- 

2713 func : callable func(x,*args) 

2714 Objective function to minimize. 

2715 args : tuple, optional 

2716 Additional arguments (if present), passed to func. 

2717 brack : tuple, optional 

2718 Either a triple ``(xa, xb, xc)`` where ``xa < xb < xc`` and 

2719 ``func(xb) < func(xa) and func(xb) < func(xc)``, or a pair (xa, xb) 

2720 to be used as initial points for a downhill bracket search (see 

2721 `scipy.optimize.bracket`). 

2722 The minimizer ``x`` will not necessarily satisfy ``xa <= x <= xb``. 

2723 tol : float, optional 

2724 x tolerance stop criterion 

2725 full_output : bool, optional 

2726 If True, return optional outputs. 

2727 maxiter : int 

2728 Maximum number of iterations to perform. 

2729 

2730 Returns 

2731 ------- 

2732 xmin : ndarray 

2733 Optimum point. 

2734 fval : float 

2735 (Optional output) Optimum function value. 

2736 funcalls : int 

2737 (Optional output) Number of objective function evaluations made. 

2738 

2739 See also 

2740 -------- 

2741 minimize_scalar: Interface to minimization algorithms for scalar 

2742 univariate functions. See the 'Golden' `method` in particular. 

2743 

2744 Notes 

2745 ----- 

2746 Uses analog of bisection method to decrease the bracketed 

2747 interval. 

2748 

2749 Examples 

2750 -------- 

2751 We illustrate the behaviour of the function when `brack` is of 

2752 size 2 and 3, respectively. In the case where `brack` is of the 

2753 form (xa,xb), we can see for the given values, the output need 

2754 not necessarily lie in the range ``(xa, xb)``. 

2755 

2756 >>> def f(x): 

2757 ... return (x-1)**2 

2758 

2759 >>> from scipy import optimize 

2760 

2761 >>> minimizer = optimize.golden(f, brack=(1, 2)) 

2762 >>> minimizer 

2763 1 

2764 >>> res = optimize.golden(f, brack=(-1, 0.5, 2), full_output=True) 

2765 >>> xmin, fval, funcalls = res 

2766 >>> f(xmin), fval 

2767 (9.925165290385052e-18, 9.925165290385052e-18) 

2768 

2769 """ 

2770 options = {'xtol': tol, 'maxiter': maxiter} 

2771 res = _minimize_scalar_golden(func, brack, args, **options) 

2772 if full_output: 

2773 return res['x'], res['fun'], res['nfev'] 

2774 else: 

2775 return res['x'] 

2776 

2777 

2778def _minimize_scalar_golden(func, brack=None, args=(), 

2779 xtol=_epsilon, maxiter=5000, disp=0, 

2780 **unknown_options): 

2781 """ 

2782 Options 

2783 ------- 

2784 xtol : float 

2785 Relative error in solution `xopt` acceptable for convergence. 

2786 maxiter : int 

2787 Maximum number of iterations to perform. 

2788 disp: int, optional 

2789 If non-zero, print messages. 

2790 0 : no message printing. 

2791 1 : non-convergence notification messages only. 

2792 2 : print a message on convergence too. 

2793 3 : print iteration results. 

2794 """ 

2795 _check_unknown_options(unknown_options) 

2796 tol = xtol 

2797 if brack is None: 

2798 xa, xb, xc, fa, fb, fc, funcalls = bracket(func, args=args) 

2799 elif len(brack) == 2: 

2800 xa, xb, xc, fa, fb, fc, funcalls = bracket(func, xa=brack[0], 

2801 xb=brack[1], args=args) 

2802 elif len(brack) == 3: 

2803 xa, xb, xc = brack 

2804 if (xa > xc): # swap so xa < xc can be assumed 

2805 xc, xa = xa, xc 

2806 if not ((xa < xb) and (xb < xc)): 

2807 raise ValueError( 

2808 "Bracketing values (xa, xb, xc) do not" 

2809 " fulfill this requirement: (xa < xb) and (xb < xc)" 

2810 ) 

2811 fa = func(*((xa,) + args)) 

2812 fb = func(*((xb,) + args)) 

2813 fc = func(*((xc,) + args)) 

2814 if not ((fb < fa) and (fb < fc)): 

2815 raise ValueError( 

2816 "Bracketing values (xa, xb, xc) do not fulfill" 

2817 " this requirement: (f(xb) < f(xa)) and (f(xb) < f(xc))" 

2818 ) 

2819 funcalls = 3 

2820 else: 

2821 raise ValueError("Bracketing interval must be length 2 or 3 sequence.") 

2822 

2823 _gR = 0.61803399 # golden ratio conjugate: 2.0/(1.0+sqrt(5.0)) 

2824 _gC = 1.0 - _gR 

2825 x3 = xc 

2826 x0 = xa 

2827 if (np.abs(xc - xb) > np.abs(xb - xa)): 

2828 x1 = xb 

2829 x2 = xb + _gC * (xc - xb) 

2830 else: 

2831 x2 = xb 

2832 x1 = xb - _gC * (xb - xa) 

2833 f1 = func(*((x1,) + args)) 

2834 f2 = func(*((x2,) + args)) 

2835 funcalls += 2 

2836 nit = 0 

2837 

2838 if disp > 2: 

2839 print(" ") 

2840 print(f"{'Func-count':^12} {'x':^12} {'f(x)': ^12}") 

2841 

2842 for i in range(maxiter): 

2843 if np.abs(x3 - x0) <= tol * (np.abs(x1) + np.abs(x2)): 

2844 break 

2845 if (f2 < f1): 

2846 x0 = x1 

2847 x1 = x2 

2848 x2 = _gR * x1 + _gC * x3 

2849 f1 = f2 

2850 f2 = func(*((x2,) + args)) 

2851 else: 

2852 x3 = x2 

2853 x2 = x1 

2854 x1 = _gR * x2 + _gC * x0 

2855 f2 = f1 

2856 f1 = func(*((x1,) + args)) 

2857 funcalls += 1 

2858 if disp > 2: 

2859 if (f1 < f2): 

2860 xmin, fval = x1, f1 

2861 else: 

2862 xmin, fval = x2, f2 

2863 print(f"{funcalls:^12g} {xmin:^12.6g} {fval:^12.6g}") 

2864 

2865 nit += 1 

2866 # end of iteration loop 

2867 

2868 if (f1 < f2): 

2869 xmin = x1 

2870 fval = f1 

2871 else: 

2872 xmin = x2 

2873 fval = f2 

2874 

2875 success = nit < maxiter and not (np.isnan(fval) or np.isnan(xmin)) 

2876 

2877 if success: 

2878 message = ("\nOptimization terminated successfully;\n" 

2879 "The returned value satisfies the termination criteria\n" 

2880 f"(using xtol = {xtol} )") 

2881 else: 

2882 if nit >= maxiter: 

2883 message = "\nMaximum number of iterations exceeded" 

2884 if np.isnan(xmin) or np.isnan(fval): 

2885 message = f"{_status_message['nan']}" 

2886 

2887 if disp: 

2888 _print_success_message_or_warn(not success, message) 

2889 

2890 return OptimizeResult(fun=fval, nfev=funcalls, x=xmin, nit=nit, 

2891 success=success, message=message) 

2892 

2893 

2894def bracket(func, xa=0.0, xb=1.0, args=(), grow_limit=110.0, maxiter=1000): 

2895 """ 

2896 Bracket the minimum of a function. 

2897 

2898 Given a function and distinct initial points, search in the 

2899 downhill direction (as defined by the initial points) and return 

2900 three points that bracket the minimum of the function. 

2901 

2902 Parameters 

2903 ---------- 

2904 func : callable f(x,*args) 

2905 Objective function to minimize. 

2906 xa, xb : float, optional 

2907 Initial points. Defaults `xa` to 0.0, and `xb` to 1.0. 

2908 A local minimum need not be contained within this interval. 

2909 args : tuple, optional 

2910 Additional arguments (if present), passed to `func`. 

2911 grow_limit : float, optional 

2912 Maximum grow limit. Defaults to 110.0 

2913 maxiter : int, optional 

2914 Maximum number of iterations to perform. Defaults to 1000. 

2915 

2916 Returns 

2917 ------- 

2918 xa, xb, xc : float 

2919 Final points of the bracket. 

2920 fa, fb, fc : float 

2921 Objective function values at the bracket points. 

2922 funcalls : int 

2923 Number of function evaluations made. 

2924 

2925 Raises 

2926 ------ 

2927 BracketError 

2928 If no valid bracket is found before the algorithm terminates. 

2929 See notes for conditions of a valid bracket. 

2930 

2931 Notes 

2932 ----- 

2933 The algorithm attempts to find three strictly ordered points (i.e. 

2934 :math:`x_a < x_b < x_c` or :math:`x_c < x_b < x_a`) satisfying 

2935 :math:`f(x_b) ≤ f(x_a)` and :math:`f(x_b) ≤ f(x_c)`, where one of the 

2936 inequalities must be satistfied strictly and all :math:`x_i` must be 

2937 finite. 

2938 

2939 Examples 

2940 -------- 

2941 This function can find a downward convex region of a function: 

2942 

2943 >>> import numpy as np 

2944 >>> import matplotlib.pyplot as plt 

2945 >>> from scipy.optimize import bracket 

2946 >>> def f(x): 

2947 ... return 10*x**2 + 3*x + 5 

2948 >>> x = np.linspace(-2, 2) 

2949 >>> y = f(x) 

2950 >>> init_xa, init_xb = 0.1, 1 

2951 >>> xa, xb, xc, fa, fb, fc, funcalls = bracket(f, xa=init_xa, xb=init_xb) 

2952 >>> plt.axvline(x=init_xa, color="k", linestyle="--") 

2953 >>> plt.axvline(x=init_xb, color="k", linestyle="--") 

2954 >>> plt.plot(x, y, "-k") 

2955 >>> plt.plot(xa, fa, "bx") 

2956 >>> plt.plot(xb, fb, "rx") 

2957 >>> plt.plot(xc, fc, "bx") 

2958 >>> plt.show() 

2959 

2960 Note that both initial points were to the right of the minimum, and the 

2961 third point was found in the "downhill" direction: the direction 

2962 in which the function appeared to be decreasing (to the left). 

2963 The final points are strictly ordered, and the function value 

2964 at the middle point is less than the function values at the endpoints; 

2965 it follows that a minimum must lie within the bracket. 

2966 

2967 """ 

2968 _gold = 1.618034 # golden ratio: (1.0+sqrt(5.0))/2.0 

2969 _verysmall_num = 1e-21 

2970 # convert to numpy floats if not already 

2971 xa, xb = np.asarray([xa, xb]) 

2972 fa = func(*(xa,) + args) 

2973 fb = func(*(xb,) + args) 

2974 if (fa < fb): # Switch so fa > fb 

2975 xa, xb = xb, xa 

2976 fa, fb = fb, fa 

2977 xc = xb + _gold * (xb - xa) 

2978 fc = func(*((xc,) + args)) 

2979 funcalls = 3 

2980 iter = 0 

2981 while (fc < fb): 

2982 tmp1 = (xb - xa) * (fb - fc) 

2983 tmp2 = (xb - xc) * (fb - fa) 

2984 val = tmp2 - tmp1 

2985 if np.abs(val) < _verysmall_num: 

2986 denom = 2.0 * _verysmall_num 

2987 else: 

2988 denom = 2.0 * val 

2989 w = xb - ((xb - xc) * tmp2 - (xb - xa) * tmp1) / denom 

2990 wlim = xb + grow_limit * (xc - xb) 

2991 msg = ("No valid bracket was found before the iteration limit was " 

2992 "reached. Consider trying different initial points or " 

2993 "increasing `maxiter`.") 

2994 if iter > maxiter: 

2995 raise RuntimeError(msg) 

2996 iter += 1 

2997 if (w - xc) * (xb - w) > 0.0: 

2998 fw = func(*((w,) + args)) 

2999 funcalls += 1 

3000 if (fw < fc): 

3001 xa = xb 

3002 xb = w 

3003 fa = fb 

3004 fb = fw 

3005 break 

3006 elif (fw > fb): 

3007 xc = w 

3008 fc = fw 

3009 break 

3010 w = xc + _gold * (xc - xb) 

3011 fw = func(*((w,) + args)) 

3012 funcalls += 1 

3013 elif (w - wlim)*(wlim - xc) >= 0.0: 

3014 w = wlim 

3015 fw = func(*((w,) + args)) 

3016 funcalls += 1 

3017 elif (w - wlim)*(xc - w) > 0.0: 

3018 fw = func(*((w,) + args)) 

3019 funcalls += 1 

3020 if (fw < fc): 

3021 xb = xc 

3022 xc = w 

3023 w = xc + _gold * (xc - xb) 

3024 fb = fc 

3025 fc = fw 

3026 fw = func(*((w,) + args)) 

3027 funcalls += 1 

3028 else: 

3029 w = xc + _gold * (xc - xb) 

3030 fw = func(*((w,) + args)) 

3031 funcalls += 1 

3032 xa = xb 

3033 xb = xc 

3034 xc = w 

3035 fa = fb 

3036 fb = fc 

3037 fc = fw 

3038 

3039 # three conditions for a valid bracket 

3040 cond1 = (fb < fc and fb <= fa) or (fb < fa and fb <= fc) 

3041 cond2 = (xa < xb < xc or xc < xb < xa) 

3042 cond3 = np.isfinite(xa) and np.isfinite(xb) and np.isfinite(xc) 

3043 msg = ("The algorithm terminated without finding a valid bracket. " 

3044 "Consider trying different initial points.") 

3045 if not (cond1 and cond2 and cond3): 

3046 e = BracketError(msg) 

3047 e.data = (xa, xb, xc, fa, fb, fc, funcalls) 

3048 raise e 

3049 

3050 return xa, xb, xc, fa, fb, fc, funcalls 

3051 

3052 

3053class BracketError(RuntimeError): 

3054 pass 

3055 

3056 

3057def _recover_from_bracket_error(solver, fun, bracket, args, **options): 

3058 # `bracket` was originally written without checking whether the resulting 

3059 # bracket is valid. `brent` and `golden` built on top of it without 

3060 # checking the returned bracket for validity, and their output can be 

3061 # incorrect without warning/error if the original bracket is invalid. 

3062 # gh-14858 noticed the problem, and the following is the desired 

3063 # behavior: 

3064 # - `scipy.optimize.bracket`, `scipy.optimize.brent`, and 

3065 # `scipy.optimize.golden` should raise an error if the bracket is 

3066 # invalid, as opposed to silently returning garbage 

3067 # - `scipy.optimize.minimize_scalar` should return with `success=False` 

3068 # and other information 

3069 # The changes that would be required to achieve this the traditional 

3070 # way (`return`ing all the required information from bracket all the way 

3071 # up to `minimizer_scalar`) are extensive and invasive. (See a6aa40d.) 

3072 # We can achieve the same thing by raising the error in `bracket`, but 

3073 # storing the information needed by `minimize_scalar` in the error object, 

3074 # and intercepting it here. 

3075 try: 

3076 res = solver(fun, bracket, args, **options) 

3077 except BracketError as e: 

3078 msg = str(e) 

3079 xa, xb, xc, fa, fb, fc, funcalls = e.data 

3080 xs, fs = [xa, xb, xc], [fa, fb, fc] 

3081 if np.any(np.isnan([xs, fs])): 

3082 x, fun = np.nan, np.nan 

3083 else: 

3084 imin = np.argmin(fs) 

3085 x, fun = xs[imin], fs[imin] 

3086 return OptimizeResult(fun=fun, nfev=funcalls, x=x, 

3087 nit=0, success=False, message=msg) 

3088 return res 

3089 

3090 

3091def _line_for_search(x0, alpha, lower_bound, upper_bound): 

3092 """ 

3093 Given a parameter vector ``x0`` with length ``n`` and a direction 

3094 vector ``alpha`` with length ``n``, and lower and upper bounds on 

3095 each of the ``n`` parameters, what are the bounds on a scalar 

3096 ``l`` such that ``lower_bound <= x0 + alpha * l <= upper_bound``. 

3097 

3098 

3099 Parameters 

3100 ---------- 

3101 x0 : np.array. 

3102 The vector representing the current location. 

3103 Note ``np.shape(x0) == (n,)``. 

3104 alpha : np.array. 

3105 The vector representing the direction. 

3106 Note ``np.shape(alpha) == (n,)``. 

3107 lower_bound : np.array. 

3108 The lower bounds for each parameter in ``x0``. If the ``i``th 

3109 parameter in ``x0`` is unbounded below, then ``lower_bound[i]`` 

3110 should be ``-np.inf``. 

3111 Note ``np.shape(lower_bound) == (n,)``. 

3112 upper_bound : np.array. 

3113 The upper bounds for each parameter in ``x0``. If the ``i``th 

3114 parameter in ``x0`` is unbounded above, then ``upper_bound[i]`` 

3115 should be ``np.inf``. 

3116 Note ``np.shape(upper_bound) == (n,)``. 

3117 

3118 Returns 

3119 ------- 

3120 res : tuple ``(lmin, lmax)`` 

3121 The bounds for ``l`` such that 

3122 ``lower_bound[i] <= x0[i] + alpha[i] * l <= upper_bound[i]`` 

3123 for all ``i``. 

3124 

3125 """ 

3126 # get nonzero indices of alpha so we don't get any zero division errors. 

3127 # alpha will not be all zero, since it is called from _linesearch_powell 

3128 # where we have a check for this. 

3129 nonzero, = alpha.nonzero() 

3130 lower_bound, upper_bound = lower_bound[nonzero], upper_bound[nonzero] 

3131 x0, alpha = x0[nonzero], alpha[nonzero] 

3132 low = (lower_bound - x0) / alpha 

3133 high = (upper_bound - x0) / alpha 

3134 

3135 # positive and negative indices 

3136 pos = alpha > 0 

3137 

3138 lmin_pos = np.where(pos, low, 0) 

3139 lmin_neg = np.where(pos, 0, high) 

3140 lmax_pos = np.where(pos, high, 0) 

3141 lmax_neg = np.where(pos, 0, low) 

3142 

3143 lmin = np.max(lmin_pos + lmin_neg) 

3144 lmax = np.min(lmax_pos + lmax_neg) 

3145 

3146 # if x0 is outside the bounds, then it is possible that there is 

3147 # no way to get back in the bounds for the parameters being updated 

3148 # with the current direction alpha. 

3149 # when this happens, lmax < lmin. 

3150 # If this is the case, then we can just return (0, 0) 

3151 return (lmin, lmax) if lmax >= lmin else (0, 0) 

3152 

3153 

3154def _linesearch_powell(func, p, xi, tol=1e-3, 

3155 lower_bound=None, upper_bound=None, fval=None): 

3156 """Line-search algorithm using fminbound. 

3157 

3158 Find the minimium of the function ``func(x0 + alpha*direc)``. 

3159 

3160 lower_bound : np.array. 

3161 The lower bounds for each parameter in ``x0``. If the ``i``th 

3162 parameter in ``x0`` is unbounded below, then ``lower_bound[i]`` 

3163 should be ``-np.inf``. 

3164 Note ``np.shape(lower_bound) == (n,)``. 

3165 upper_bound : np.array. 

3166 The upper bounds for each parameter in ``x0``. If the ``i``th 

3167 parameter in ``x0`` is unbounded above, then ``upper_bound[i]`` 

3168 should be ``np.inf``. 

3169 Note ``np.shape(upper_bound) == (n,)``. 

3170 fval : number. 

3171 ``fval`` is equal to ``func(p)``, the idea is just to avoid 

3172 recomputing it so we can limit the ``fevals``. 

3173 

3174 """ 

3175 def myfunc(alpha): 

3176 return func(p + alpha*xi) 

3177 

3178 # if xi is zero, then don't optimize 

3179 if not np.any(xi): 

3180 return ((fval, p, xi) if fval is not None else (func(p), p, xi)) 

3181 elif lower_bound is None and upper_bound is None: 

3182 # non-bounded minimization 

3183 res = _recover_from_bracket_error(_minimize_scalar_brent, 

3184 myfunc, None, tuple(), xtol=tol) 

3185 alpha_min, fret = res.x, res.fun 

3186 xi = alpha_min * xi 

3187 return squeeze(fret), p + xi, xi 

3188 else: 

3189 bound = _line_for_search(p, xi, lower_bound, upper_bound) 

3190 if np.isneginf(bound[0]) and np.isposinf(bound[1]): 

3191 # equivalent to unbounded 

3192 return _linesearch_powell(func, p, xi, fval=fval, tol=tol) 

3193 elif not np.isneginf(bound[0]) and not np.isposinf(bound[1]): 

3194 # we can use a bounded scalar minimization 

3195 res = _minimize_scalar_bounded(myfunc, bound, xatol=tol / 100) 

3196 xi = res.x * xi 

3197 return squeeze(res.fun), p + xi, xi 

3198 else: 

3199 # only bounded on one side. use the tangent function to convert 

3200 # the infinity bound to a finite bound. The new bounded region 

3201 # is a subregion of the region bounded by -np.pi/2 and np.pi/2. 

3202 bound = np.arctan(bound[0]), np.arctan(bound[1]) 

3203 res = _minimize_scalar_bounded( 

3204 lambda x: myfunc(np.tan(x)), 

3205 bound, 

3206 xatol=tol / 100) 

3207 xi = np.tan(res.x) * xi 

3208 return squeeze(res.fun), p + xi, xi 

3209 

3210 

3211def fmin_powell(func, x0, args=(), xtol=1e-4, ftol=1e-4, maxiter=None, 

3212 maxfun=None, full_output=0, disp=1, retall=0, callback=None, 

3213 direc=None): 

3214 """ 

3215 Minimize a function using modified Powell's method. 

3216 

3217 This method only uses function values, not derivatives. 

3218 

3219 Parameters 

3220 ---------- 

3221 func : callable f(x,*args) 

3222 Objective function to be minimized. 

3223 x0 : ndarray 

3224 Initial guess. 

3225 args : tuple, optional 

3226 Extra arguments passed to func. 

3227 xtol : float, optional 

3228 Line-search error tolerance. 

3229 ftol : float, optional 

3230 Relative error in ``func(xopt)`` acceptable for convergence. 

3231 maxiter : int, optional 

3232 Maximum number of iterations to perform. 

3233 maxfun : int, optional 

3234 Maximum number of function evaluations to make. 

3235 full_output : bool, optional 

3236 If True, ``fopt``, ``xi``, ``direc``, ``iter``, ``funcalls``, and 

3237 ``warnflag`` are returned. 

3238 disp : bool, optional 

3239 If True, print convergence messages. 

3240 retall : bool, optional 

3241 If True, return a list of the solution at each iteration. 

3242 callback : callable, optional 

3243 An optional user-supplied function, called after each 

3244 iteration. Called as ``callback(xk)``, where ``xk`` is the 

3245 current parameter vector. 

3246 direc : ndarray, optional 

3247 Initial fitting step and parameter order set as an (N, N) array, where N 

3248 is the number of fitting parameters in `x0`. Defaults to step size 1.0 

3249 fitting all parameters simultaneously (``np.eye((N, N))``). To 

3250 prevent initial consideration of values in a step or to change initial 

3251 step size, set to 0 or desired step size in the Jth position in the Mth 

3252 block, where J is the position in `x0` and M is the desired evaluation 

3253 step, with steps being evaluated in index order. Step size and ordering 

3254 will change freely as minimization proceeds. 

3255 

3256 Returns 

3257 ------- 

3258 xopt : ndarray 

3259 Parameter which minimizes `func`. 

3260 fopt : number 

3261 Value of function at minimum: ``fopt = func(xopt)``. 

3262 direc : ndarray 

3263 Current direction set. 

3264 iter : int 

3265 Number of iterations. 

3266 funcalls : int 

3267 Number of function calls made. 

3268 warnflag : int 

3269 Integer warning flag: 

3270 1 : Maximum number of function evaluations. 

3271 2 : Maximum number of iterations. 

3272 3 : NaN result encountered. 

3273 4 : The result is out of the provided bounds. 

3274 allvecs : list 

3275 List of solutions at each iteration. 

3276 

3277 See also 

3278 -------- 

3279 minimize: Interface to unconstrained minimization algorithms for 

3280 multivariate functions. See the 'Powell' method in particular. 

3281 

3282 Notes 

3283 ----- 

3284 Uses a modification of Powell's method to find the minimum of 

3285 a function of N variables. Powell's method is a conjugate 

3286 direction method. 

3287 

3288 The algorithm has two loops. The outer loop merely iterates over the inner 

3289 loop. The inner loop minimizes over each current direction in the direction 

3290 set. At the end of the inner loop, if certain conditions are met, the 

3291 direction that gave the largest decrease is dropped and replaced with the 

3292 difference between the current estimated x and the estimated x from the 

3293 beginning of the inner-loop. 

3294 

3295 The technical conditions for replacing the direction of greatest 

3296 increase amount to checking that 

3297 

3298 1. No further gain can be made along the direction of greatest increase 

3299 from that iteration. 

3300 2. The direction of greatest increase accounted for a large sufficient 

3301 fraction of the decrease in the function value from that iteration of 

3302 the inner loop. 

3303 

3304 References 

3305 ---------- 

3306 Powell M.J.D. (1964) An efficient method for finding the minimum of a 

3307 function of several variables without calculating derivatives, 

3308 Computer Journal, 7 (2):155-162. 

3309 

3310 Press W., Teukolsky S.A., Vetterling W.T., and Flannery B.P.: 

3311 Numerical Recipes (any edition), Cambridge University Press 

3312 

3313 Examples 

3314 -------- 

3315 >>> def f(x): 

3316 ... return x**2 

3317 

3318 >>> from scipy import optimize 

3319 

3320 >>> minimum = optimize.fmin_powell(f, -1) 

3321 Optimization terminated successfully. 

3322 Current function value: 0.000000 

3323 Iterations: 2 

3324 Function evaluations: 16 

3325 >>> minimum 

3326 array(0.0) 

3327 

3328 """ 

3329 opts = {'xtol': xtol, 

3330 'ftol': ftol, 

3331 'maxiter': maxiter, 

3332 'maxfev': maxfun, 

3333 'disp': disp, 

3334 'direc': direc, 

3335 'return_all': retall} 

3336 

3337 callback = _wrap_callback(callback) 

3338 res = _minimize_powell(func, x0, args, callback=callback, **opts) 

3339 

3340 if full_output: 

3341 retlist = (res['x'], res['fun'], res['direc'], res['nit'], 

3342 res['nfev'], res['status']) 

3343 if retall: 

3344 retlist += (res['allvecs'], ) 

3345 return retlist 

3346 else: 

3347 if retall: 

3348 return res['x'], res['allvecs'] 

3349 else: 

3350 return res['x'] 

3351 

3352 

3353def _minimize_powell(func, x0, args=(), callback=None, bounds=None, 

3354 xtol=1e-4, ftol=1e-4, maxiter=None, maxfev=None, 

3355 disp=False, direc=None, return_all=False, 

3356 **unknown_options): 

3357 """ 

3358 Minimization of scalar function of one or more variables using the 

3359 modified Powell algorithm. 

3360 

3361 Parameters 

3362 ---------- 

3363 fun : callable 

3364 The objective function to be minimized. 

3365 

3366 ``fun(x, *args) -> float`` 

3367 

3368 where ``x`` is a 1-D array with shape (n,) and ``args`` 

3369 is a tuple of the fixed parameters needed to completely 

3370 specify the function. 

3371 x0 : ndarray, shape (n,) 

3372 Initial guess. Array of real elements of size (n,), 

3373 where ``n`` is the number of independent variables. 

3374 args : tuple, optional 

3375 Extra arguments passed to the objective function and its 

3376 derivatives (`fun`, `jac` and `hess` functions). 

3377 method : str or callable, optional 

3378 The present documentation is specific to ``method='powell'``, but other 

3379 options are available. See documentation for `scipy.optimize.minimize`. 

3380 bounds : sequence or `Bounds`, optional 

3381 Bounds on decision variables. There are two ways to specify the bounds: 

3382 

3383 1. Instance of `Bounds` class. 

3384 2. Sequence of ``(min, max)`` pairs for each element in `x`. None 

3385 is used to specify no bound. 

3386 

3387 If bounds are not provided, then an unbounded line search will be used. 

3388 If bounds are provided and the initial guess is within the bounds, then 

3389 every function evaluation throughout the minimization procedure will be 

3390 within the bounds. If bounds are provided, the initial guess is outside 

3391 the bounds, and `direc` is full rank (or left to default), then some 

3392 function evaluations during the first iteration may be outside the 

3393 bounds, but every function evaluation after the first iteration will be 

3394 within the bounds. If `direc` is not full rank, then some parameters 

3395 may not be optimized and the solution is not guaranteed to be within 

3396 the bounds. 

3397 

3398 options : dict, optional 

3399 A dictionary of solver options. All methods accept the following 

3400 generic options: 

3401 

3402 maxiter : int 

3403 Maximum number of iterations to perform. Depending on the 

3404 method each iteration may use several function evaluations. 

3405 disp : bool 

3406 Set to True to print convergence messages. 

3407 

3408 See method-specific options for ``method='powell'`` below. 

3409 callback : callable, optional 

3410 Called after each iteration. The signature is: 

3411 

3412 ``callback(xk)`` 

3413 

3414 where ``xk`` is the current parameter vector. 

3415 

3416 Returns 

3417 ------- 

3418 res : OptimizeResult 

3419 The optimization result represented as a ``OptimizeResult`` object. 

3420 Important attributes are: ``x`` the solution array, ``success`` a 

3421 Boolean flag indicating if the optimizer exited successfully and 

3422 ``message`` which describes the cause of the termination. See 

3423 `OptimizeResult` for a description of other attributes. 

3424 

3425 Options 

3426 ------- 

3427 disp : bool 

3428 Set to True to print convergence messages. 

3429 xtol : float 

3430 Relative error in solution `xopt` acceptable for convergence. 

3431 ftol : float 

3432 Relative error in ``fun(xopt)`` acceptable for convergence. 

3433 maxiter, maxfev : int 

3434 Maximum allowed number of iterations and function evaluations. 

3435 Will default to ``N*1000``, where ``N`` is the number of 

3436 variables, if neither `maxiter` or `maxfev` is set. If both 

3437 `maxiter` and `maxfev` are set, minimization will stop at the 

3438 first reached. 

3439 direc : ndarray 

3440 Initial set of direction vectors for the Powell method. 

3441 return_all : bool, optional 

3442 Set to True to return a list of the best solution at each of the 

3443 iterations. 

3444 """ 

3445 _check_unknown_options(unknown_options) 

3446 maxfun = maxfev 

3447 retall = return_all 

3448 

3449 x = asarray(x0).flatten() 

3450 if retall: 

3451 allvecs = [x] 

3452 N = len(x) 

3453 # If neither are set, then set both to default 

3454 if maxiter is None and maxfun is None: 

3455 maxiter = N * 1000 

3456 maxfun = N * 1000 

3457 elif maxiter is None: 

3458 # Convert remaining Nones, to np.inf, unless the other is np.inf, in 

3459 # which case use the default to avoid unbounded iteration 

3460 if maxfun == np.inf: 

3461 maxiter = N * 1000 

3462 else: 

3463 maxiter = np.inf 

3464 elif maxfun is None: 

3465 if maxiter == np.inf: 

3466 maxfun = N * 1000 

3467 else: 

3468 maxfun = np.inf 

3469 

3470 # we need to use a mutable object here that we can update in the 

3471 # wrapper function 

3472 fcalls, func = _wrap_scalar_function_maxfun_validation(func, args, maxfun) 

3473 

3474 if direc is None: 

3475 direc = eye(N, dtype=float) 

3476 else: 

3477 direc = asarray(direc, dtype=float) 

3478 if np.linalg.matrix_rank(direc) != direc.shape[0]: 

3479 warnings.warn("direc input is not full rank, some parameters may " 

3480 "not be optimized", 

3481 OptimizeWarning, 3) 

3482 

3483 if bounds is None: 

3484 # don't make these arrays of all +/- inf. because 

3485 # _linesearch_powell will do an unnecessary check of all the elements. 

3486 # just keep them None, _linesearch_powell will not have to check 

3487 # all the elements. 

3488 lower_bound, upper_bound = None, None 

3489 else: 

3490 # bounds is standardized in _minimize.py. 

3491 lower_bound, upper_bound = bounds.lb, bounds.ub 

3492 if np.any(lower_bound > x0) or np.any(x0 > upper_bound): 

3493 warnings.warn("Initial guess is not within the specified bounds", 

3494 OptimizeWarning, 3) 

3495 

3496 fval = squeeze(func(x)) 

3497 x1 = x.copy() 

3498 iter = 0 

3499 while True: 

3500 try: 

3501 fx = fval 

3502 bigind = 0 

3503 delta = 0.0 

3504 for i in range(N): 

3505 direc1 = direc[i] 

3506 fx2 = fval 

3507 fval, x, direc1 = _linesearch_powell(func, x, direc1, 

3508 tol=xtol * 100, 

3509 lower_bound=lower_bound, 

3510 upper_bound=upper_bound, 

3511 fval=fval) 

3512 if (fx2 - fval) > delta: 

3513 delta = fx2 - fval 

3514 bigind = i 

3515 iter += 1 

3516 if retall: 

3517 allvecs.append(x) 

3518 intermediate_result = OptimizeResult(x=x, fun=fval) 

3519 if _call_callback_maybe_halt(callback, intermediate_result): 

3520 break 

3521 bnd = ftol * (np.abs(fx) + np.abs(fval)) + 1e-20 

3522 if 2.0 * (fx - fval) <= bnd: 

3523 break 

3524 if fcalls[0] >= maxfun: 

3525 break 

3526 if iter >= maxiter: 

3527 break 

3528 if np.isnan(fx) and np.isnan(fval): 

3529 # Ended up in a nan-region: bail out 

3530 break 

3531 

3532 # Construct the extrapolated point 

3533 direc1 = x - x1 

3534 x1 = x.copy() 

3535 # make sure that we don't go outside the bounds when extrapolating 

3536 if lower_bound is None and upper_bound is None: 

3537 lmax = 1 

3538 else: 

3539 _, lmax = _line_for_search(x, direc1, lower_bound, upper_bound) 

3540 x2 = x + min(lmax, 1) * direc1 

3541 fx2 = squeeze(func(x2)) 

3542 

3543 if (fx > fx2): 

3544 t = 2.0*(fx + fx2 - 2.0*fval) 

3545 temp = (fx - fval - delta) 

3546 t *= temp*temp 

3547 temp = fx - fx2 

3548 t -= delta*temp*temp 

3549 if t < 0.0: 

3550 fval, x, direc1 = _linesearch_powell( 

3551 func, x, direc1, 

3552 tol=xtol * 100, 

3553 lower_bound=lower_bound, 

3554 upper_bound=upper_bound, 

3555 fval=fval 

3556 ) 

3557 if np.any(direc1): 

3558 direc[bigind] = direc[-1] 

3559 direc[-1] = direc1 

3560 except _MaxFuncCallError: 

3561 break 

3562 

3563 warnflag = 0 

3564 msg = _status_message['success'] 

3565 # out of bounds is more urgent than exceeding function evals or iters, 

3566 # but I don't want to cause inconsistencies by changing the 

3567 # established warning flags for maxfev and maxiter, so the out of bounds 

3568 # warning flag becomes 3, but is checked for first. 

3569 if bounds and (np.any(lower_bound > x) or np.any(x > upper_bound)): 

3570 warnflag = 4 

3571 msg = _status_message['out_of_bounds'] 

3572 elif fcalls[0] >= maxfun: 

3573 warnflag = 1 

3574 msg = _status_message['maxfev'] 

3575 elif iter >= maxiter: 

3576 warnflag = 2 

3577 msg = _status_message['maxiter'] 

3578 elif np.isnan(fval) or np.isnan(x).any(): 

3579 warnflag = 3 

3580 msg = _status_message['nan'] 

3581 

3582 if disp: 

3583 _print_success_message_or_warn(warnflag, msg, RuntimeWarning) 

3584 print(" Current function value: %f" % fval) 

3585 print(" Iterations: %d" % iter) 

3586 print(" Function evaluations: %d" % fcalls[0]) 

3587 

3588 result = OptimizeResult(fun=fval, direc=direc, nit=iter, nfev=fcalls[0], 

3589 status=warnflag, success=(warnflag == 0), 

3590 message=msg, x=x) 

3591 if retall: 

3592 result['allvecs'] = allvecs 

3593 return result 

3594 

3595 

3596def _endprint(x, flag, fval, maxfun, xtol, disp): 

3597 if flag == 0: 

3598 if disp > 1: 

3599 print("\nOptimization terminated successfully;\n" 

3600 "The returned value satisfies the termination criteria\n" 

3601 "(using xtol = ", xtol, ")") 

3602 return 

3603 

3604 if flag == 1: 

3605 msg = ("\nMaximum number of function evaluations exceeded --- " 

3606 "increase maxfun argument.\n") 

3607 elif flag == 2: 

3608 msg = "\n{}".format(_status_message['nan']) 

3609 

3610 _print_success_message_or_warn(flag, msg) 

3611 return 

3612 

3613 

3614def brute(func, ranges, args=(), Ns=20, full_output=0, finish=fmin, 

3615 disp=False, workers=1): 

3616 """Minimize a function over a given range by brute force. 

3617 

3618 Uses the "brute force" method, i.e., computes the function's value 

3619 at each point of a multidimensional grid of points, to find the global 

3620 minimum of the function. 

3621 

3622 The function is evaluated everywhere in the range with the datatype of the 

3623 first call to the function, as enforced by the ``vectorize`` NumPy 

3624 function. The value and type of the function evaluation returned when 

3625 ``full_output=True`` are affected in addition by the ``finish`` argument 

3626 (see Notes). 

3627 

3628 The brute force approach is inefficient because the number of grid points 

3629 increases exponentially - the number of grid points to evaluate is 

3630 ``Ns ** len(x)``. Consequently, even with coarse grid spacing, even 

3631 moderately sized problems can take a long time to run, and/or run into 

3632 memory limitations. 

3633 

3634 Parameters 

3635 ---------- 

3636 func : callable 

3637 The objective function to be minimized. Must be in the 

3638 form ``f(x, *args)``, where ``x`` is the argument in 

3639 the form of a 1-D array and ``args`` is a tuple of any 

3640 additional fixed parameters needed to completely specify 

3641 the function. 

3642 ranges : tuple 

3643 Each component of the `ranges` tuple must be either a 

3644 "slice object" or a range tuple of the form ``(low, high)``. 

3645 The program uses these to create the grid of points on which 

3646 the objective function will be computed. See `Note 2` for 

3647 more detail. 

3648 args : tuple, optional 

3649 Any additional fixed parameters needed to completely specify 

3650 the function. 

3651 Ns : int, optional 

3652 Number of grid points along the axes, if not otherwise 

3653 specified. See `Note2`. 

3654 full_output : bool, optional 

3655 If True, return the evaluation grid and the objective function's 

3656 values on it. 

3657 finish : callable, optional 

3658 An optimization function that is called with the result of brute force 

3659 minimization as initial guess. `finish` should take `func` and 

3660 the initial guess as positional arguments, and take `args` as 

3661 keyword arguments. It may additionally take `full_output` 

3662 and/or `disp` as keyword arguments. Use None if no "polishing" 

3663 function is to be used. See Notes for more details. 

3664 disp : bool, optional 

3665 Set to True to print convergence messages from the `finish` callable. 

3666 workers : int or map-like callable, optional 

3667 If `workers` is an int the grid is subdivided into `workers` 

3668 sections and evaluated in parallel (uses 

3669 `multiprocessing.Pool <multiprocessing>`). 

3670 Supply `-1` to use all cores available to the Process. 

3671 Alternatively supply a map-like callable, such as 

3672 `multiprocessing.Pool.map` for evaluating the grid in parallel. 

3673 This evaluation is carried out as ``workers(func, iterable)``. 

3674 Requires that `func` be pickleable. 

3675 

3676 .. versionadded:: 1.3.0 

3677 

3678 Returns 

3679 ------- 

3680 x0 : ndarray 

3681 A 1-D array containing the coordinates of a point at which the 

3682 objective function had its minimum value. (See `Note 1` for 

3683 which point is returned.) 

3684 fval : float 

3685 Function value at the point `x0`. (Returned when `full_output` is 

3686 True.) 

3687 grid : tuple 

3688 Representation of the evaluation grid. It has the same 

3689 length as `x0`. (Returned when `full_output` is True.) 

3690 Jout : ndarray 

3691 Function values at each point of the evaluation 

3692 grid, i.e., ``Jout = func(*grid)``. (Returned 

3693 when `full_output` is True.) 

3694 

3695 See Also 

3696 -------- 

3697 basinhopping, differential_evolution 

3698 

3699 Notes 

3700 ----- 

3701 *Note 1*: The program finds the gridpoint at which the lowest value 

3702 of the objective function occurs. If `finish` is None, that is the 

3703 point returned. When the global minimum occurs within (or not very far 

3704 outside) the grid's boundaries, and the grid is fine enough, that 

3705 point will be in the neighborhood of the global minimum. 

3706 

3707 However, users often employ some other optimization program to 

3708 "polish" the gridpoint values, i.e., to seek a more precise 

3709 (local) minimum near `brute's` best gridpoint. 

3710 The `brute` function's `finish` option provides a convenient way to do 

3711 that. Any polishing program used must take `brute's` output as its 

3712 initial guess as a positional argument, and take `brute's` input values 

3713 for `args` as keyword arguments, otherwise an error will be raised. 

3714 It may additionally take `full_output` and/or `disp` as keyword arguments. 

3715 

3716 `brute` assumes that the `finish` function returns either an 

3717 `OptimizeResult` object or a tuple in the form: 

3718 ``(xmin, Jmin, ... , statuscode)``, where ``xmin`` is the minimizing 

3719 value of the argument, ``Jmin`` is the minimum value of the objective 

3720 function, "..." may be some other returned values (which are not used 

3721 by `brute`), and ``statuscode`` is the status code of the `finish` program. 

3722 

3723 Note that when `finish` is not None, the values returned are those 

3724 of the `finish` program, *not* the gridpoint ones. Consequently, 

3725 while `brute` confines its search to the input grid points, 

3726 the `finish` program's results usually will not coincide with any 

3727 gridpoint, and may fall outside the grid's boundary. Thus, if a 

3728 minimum only needs to be found over the provided grid points, make 

3729 sure to pass in `finish=None`. 

3730 

3731 *Note 2*: The grid of points is a `numpy.mgrid` object. 

3732 For `brute` the `ranges` and `Ns` inputs have the following effect. 

3733 Each component of the `ranges` tuple can be either a slice object or a 

3734 two-tuple giving a range of values, such as (0, 5). If the component is a 

3735 slice object, `brute` uses it directly. If the component is a two-tuple 

3736 range, `brute` internally converts it to a slice object that interpolates 

3737 `Ns` points from its low-value to its high-value, inclusive. 

3738 

3739 Examples 

3740 -------- 

3741 We illustrate the use of `brute` to seek the global minimum of a function 

3742 of two variables that is given as the sum of a positive-definite 

3743 quadratic and two deep "Gaussian-shaped" craters. Specifically, define 

3744 the objective function `f` as the sum of three other functions, 

3745 ``f = f1 + f2 + f3``. We suppose each of these has a signature 

3746 ``(z, *params)``, where ``z = (x, y)``, and ``params`` and the functions 

3747 are as defined below. 

3748 

3749 >>> import numpy as np 

3750 >>> params = (2, 3, 7, 8, 9, 10, 44, -1, 2, 26, 1, -2, 0.5) 

3751 >>> def f1(z, *params): 

3752 ... x, y = z 

3753 ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params 

3754 ... return (a * x**2 + b * x * y + c * y**2 + d*x + e*y + f) 

3755 

3756 >>> def f2(z, *params): 

3757 ... x, y = z 

3758 ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params 

3759 ... return (-g*np.exp(-((x-h)**2 + (y-i)**2) / scale)) 

3760 

3761 >>> def f3(z, *params): 

3762 ... x, y = z 

3763 ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params 

3764 ... return (-j*np.exp(-((x-k)**2 + (y-l)**2) / scale)) 

3765 

3766 >>> def f(z, *params): 

3767 ... return f1(z, *params) + f2(z, *params) + f3(z, *params) 

3768 

3769 Thus, the objective function may have local minima near the minimum 

3770 of each of the three functions of which it is composed. To 

3771 use `fmin` to polish its gridpoint result, we may then continue as 

3772 follows: 

3773 

3774 >>> rranges = (slice(-4, 4, 0.25), slice(-4, 4, 0.25)) 

3775 >>> from scipy import optimize 

3776 >>> resbrute = optimize.brute(f, rranges, args=params, full_output=True, 

3777 ... finish=optimize.fmin) 

3778 >>> resbrute[0] # global minimum 

3779 array([-1.05665192, 1.80834843]) 

3780 >>> resbrute[1] # function value at global minimum 

3781 -3.4085818767 

3782 

3783 Note that if `finish` had been set to None, we would have gotten the 

3784 gridpoint [-1.0 1.75] where the rounded function value is -2.892. 

3785 

3786 """ 

3787 N = len(ranges) 

3788 if N > 40: 

3789 raise ValueError("Brute Force not possible with more " 

3790 "than 40 variables.") 

3791 lrange = list(ranges) 

3792 for k in range(N): 

3793 if not isinstance(lrange[k], slice): 

3794 if len(lrange[k]) < 3: 

3795 lrange[k] = tuple(lrange[k]) + (complex(Ns),) 

3796 lrange[k] = slice(*lrange[k]) 

3797 if (N == 1): 

3798 lrange = lrange[0] 

3799 

3800 grid = np.mgrid[lrange] 

3801 

3802 # obtain an array of parameters that is iterable by a map-like callable 

3803 inpt_shape = grid.shape 

3804 if (N > 1): 

3805 grid = np.reshape(grid, (inpt_shape[0], np.prod(inpt_shape[1:]))).T 

3806 

3807 if not np.iterable(args): 

3808 args = (args,) 

3809 

3810 wrapped_func = _Brute_Wrapper(func, args) 

3811 

3812 # iterate over input arrays, possibly in parallel 

3813 with MapWrapper(pool=workers) as mapper: 

3814 Jout = np.array(list(mapper(wrapped_func, grid))) 

3815 if (N == 1): 

3816 grid = (grid,) 

3817 Jout = np.squeeze(Jout) 

3818 elif (N > 1): 

3819 Jout = np.reshape(Jout, inpt_shape[1:]) 

3820 grid = np.reshape(grid.T, inpt_shape) 

3821 

3822 Nshape = shape(Jout) 

3823 

3824 indx = argmin(Jout.ravel(), axis=-1) 

3825 Nindx = np.empty(N, int) 

3826 xmin = np.empty(N, float) 

3827 for k in range(N - 1, -1, -1): 

3828 thisN = Nshape[k] 

3829 Nindx[k] = indx % Nshape[k] 

3830 indx = indx // thisN 

3831 for k in range(N): 

3832 xmin[k] = grid[k][tuple(Nindx)] 

3833 

3834 Jmin = Jout[tuple(Nindx)] 

3835 if (N == 1): 

3836 grid = grid[0] 

3837 xmin = xmin[0] 

3838 

3839 if callable(finish): 

3840 # set up kwargs for `finish` function 

3841 finish_args = _getfullargspec(finish).args 

3842 finish_kwargs = dict() 

3843 if 'full_output' in finish_args: 

3844 finish_kwargs['full_output'] = 1 

3845 if 'disp' in finish_args: 

3846 finish_kwargs['disp'] = disp 

3847 elif 'options' in finish_args: 

3848 # pass 'disp' as `options` 

3849 # (e.g., if `finish` is `minimize`) 

3850 finish_kwargs['options'] = {'disp': disp} 

3851 

3852 # run minimizer 

3853 res = finish(func, xmin, args=args, **finish_kwargs) 

3854 

3855 if isinstance(res, OptimizeResult): 

3856 xmin = res.x 

3857 Jmin = res.fun 

3858 success = res.success 

3859 else: 

3860 xmin = res[0] 

3861 Jmin = res[1] 

3862 success = res[-1] == 0 

3863 if not success: 

3864 if disp: 

3865 warnings.warn( 

3866 "Either final optimization did not succeed " 

3867 "or `finish` does not return `statuscode` as its last " 

3868 "argument.", RuntimeWarning, 2) 

3869 

3870 if full_output: 

3871 return xmin, Jmin, grid, Jout 

3872 else: 

3873 return xmin 

3874 

3875 

3876class _Brute_Wrapper: 

3877 """ 

3878 Object to wrap user cost function for optimize.brute, allowing picklability 

3879 """ 

3880 

3881 def __init__(self, f, args): 

3882 self.f = f 

3883 self.args = [] if args is None else args 

3884 

3885 def __call__(self, x): 

3886 # flatten needed for one dimensional case. 

3887 return self.f(np.asarray(x).flatten(), *self.args) 

3888 

3889 

3890def show_options(solver=None, method=None, disp=True): 

3891 """ 

3892 Show documentation for additional options of optimization solvers. 

3893 

3894 These are method-specific options that can be supplied through the 

3895 ``options`` dict. 

3896 

3897 Parameters 

3898 ---------- 

3899 solver : str 

3900 Type of optimization solver. One of 'minimize', 'minimize_scalar', 

3901 'root', 'root_scalar', 'linprog', or 'quadratic_assignment'. 

3902 method : str, optional 

3903 If not given, shows all methods of the specified solver. Otherwise, 

3904 show only the options for the specified method. Valid values 

3905 corresponds to methods' names of respective solver (e.g., 'BFGS' for 

3906 'minimize'). 

3907 disp : bool, optional 

3908 Whether to print the result rather than returning it. 

3909 

3910 Returns 

3911 ------- 

3912 text 

3913 Either None (for disp=True) or the text string (disp=False) 

3914 

3915 Notes 

3916 ----- 

3917 The solver-specific methods are: 

3918 

3919 `scipy.optimize.minimize` 

3920 

3921 - :ref:`Nelder-Mead <optimize.minimize-neldermead>` 

3922 - :ref:`Powell <optimize.minimize-powell>` 

3923 - :ref:`CG <optimize.minimize-cg>` 

3924 - :ref:`BFGS <optimize.minimize-bfgs>` 

3925 - :ref:`Newton-CG <optimize.minimize-newtoncg>` 

3926 - :ref:`L-BFGS-B <optimize.minimize-lbfgsb>` 

3927 - :ref:`TNC <optimize.minimize-tnc>` 

3928 - :ref:`COBYLA <optimize.minimize-cobyla>` 

3929 - :ref:`SLSQP <optimize.minimize-slsqp>` 

3930 - :ref:`dogleg <optimize.minimize-dogleg>` 

3931 - :ref:`trust-ncg <optimize.minimize-trustncg>` 

3932 

3933 `scipy.optimize.root` 

3934 

3935 - :ref:`hybr <optimize.root-hybr>` 

3936 - :ref:`lm <optimize.root-lm>` 

3937 - :ref:`broyden1 <optimize.root-broyden1>` 

3938 - :ref:`broyden2 <optimize.root-broyden2>` 

3939 - :ref:`anderson <optimize.root-anderson>` 

3940 - :ref:`linearmixing <optimize.root-linearmixing>` 

3941 - :ref:`diagbroyden <optimize.root-diagbroyden>` 

3942 - :ref:`excitingmixing <optimize.root-excitingmixing>` 

3943 - :ref:`krylov <optimize.root-krylov>` 

3944 - :ref:`df-sane <optimize.root-dfsane>` 

3945 

3946 `scipy.optimize.minimize_scalar` 

3947 

3948 - :ref:`brent <optimize.minimize_scalar-brent>` 

3949 - :ref:`golden <optimize.minimize_scalar-golden>` 

3950 - :ref:`bounded <optimize.minimize_scalar-bounded>` 

3951 

3952 `scipy.optimize.root_scalar` 

3953 

3954 - :ref:`bisect <optimize.root_scalar-bisect>` 

3955 - :ref:`brentq <optimize.root_scalar-brentq>` 

3956 - :ref:`brenth <optimize.root_scalar-brenth>` 

3957 - :ref:`ridder <optimize.root_scalar-ridder>` 

3958 - :ref:`toms748 <optimize.root_scalar-toms748>` 

3959 - :ref:`newton <optimize.root_scalar-newton>` 

3960 - :ref:`secant <optimize.root_scalar-secant>` 

3961 - :ref:`halley <optimize.root_scalar-halley>` 

3962 

3963 `scipy.optimize.linprog` 

3964 

3965 - :ref:`simplex <optimize.linprog-simplex>` 

3966 - :ref:`interior-point <optimize.linprog-interior-point>` 

3967 - :ref:`revised simplex <optimize.linprog-revised_simplex>` 

3968 - :ref:`highs <optimize.linprog-highs>` 

3969 - :ref:`highs-ds <optimize.linprog-highs-ds>` 

3970 - :ref:`highs-ipm <optimize.linprog-highs-ipm>` 

3971 

3972 `scipy.optimize.quadratic_assignment` 

3973 

3974 - :ref:`faq <optimize.qap-faq>` 

3975 - :ref:`2opt <optimize.qap-2opt>` 

3976 

3977 Examples 

3978 -------- 

3979 We can print documentations of a solver in stdout: 

3980 

3981 >>> from scipy.optimize import show_options 

3982 >>> show_options(solver="minimize") 

3983 ... 

3984 

3985 Specifying a method is possible: 

3986 

3987 >>> show_options(solver="minimize", method="Nelder-Mead") 

3988 ... 

3989 

3990 We can also get the documentations as a string: 

3991 

3992 >>> show_options(solver="minimize", method="Nelder-Mead", disp=False) 

3993 Minimization of scalar function of one or more variables using the ... 

3994 

3995 """ 

3996 import textwrap 

3997 

3998 doc_routines = { 

3999 'minimize': ( 

4000 ('bfgs', 'scipy.optimize._optimize._minimize_bfgs'), 

4001 ('cg', 'scipy.optimize._optimize._minimize_cg'), 

4002 ('cobyla', 'scipy.optimize._cobyla_py._minimize_cobyla'), 

4003 ('dogleg', 'scipy.optimize._trustregion_dogleg._minimize_dogleg'), 

4004 ('l-bfgs-b', 'scipy.optimize._lbfgsb_py._minimize_lbfgsb'), 

4005 ('nelder-mead', 'scipy.optimize._optimize._minimize_neldermead'), 

4006 ('newton-cg', 'scipy.optimize._optimize._minimize_newtoncg'), 

4007 ('powell', 'scipy.optimize._optimize._minimize_powell'), 

4008 ('slsqp', 'scipy.optimize._slsqp_py._minimize_slsqp'), 

4009 ('tnc', 'scipy.optimize._tnc._minimize_tnc'), 

4010 ('trust-ncg', 

4011 'scipy.optimize._trustregion_ncg._minimize_trust_ncg'), 

4012 ('trust-constr', 

4013 'scipy.optimize._trustregion_constr.' 

4014 '_minimize_trustregion_constr'), 

4015 ('trust-exact', 

4016 'scipy.optimize._trustregion_exact._minimize_trustregion_exact'), 

4017 ('trust-krylov', 

4018 'scipy.optimize._trustregion_krylov._minimize_trust_krylov'), 

4019 ), 

4020 'root': ( 

4021 ('hybr', 'scipy.optimize._minpack_py._root_hybr'), 

4022 ('lm', 'scipy.optimize._root._root_leastsq'), 

4023 ('broyden1', 'scipy.optimize._root._root_broyden1_doc'), 

4024 ('broyden2', 'scipy.optimize._root._root_broyden2_doc'), 

4025 ('anderson', 'scipy.optimize._root._root_anderson_doc'), 

4026 ('diagbroyden', 'scipy.optimize._root._root_diagbroyden_doc'), 

4027 ('excitingmixing', 'scipy.optimize._root._root_excitingmixing_doc'), 

4028 ('linearmixing', 'scipy.optimize._root._root_linearmixing_doc'), 

4029 ('krylov', 'scipy.optimize._root._root_krylov_doc'), 

4030 ('df-sane', 'scipy.optimize._spectral._root_df_sane'), 

4031 ), 

4032 'root_scalar': ( 

4033 ('bisect', 'scipy.optimize._root_scalar._root_scalar_bisect_doc'), 

4034 ('brentq', 'scipy.optimize._root_scalar._root_scalar_brentq_doc'), 

4035 ('brenth', 'scipy.optimize._root_scalar._root_scalar_brenth_doc'), 

4036 ('ridder', 'scipy.optimize._root_scalar._root_scalar_ridder_doc'), 

4037 ('toms748', 'scipy.optimize._root_scalar._root_scalar_toms748_doc'), 

4038 ('secant', 'scipy.optimize._root_scalar._root_scalar_secant_doc'), 

4039 ('newton', 'scipy.optimize._root_scalar._root_scalar_newton_doc'), 

4040 ('halley', 'scipy.optimize._root_scalar._root_scalar_halley_doc'), 

4041 ), 

4042 'linprog': ( 

4043 ('simplex', 'scipy.optimize._linprog._linprog_simplex_doc'), 

4044 ('interior-point', 'scipy.optimize._linprog._linprog_ip_doc'), 

4045 ('revised simplex', 'scipy.optimize._linprog._linprog_rs_doc'), 

4046 ('highs-ipm', 'scipy.optimize._linprog._linprog_highs_ipm_doc'), 

4047 ('highs-ds', 'scipy.optimize._linprog._linprog_highs_ds_doc'), 

4048 ('highs', 'scipy.optimize._linprog._linprog_highs_doc'), 

4049 ), 

4050 'quadratic_assignment': ( 

4051 ('faq', 'scipy.optimize._qap._quadratic_assignment_faq'), 

4052 ('2opt', 'scipy.optimize._qap._quadratic_assignment_2opt'), 

4053 ), 

4054 'minimize_scalar': ( 

4055 ('brent', 'scipy.optimize._optimize._minimize_scalar_brent'), 

4056 ('bounded', 'scipy.optimize._optimize._minimize_scalar_bounded'), 

4057 ('golden', 'scipy.optimize._optimize._minimize_scalar_golden'), 

4058 ), 

4059 } 

4060 

4061 if solver is None: 

4062 text = ["\n\n\n========\n", "minimize\n", "========\n"] 

4063 text.append(show_options('minimize', disp=False)) 

4064 text.extend(["\n\n===============\n", "minimize_scalar\n", 

4065 "===============\n"]) 

4066 text.append(show_options('minimize_scalar', disp=False)) 

4067 text.extend(["\n\n\n====\n", "root\n", 

4068 "====\n"]) 

4069 text.append(show_options('root', disp=False)) 

4070 text.extend(['\n\n\n=======\n', 'linprog\n', 

4071 '=======\n']) 

4072 text.append(show_options('linprog', disp=False)) 

4073 text = "".join(text) 

4074 else: 

4075 solver = solver.lower() 

4076 if solver not in doc_routines: 

4077 raise ValueError(f'Unknown solver {solver!r}') 

4078 

4079 if method is None: 

4080 text = [] 

4081 for name, _ in doc_routines[solver]: 

4082 text.extend(["\n\n" + name, "\n" + "="*len(name) + "\n\n"]) 

4083 text.append(show_options(solver, name, disp=False)) 

4084 text = "".join(text) 

4085 else: 

4086 method = method.lower() 

4087 methods = dict(doc_routines[solver]) 

4088 if method not in methods: 

4089 raise ValueError(f"Unknown method {method!r}") 

4090 name = methods[method] 

4091 

4092 # Import function object 

4093 parts = name.split('.') 

4094 mod_name = ".".join(parts[:-1]) 

4095 __import__(mod_name) 

4096 obj = getattr(sys.modules[mod_name], parts[-1]) 

4097 

4098 # Get doc 

4099 doc = obj.__doc__ 

4100 if doc is not None: 

4101 text = textwrap.dedent(doc).strip() 

4102 else: 

4103 text = "" 

4104 

4105 if disp: 

4106 print(text) 

4107 return 

4108 else: 

4109 return text