Coverage for /usr/lib/python3/dist-packages/scipy/optimize/_tnc.py: 31%

77 statements  

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

1# TNC Python interface 

2# @(#) $Jeannot: tnc.py,v 1.11 2005/01/28 18:27:31 js Exp $ 

3 

4# Copyright (c) 2004-2005, Jean-Sebastien Roy (js@jeannot.org) 

5 

6# Permission is hereby granted, free of charge, to any person obtaining a 

7# copy of this software and associated documentation files (the 

8# "Software"), to deal in the Software without restriction, including 

9# without limitation the rights to use, copy, modify, merge, publish, 

10# distribute, sublicense, and/or sell copies of the Software, and to 

11# permit persons to whom the Software is furnished to do so, subject to 

12# the following conditions: 

13 

14# The above copyright notice and this permission notice shall be included 

15# in all copies or substantial portions of the Software. 

16 

17# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 

18# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 

19# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 

20# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 

21# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 

22# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 

23# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 

24 

25""" 

26TNC: A Python interface to the TNC non-linear optimizer 

27 

28TNC is a non-linear optimizer. To use it, you must provide a function to 

29minimize. The function must take one argument: the list of coordinates where to 

30evaluate the function; and it must return either a tuple, whose first element is the 

31value of the function, and whose second argument is the gradient of the function 

32(as a list of values); or None, to abort the minimization. 

33""" 

34 

35from scipy.optimize import _moduleTNC as moduleTNC 

36from ._optimize import (MemoizeJac, OptimizeResult, _check_unknown_options, 

37 _prepare_scalar_function) 

38from ._constraints import old_bound_to_new 

39 

40from numpy import inf, array, zeros, asfarray 

41 

42__all__ = ['fmin_tnc'] 

43 

44 

45MSG_NONE = 0 # No messages 

46MSG_ITER = 1 # One line per iteration 

47MSG_INFO = 2 # Informational messages 

48MSG_VERS = 4 # Version info 

49MSG_EXIT = 8 # Exit reasons 

50MSG_ALL = MSG_ITER + MSG_INFO + MSG_VERS + MSG_EXIT 

51 

52MSGS = { 

53 MSG_NONE: "No messages", 

54 MSG_ITER: "One line per iteration", 

55 MSG_INFO: "Informational messages", 

56 MSG_VERS: "Version info", 

57 MSG_EXIT: "Exit reasons", 

58 MSG_ALL: "All messages" 

59} 

60 

61INFEASIBLE = -1 # Infeasible (lower bound > upper bound) 

62LOCALMINIMUM = 0 # Local minimum reached (|pg| ~= 0) 

63FCONVERGED = 1 # Converged (|f_n-f_(n-1)| ~= 0) 

64XCONVERGED = 2 # Converged (|x_n-x_(n-1)| ~= 0) 

65MAXFUN = 3 # Max. number of function evaluations reached 

66LSFAIL = 4 # Linear search failed 

67CONSTANT = 5 # All lower bounds are equal to the upper bounds 

68NOPROGRESS = 6 # Unable to progress 

69USERABORT = 7 # User requested end of minimization 

70 

71RCSTRINGS = { 

72 INFEASIBLE: "Infeasible (lower bound > upper bound)", 

73 LOCALMINIMUM: "Local minimum reached (|pg| ~= 0)", 

74 FCONVERGED: "Converged (|f_n-f_(n-1)| ~= 0)", 

75 XCONVERGED: "Converged (|x_n-x_(n-1)| ~= 0)", 

76 MAXFUN: "Max. number of function evaluations reached", 

77 LSFAIL: "Linear search failed", 

78 CONSTANT: "All lower bounds are equal to the upper bounds", 

79 NOPROGRESS: "Unable to progress", 

80 USERABORT: "User requested end of minimization" 

81} 

82 

83# Changes to interface made by Travis Oliphant, Apr. 2004 for inclusion in 

84# SciPy 

85 

86 

87def fmin_tnc(func, x0, fprime=None, args=(), approx_grad=0, 

88 bounds=None, epsilon=1e-8, scale=None, offset=None, 

89 messages=MSG_ALL, maxCGit=-1, maxfun=None, eta=-1, 

90 stepmx=0, accuracy=0, fmin=0, ftol=-1, xtol=-1, pgtol=-1, 

91 rescale=-1, disp=None, callback=None): 

92 """ 

93 Minimize a function with variables subject to bounds, using 

94 gradient information in a truncated Newton algorithm. This 

95 method wraps a C implementation of the algorithm. 

96 

97 Parameters 

98 ---------- 

99 func : callable ``func(x, *args)`` 

100 Function to minimize. Must do one of: 

101 

102 1. Return f and g, where f is the value of the function and g its 

103 gradient (a list of floats). 

104 

105 2. Return the function value but supply gradient function 

106 separately as `fprime`. 

107 

108 3. Return the function value and set ``approx_grad=True``. 

109 

110 If the function returns None, the minimization 

111 is aborted. 

112 x0 : array_like 

113 Initial estimate of minimum. 

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

115 Gradient of `func`. If None, then either `func` must return the 

116 function value and the gradient (``f,g = func(x, *args)``) 

117 or `approx_grad` must be True. 

118 args : tuple, optional 

119 Arguments to pass to function. 

120 approx_grad : bool, optional 

121 If true, approximate the gradient numerically. 

122 bounds : list, optional 

123 (min, max) pairs for each element in x0, defining the 

124 bounds on that parameter. Use None or +/-inf for one of 

125 min or max when there is no bound in that direction. 

126 epsilon : float, optional 

127 Used if approx_grad is True. The stepsize in a finite 

128 difference approximation for fprime. 

129 scale : array_like, optional 

130 Scaling factors to apply to each variable. If None, the 

131 factors are up-low for interval bounded variables and 

132 1+|x| for the others. Defaults to None. 

133 offset : array_like, optional 

134 Value to subtract from each variable. If None, the 

135 offsets are (up+low)/2 for interval bounded variables 

136 and x for the others. 

137 messages : int, optional 

138 Bit mask used to select messages display during 

139 minimization values defined in the MSGS dict. Defaults to 

140 MGS_ALL. 

141 disp : int, optional 

142 Integer interface to messages. 0 = no message, 5 = all messages 

143 maxCGit : int, optional 

144 Maximum number of hessian*vector evaluations per main 

145 iteration. If maxCGit == 0, the direction chosen is 

146 -gradient if maxCGit < 0, maxCGit is set to 

147 max(1,min(50,n/2)). Defaults to -1. 

148 maxfun : int, optional 

149 Maximum number of function evaluation. If None, maxfun is 

150 set to max(100, 10*len(x0)). Defaults to None. Note that this function 

151 may violate the limit because of evaluating gradients by numerical 

152 differentiation. 

153 eta : float, optional 

154 Severity of the line search. If < 0 or > 1, set to 0.25. 

155 Defaults to -1. 

156 stepmx : float, optional 

157 Maximum step for the line search. May be increased during 

158 call. If too small, it will be set to 10.0. Defaults to 0. 

159 accuracy : float, optional 

160 Relative precision for finite difference calculations. If 

161 <= machine_precision, set to sqrt(machine_precision). 

162 Defaults to 0. 

163 fmin : float, optional 

164 Minimum function value estimate. Defaults to 0. 

165 ftol : float, optional 

166 Precision goal for the value of f in the stopping criterion. 

167 If ftol < 0.0, ftol is set to 0.0 defaults to -1. 

168 xtol : float, optional 

169 Precision goal for the value of x in the stopping 

170 criterion (after applying x scaling factors). If xtol < 

171 0.0, xtol is set to sqrt(machine_precision). Defaults to 

172 -1. 

173 pgtol : float, optional 

174 Precision goal for the value of the projected gradient in 

175 the stopping criterion (after applying x scaling factors). 

176 If pgtol < 0.0, pgtol is set to 1e-2 * sqrt(accuracy). 

177 Setting it to 0.0 is not recommended. Defaults to -1. 

178 rescale : float, optional 

179 Scaling factor (in log10) used to trigger f value 

180 rescaling. If 0, rescale at each iteration. If a large 

181 value, never rescale. If < 0, rescale is set to 1.3. 

182 callback : callable, optional 

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

184 current parameter vector. 

185 

186 Returns 

187 ------- 

188 x : ndarray 

189 The solution. 

190 nfeval : int 

191 The number of function evaluations. 

192 rc : int 

193 Return code, see below 

194 

195 See also 

196 -------- 

197 minimize: Interface to minimization algorithms for multivariate 

198 functions. See the 'TNC' `method` in particular. 

199 

200 Notes 

201 ----- 

202 The underlying algorithm is truncated Newton, also called 

203 Newton Conjugate-Gradient. This method differs from 

204 scipy.optimize.fmin_ncg in that 

205 

206 1. it wraps a C implementation of the algorithm 

207 2. it allows each variable to be given an upper and lower bound. 

208 

209 The algorithm incorporates the bound constraints by determining 

210 the descent direction as in an unconstrained truncated Newton, 

211 but never taking a step-size large enough to leave the space 

212 of feasible x's. The algorithm keeps track of a set of 

213 currently active constraints, and ignores them when computing 

214 the minimum allowable step size. (The x's associated with the 

215 active constraint are kept fixed.) If the maximum allowable 

216 step size is zero then a new constraint is added. At the end 

217 of each iteration one of the constraints may be deemed no 

218 longer active and removed. A constraint is considered 

219 no longer active is if it is currently active 

220 but the gradient for that variable points inward from the 

221 constraint. The specific constraint removed is the one 

222 associated with the variable of largest index whose 

223 constraint is no longer active. 

224 

225 Return codes are defined as follows:: 

226 

227 -1 : Infeasible (lower bound > upper bound) 

228 0 : Local minimum reached (|pg| ~= 0) 

229 1 : Converged (|f_n-f_(n-1)| ~= 0) 

230 2 : Converged (|x_n-x_(n-1)| ~= 0) 

231 3 : Max. number of function evaluations reached 

232 4 : Linear search failed 

233 5 : All lower bounds are equal to the upper bounds 

234 6 : Unable to progress 

235 7 : User requested end of minimization 

236 

237 References 

238 ---------- 

239 Wright S., Nocedal J. (2006), 'Numerical Optimization' 

240 

241 Nash S.G. (1984), "Newton-Type Minimization Via the Lanczos Method", 

242 SIAM Journal of Numerical Analysis 21, pp. 770-778 

243 

244 """ 

245 # handle fprime/approx_grad 

246 if approx_grad: 

247 fun = func 

248 jac = None 

249 elif fprime is None: 

250 fun = MemoizeJac(func) 

251 jac = fun.derivative 

252 else: 

253 fun = func 

254 jac = fprime 

255 

256 if disp is not None: # disp takes precedence over messages 

257 mesg_num = disp 

258 else: 

259 mesg_num = {0:MSG_NONE, 1:MSG_ITER, 2:MSG_INFO, 3:MSG_VERS, 

260 4:MSG_EXIT, 5:MSG_ALL}.get(messages, MSG_ALL) 

261 # build options 

262 opts = {'eps': epsilon, 

263 'scale': scale, 

264 'offset': offset, 

265 'mesg_num': mesg_num, 

266 'maxCGit': maxCGit, 

267 'maxfun': maxfun, 

268 'eta': eta, 

269 'stepmx': stepmx, 

270 'accuracy': accuracy, 

271 'minfev': fmin, 

272 'ftol': ftol, 

273 'xtol': xtol, 

274 'gtol': pgtol, 

275 'rescale': rescale, 

276 'disp': False} 

277 

278 res = _minimize_tnc(fun, x0, args, jac, bounds, callback=callback, **opts) 

279 

280 return res['x'], res['nfev'], res['status'] 

281 

282 

283def _minimize_tnc(fun, x0, args=(), jac=None, bounds=None, 

284 eps=1e-8, scale=None, offset=None, mesg_num=None, 

285 maxCGit=-1, eta=-1, stepmx=0, accuracy=0, 

286 minfev=0, ftol=-1, xtol=-1, gtol=-1, rescale=-1, disp=False, 

287 callback=None, finite_diff_rel_step=None, maxfun=None, 

288 **unknown_options): 

289 """ 

290 Minimize a scalar function of one or more variables using a truncated 

291 Newton (TNC) algorithm. 

292 

293 Options 

294 ------- 

295 eps : float or ndarray 

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

297 approximation of the jacobian via forward differences. 

298 scale : list of floats 

299 Scaling factors to apply to each variable. If None, the 

300 factors are up-low for interval bounded variables and 

301 1+|x] fo the others. Defaults to None. 

302 offset : float 

303 Value to subtract from each variable. If None, the 

304 offsets are (up+low)/2 for interval bounded variables 

305 and x for the others. 

306 disp : bool 

307 Set to True to print convergence messages. 

308 maxCGit : int 

309 Maximum number of hessian*vector evaluations per main 

310 iteration. If maxCGit == 0, the direction chosen is 

311 -gradient if maxCGit < 0, maxCGit is set to 

312 max(1,min(50,n/2)). Defaults to -1. 

313 eta : float 

314 Severity of the line search. If < 0 or > 1, set to 0.25. 

315 Defaults to -1. 

316 stepmx : float 

317 Maximum step for the line search. May be increased during 

318 call. If too small, it will be set to 10.0. Defaults to 0. 

319 accuracy : float 

320 Relative precision for finite difference calculations. If 

321 <= machine_precision, set to sqrt(machine_precision). 

322 Defaults to 0. 

323 minfev : float 

324 Minimum function value estimate. Defaults to 0. 

325 ftol : float 

326 Precision goal for the value of f in the stopping criterion. 

327 If ftol < 0.0, ftol is set to 0.0 defaults to -1. 

328 xtol : float 

329 Precision goal for the value of x in the stopping 

330 criterion (after applying x scaling factors). If xtol < 

331 0.0, xtol is set to sqrt(machine_precision). Defaults to 

332 -1. 

333 gtol : float 

334 Precision goal for the value of the projected gradient in 

335 the stopping criterion (after applying x scaling factors). 

336 If gtol < 0.0, gtol is set to 1e-2 * sqrt(accuracy). 

337 Setting it to 0.0 is not recommended. Defaults to -1. 

338 rescale : float 

339 Scaling factor (in log10) used to trigger f value 

340 rescaling. If 0, rescale at each iteration. If a large 

341 value, never rescale. If < 0, rescale is set to 1.3. 

342 finite_diff_rel_step : None or array_like, optional 

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

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

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

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

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

348 automatically. 

349 maxfun : int 

350 Maximum number of function evaluations. If None, `maxfun` is 

351 set to max(100, 10*len(x0)). Defaults to None. 

352 """ 

353 _check_unknown_options(unknown_options) 

354 fmin = minfev 

355 pgtol = gtol 

356 

357 x0 = asfarray(x0).flatten() 

358 n = len(x0) 

359 

360 if bounds is None: 

361 bounds = [(None,None)] * n 

362 if len(bounds) != n: 

363 raise ValueError('length of x0 != length of bounds') 

364 new_bounds = old_bound_to_new(bounds) 

365 

366 if mesg_num is not None: 

367 messages = {0:MSG_NONE, 1:MSG_ITER, 2:MSG_INFO, 3:MSG_VERS, 

368 4:MSG_EXIT, 5:MSG_ALL}.get(mesg_num, MSG_ALL) 

369 elif disp: 

370 messages = MSG_ALL 

371 else: 

372 messages = MSG_NONE 

373 

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

375 finite_diff_rel_step=finite_diff_rel_step, 

376 bounds=new_bounds) 

377 func_and_grad = sf.fun_and_grad 

378 

379 """ 

380 low, up : the bounds (lists of floats) 

381 if low is None, the lower bounds are removed. 

382 if up is None, the upper bounds are removed. 

383 low and up defaults to None 

384 """ 

385 low = zeros(n) 

386 up = zeros(n) 

387 for i in range(n): 

388 if bounds[i] is None: 

389 l, u = -inf, inf 

390 else: 

391 l,u = bounds[i] 

392 if l is None: 

393 low[i] = -inf 

394 else: 

395 low[i] = l 

396 if u is None: 

397 up[i] = inf 

398 else: 

399 up[i] = u 

400 

401 if scale is None: 

402 scale = array([]) 

403 

404 if offset is None: 

405 offset = array([]) 

406 

407 if maxfun is None: 

408 maxfun = max(100, 10*len(x0)) 

409 

410 rc, nf, nit, x, funv, jacv = moduleTNC.tnc_minimize( 

411 func_and_grad, x0, low, up, scale, 

412 offset, messages, maxCGit, maxfun, 

413 eta, stepmx, accuracy, fmin, ftol, 

414 xtol, pgtol, rescale, callback 

415 ) 

416 # the TNC documentation states: "On output, x, f and g may be very 

417 # slightly out of sync because of scaling". Therefore re-evaluate 

418 # func_and_grad so they are synced. 

419 funv, jacv = func_and_grad(x) 

420 

421 return OptimizeResult(x=x, fun=funv, jac=jacv, nfev=sf.nfev, 

422 nit=nit, status=rc, message=RCSTRINGS[rc], 

423 success=(-1 < rc < 3))