_optimize.py 146 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169
  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. # A collection of optimization algorithms. Version 0.5
  9. # CHANGES
  10. # Added fminbound (July 2001)
  11. # Added brute (Aug. 2002)
  12. # Finished line search satisfying strong Wolfe conditions (Mar. 2004)
  13. # Updated strong Wolfe conditions line search to use
  14. # cubic-interpolation (Mar. 2004)
  15. # Minimization routines
  16. __all__ = ['fmin', 'fmin_powell', 'fmin_bfgs', 'fmin_ncg', 'fmin_cg',
  17. 'fminbound', 'brent', 'golden', 'bracket', 'rosen', 'rosen_der',
  18. 'rosen_hess', 'rosen_hess_prod', 'brute', 'approx_fprime',
  19. 'line_search', 'check_grad', 'OptimizeResult', 'show_options',
  20. 'OptimizeWarning']
  21. __docformat__ = "restructuredtext en"
  22. import math
  23. import warnings
  24. import sys
  25. from numpy import eye, argmin, zeros, shape, asarray, sqrt
  26. import numpy as np
  27. from scipy.linalg import cholesky, issymmetric, LinAlgError
  28. from scipy.sparse.linalg import LinearOperator
  29. from ._linesearch import (line_search_wolfe1, line_search_wolfe2,
  30. line_search_wolfe2 as line_search,
  31. LineSearchWarning)
  32. from ._numdiff import approx_derivative
  33. from scipy._lib._util import getfullargspec_no_self as _getfullargspec
  34. from scipy._lib._util import (MapWrapper, check_random_state, _RichResult,
  35. _call_callback_maybe_halt, _transition_to_rng,
  36. wrapped_inspect_signature)
  37. from scipy.optimize._differentiable_functions import ScalarFunction, FD_METHODS
  38. from scipy._lib._array_api import array_namespace, xp_capabilities, xp_promote
  39. from scipy._lib import array_api_extra as xpx
  40. # standard status messages of optimizers
  41. _status_message = {'success': 'Optimization terminated successfully.',
  42. 'maxfev': 'Maximum number of function evaluations has '
  43. 'been exceeded.',
  44. 'maxiter': 'Maximum number of iterations has been '
  45. 'exceeded.',
  46. 'pr_loss': 'Desired error not necessarily achieved due '
  47. 'to precision loss.',
  48. 'nan': 'NaN result encountered.',
  49. 'out_of_bounds': 'The result is outside of the provided '
  50. 'bounds.'}
  51. class MemoizeJac:
  52. """Decorator that caches the return values of a function returning ``(fun, grad)``
  53. each time it is called."""
  54. def __init__(self, fun):
  55. self.fun = fun
  56. self.jac = None
  57. self._value = None
  58. self.x = None
  59. def _compute_if_needed(self, x, *args):
  60. if not np.all(x == self.x) or self._value is None or self.jac is None:
  61. self.x = np.asarray(x).copy()
  62. fg = self.fun(x, *args)
  63. self.jac = fg[1]
  64. self._value = fg[0]
  65. def __call__(self, x, *args):
  66. """ returns the function value """
  67. self._compute_if_needed(x, *args)
  68. return self._value
  69. def derivative(self, x, *args):
  70. self._compute_if_needed(x, *args)
  71. return self.jac
  72. def _wrap_callback(callback, method=None):
  73. """Wrap a user-provided callback so that attributes can be attached."""
  74. if callback is None or method in {'tnc', 'cobyla', 'cobyqa'}:
  75. return callback # don't wrap
  76. sig = wrapped_inspect_signature(callback)
  77. if set(sig.parameters) == {'intermediate_result'}:
  78. def wrapped_callback(res):
  79. return callback(intermediate_result=res)
  80. elif method == 'trust-constr':
  81. def wrapped_callback(res):
  82. return callback(np.copy(res.x), res)
  83. elif method == 'differential_evolution':
  84. def wrapped_callback(res):
  85. return callback(np.copy(res.x), res.convergence)
  86. else:
  87. def wrapped_callback(res):
  88. return callback(np.copy(res.x))
  89. wrapped_callback.stop_iteration = False
  90. return wrapped_callback
  91. class OptimizeResult(_RichResult):
  92. """
  93. Represents the optimization result.
  94. Attributes
  95. ----------
  96. x : ndarray
  97. The solution of the optimization.
  98. success : bool
  99. Whether or not the optimizer exited successfully.
  100. status : int
  101. Termination status of the optimizer. Its value depends on the
  102. underlying solver. Refer to `message` for details.
  103. message : str
  104. Description of the cause of the termination.
  105. fun : float
  106. Value of objective function at `x`.
  107. jac, hess : ndarray
  108. Values of objective function's Jacobian and its Hessian at `x` (if
  109. available). The Hessian may be an approximation, see the documentation
  110. of the function in question.
  111. hess_inv : object
  112. Inverse of the objective function's Hessian; may be an approximation.
  113. Not available for all solvers. The type of this attribute may be
  114. either np.ndarray or scipy.sparse.linalg.LinearOperator.
  115. nfev, njev, nhev : int
  116. Number of evaluations of the objective functions and of its
  117. Jacobian and Hessian.
  118. nit : int
  119. Number of iterations performed by the optimizer.
  120. maxcv : float
  121. The maximum constraint violation.
  122. Notes
  123. -----
  124. Depending on the specific solver being used, `OptimizeResult` may
  125. not have all attributes listed here, and they may have additional
  126. attributes not listed here. Since this class is essentially a
  127. subclass of dict with attribute accessors, one can see which
  128. attributes are available using the `OptimizeResult.keys` method.
  129. """
  130. pass
  131. class OptimizeWarning(UserWarning):
  132. """General warning for :mod:`scipy.optimize`."""
  133. pass
  134. def _check_positive_definite(Hk):
  135. def is_pos_def(A):
  136. if issymmetric(A):
  137. try:
  138. cholesky(A)
  139. return True
  140. except LinAlgError:
  141. return False
  142. else:
  143. return False
  144. if Hk is not None:
  145. if not is_pos_def(Hk):
  146. raise ValueError("'hess_inv0' matrix isn't positive definite.")
  147. def _check_unknown_options(unknown_options):
  148. if unknown_options:
  149. msg = ", ".join(map(str, unknown_options.keys()))
  150. # Stack level 4: this is called from _minimize_*, which is
  151. # called from another function in SciPy. Level 4 is the first
  152. # level in user code.
  153. warnings.warn(f"Unknown solver options: {msg}", OptimizeWarning, stacklevel=4)
  154. def is_finite_scalar(x):
  155. """Test whether `x` is either a finite scalar or a finite array scalar.
  156. """
  157. return np.size(x) == 1 and np.isfinite(x)
  158. _epsilon = sqrt(np.finfo(float).eps)
  159. def vecnorm(x, ord=2):
  160. if ord == np.inf:
  161. return np.amax(np.abs(x))
  162. elif ord == -np.inf:
  163. return np.amin(np.abs(x))
  164. else:
  165. return np.sum(np.abs(x)**ord, axis=0)**(1.0 / ord)
  166. def _prepare_scalar_function(fun, x0, jac=None, args=(), bounds=None,
  167. epsilon=None, finite_diff_rel_step=None,
  168. hess=None, workers=None):
  169. """
  170. Creates a ScalarFunction object for use with scalar minimizers
  171. (BFGS/LBFGSB/SLSQP/TNC/CG/etc).
  172. Parameters
  173. ----------
  174. fun : callable
  175. The objective function to be minimized.
  176. ``fun(x, *args) -> float``
  177. where ``x`` is a 1-D array with shape (n,) and ``args``
  178. is a tuple of the fixed parameters needed to completely
  179. specify the function.
  180. x0 : ndarray, shape (n,)
  181. Initial guess. Array of real elements of size (n,),
  182. where 'n' is the number of independent variables.
  183. jac : {callable, '2-point', '3-point', 'cs', None}, optional
  184. Method for computing the gradient vector. If it is a callable, it
  185. should be a function that returns the gradient vector:
  186. ``jac(x, *args) -> array_like, shape (n,)``
  187. If one of `{'2-point', '3-point', 'cs'}` is selected then the gradient
  188. is calculated with a relative step for finite differences. If `None`,
  189. then two-point finite differences with an absolute step is used.
  190. args : tuple, optional
  191. Extra arguments passed to the objective function and its
  192. derivatives (`fun`, `jac` functions).
  193. bounds : sequence, optional
  194. Bounds on variables. 'new-style' bounds are required.
  195. eps : float or ndarray
  196. If ``jac is None`` the absolute step size used for numerical
  197. approximation of the jacobian via forward differences.
  198. finite_diff_rel_step : None or array_like, optional
  199. If ``jac in ['2-point', '3-point', 'cs']`` the relative step size to
  200. use for numerical approximation of the jacobian. The absolute step
  201. size is computed as ``h = rel_step * sign(x0) * max(1, abs(x0))``,
  202. possibly adjusted to fit into the bounds. For ``jac='3-point'``
  203. the sign of `h` is ignored. If None (default) then step is selected
  204. automatically.
  205. hess : {callable, '2-point', '3-point', 'cs', None}
  206. Computes the Hessian matrix. If it is callable, it should return the
  207. Hessian matrix:
  208. ``hess(x, *args) -> {LinearOperator, spmatrix, array}, (n, n)``
  209. Alternatively, the keywords {'2-point', '3-point', 'cs'} select a
  210. finite difference scheme for numerical estimation.
  211. Whenever the gradient is estimated via finite-differences, the Hessian
  212. cannot be estimated with options {'2-point', '3-point', 'cs'} and needs
  213. to be estimated using one of the quasi-Newton strategies.
  214. workers : int or map-like callable, optional
  215. A map-like callable, such as `multiprocessing.Pool.map` for evaluating
  216. any numerical differentiation in parallel.
  217. This evaluation is carried out as ``workers(fun, iterable)``, or
  218. ``workers(grad, iterable)``, depending on what is being numerically
  219. differentiated.
  220. Alternatively, if `workers` is an int the task is subdivided into `workers`
  221. sections and the function evaluated in parallel
  222. (uses `multiprocessing.Pool <multiprocessing>`).
  223. Supply -1 to use all available CPU cores.
  224. It is recommended that a map-like be used instead of int, as repeated
  225. calls to `approx_derivative` will incur large overhead from setting up
  226. new processes.
  227. .. versionadded:: 1.16.0
  228. Returns
  229. -------
  230. sf : ScalarFunction
  231. """
  232. if callable(jac):
  233. grad = jac
  234. elif jac in FD_METHODS:
  235. # epsilon is set to None so that ScalarFunction is made to use
  236. # rel_step
  237. epsilon = None
  238. grad = jac
  239. else:
  240. # default (jac is None) is to do 2-point finite differences with
  241. # absolute step size. ScalarFunction has to be provided an
  242. # epsilon value that is not None to use absolute steps. This is
  243. # normally the case from most _minimize* methods.
  244. grad = '2-point'
  245. epsilon = epsilon
  246. if hess is None:
  247. # ScalarFunction requires something for hess, so we give a dummy
  248. # implementation here if nothing is provided, return a value of None
  249. # so that downstream minimisers halt. The results of `fun.hess`
  250. # should not be used.
  251. def hess(x, *args):
  252. return None
  253. if bounds is None:
  254. bounds = (-np.inf, np.inf)
  255. # normalize workers
  256. workers = workers or map
  257. # ScalarFunction caches. Reuse of fun(x) during grad
  258. # calculation reduces overall function evaluations.
  259. sf = ScalarFunction(fun, x0, args, grad, hess,
  260. finite_diff_rel_step, bounds, epsilon=epsilon,
  261. workers=workers)
  262. return sf
  263. def _clip_x_for_func(func, bounds):
  264. # ensures that x values sent to func are clipped to bounds
  265. # this is used as a mitigation for gh11403, slsqp/tnc sometimes
  266. # suggest a move that is outside the limits by 1 or 2 ULP. This
  267. # unclean fix makes sure x is strictly within bounds.
  268. def eval(x):
  269. x = _check_clip_x(x, bounds)
  270. return func(x)
  271. return eval
  272. def _check_clip_x(x, bounds):
  273. if (x < bounds[0]).any() or (x > bounds[1]).any():
  274. warnings.warn("Values in x were outside bounds during a "
  275. "minimize step, clipping to bounds",
  276. RuntimeWarning, stacklevel=3)
  277. x = np.clip(x, bounds[0], bounds[1])
  278. return x
  279. return x
  280. @xp_capabilities()
  281. def rosen(x):
  282. """
  283. The Rosenbrock function.
  284. The function computed is::
  285. sum(100.0*(x[1:] - x[:-1]**2.0)**2.0 + (1 - x[:-1])**2.0)
  286. Parameters
  287. ----------
  288. x : array_like
  289. 1-D array of points at which the Rosenbrock function is to be computed.
  290. Returns
  291. -------
  292. f : float
  293. The value of the Rosenbrock function.
  294. See Also
  295. --------
  296. rosen_der, rosen_hess, rosen_hess_prod
  297. Examples
  298. --------
  299. >>> import numpy as np
  300. >>> from scipy.optimize import rosen
  301. >>> X = 0.1 * np.arange(10)
  302. >>> rosen(X)
  303. 76.56
  304. For higher-dimensional input ``rosen`` broadcasts.
  305. In the following example, we use this to plot a 2D landscape.
  306. Note that ``rosen_hess`` does not broadcast in this manner.
  307. >>> import matplotlib.pyplot as plt
  308. >>> from mpl_toolkits.mplot3d import Axes3D
  309. >>> x = np.linspace(-1, 1, 50)
  310. >>> X, Y = np.meshgrid(x, x)
  311. >>> ax = plt.subplot(111, projection='3d')
  312. >>> ax.plot_surface(X, Y, rosen([X, Y]))
  313. >>> plt.show()
  314. """
  315. xp = array_namespace(x)
  316. x = xp_promote(x, force_floating=True, xp=xp)
  317. r = xp.sum(100.0 * (x[1:] - x[:-1]**2.0)**2.0 + (1 - x[:-1])**2.0,
  318. axis=0, dtype=x.dtype)
  319. return r
  320. @xp_capabilities(skip_backends=[('jax.numpy', "JAX doesn't allow item assignment.")])
  321. def rosen_der(x):
  322. """
  323. The derivative (i.e. gradient) of the Rosenbrock function.
  324. Parameters
  325. ----------
  326. x : array_like
  327. 1-D array of points at which the derivative is to be computed.
  328. Returns
  329. -------
  330. rosen_der : (N,) ndarray
  331. The gradient of the Rosenbrock function at `x`.
  332. See Also
  333. --------
  334. rosen, rosen_hess, rosen_hess_prod
  335. Examples
  336. --------
  337. >>> import numpy as np
  338. >>> from scipy.optimize import rosen_der
  339. >>> X = 0.1 * np.arange(9)
  340. >>> rosen_der(X)
  341. array([ -2. , 10.6, 15.6, 13.4, 6.4, -3. , -12.4, -19.4, 62. ])
  342. """
  343. xp = array_namespace(x)
  344. x = xp_promote(x, force_floating=True, xp=xp)
  345. xm = x[1:-1]
  346. xm_m1 = x[:-2]
  347. xm_p1 = x[2:]
  348. der = xp.zeros_like(x)
  349. der[1:-1] = (200 * (xm - xm_m1**2) -
  350. 400 * (xm_p1 - xm**2) * xm - 2 * (1 - xm))
  351. der[0] = -400 * x[0] * (x[1] - x[0]**2) - 2 * (1 - x[0])
  352. der[-1] = 200 * (x[-1] - x[-2]**2)
  353. return der
  354. @xp_capabilities()
  355. def rosen_hess(x):
  356. """
  357. The Hessian matrix of the Rosenbrock function.
  358. Parameters
  359. ----------
  360. x : array_like
  361. 1-D array of points at which the Hessian matrix is to be computed.
  362. Returns
  363. -------
  364. rosen_hess : ndarray
  365. The Hessian matrix of the Rosenbrock function at `x`.
  366. See Also
  367. --------
  368. rosen, rosen_der, rosen_hess_prod
  369. Examples
  370. --------
  371. >>> import numpy as np
  372. >>> from scipy.optimize import rosen_hess
  373. >>> X = 0.1 * np.arange(4)
  374. >>> rosen_hess(X)
  375. array([[-38., 0., 0., 0.],
  376. [ 0., 134., -40., 0.],
  377. [ 0., -40., 130., -80.],
  378. [ 0., 0., -80., 200.]])
  379. """
  380. xp = array_namespace(x)
  381. x = xp_promote(x, force_floating=True, xp=xp)
  382. H = (xpx.create_diagonal(-400 * x[:-1], offset=1, xp=xp)
  383. - xpx.create_diagonal(400 * x[:-1], offset=-1, xp=xp))
  384. diagonal = xp.zeros(x.shape[0], dtype=x.dtype)
  385. diagonal = xpx.at(diagonal)[0].set(1200 * x[0]**2 - 400 * x[1] + 2)
  386. diagonal = xpx.at(diagonal)[-1].set(200)
  387. diagonal = xpx.at(diagonal)[1:-1].set(202 + 1200 * x[1:-1]**2 - 400 * x[2:])
  388. return H + xpx.create_diagonal(diagonal, xp=xp)
  389. @xp_capabilities(skip_backends=[('jax.numpy', "JAX doesn't allow item assignment.")])
  390. def rosen_hess_prod(x, p):
  391. """
  392. Product of the Hessian matrix of the Rosenbrock function with a vector.
  393. Parameters
  394. ----------
  395. x : array_like
  396. 1-D array of points at which the Hessian matrix is to be computed.
  397. p : array_like
  398. 1-D array, the vector to be multiplied by the Hessian matrix.
  399. Returns
  400. -------
  401. rosen_hess_prod : ndarray
  402. The Hessian matrix of the Rosenbrock function at `x` multiplied
  403. by the vector `p`.
  404. See Also
  405. --------
  406. rosen, rosen_der, rosen_hess
  407. Examples
  408. --------
  409. >>> import numpy as np
  410. >>> from scipy.optimize import rosen_hess_prod
  411. >>> X = 0.1 * np.arange(9)
  412. >>> p = 0.5 * np.arange(9)
  413. >>> rosen_hess_prod(X, p)
  414. array([ -0., 27., -10., -95., -192., -265., -278., -195., -180.])
  415. """
  416. xp = array_namespace(x, p)
  417. x = xp_promote(x, force_floating=True, xp=xp)
  418. x = xpx.atleast_nd(x, ndim=1, xp=xp)
  419. p = xp.asarray(p, dtype=x.dtype)
  420. Hp = xp.zeros(x.shape[0], dtype=x.dtype)
  421. Hp[0] = (1200 * x[0]**2 - 400 * x[1] + 2) * p[0] - 400 * x[0] * p[1]
  422. Hp[1:-1] = (-400 * x[:-2] * p[:-2] +
  423. (202 + 1200 * x[1:-1]**2 - 400 * x[2:]) * p[1:-1] -
  424. 400 * x[1:-1] * p[2:])
  425. Hp[-1] = -400 * x[-2] * p[-2] + 200*p[-1]
  426. return Hp
  427. def _wrap_scalar_function(function, args):
  428. # wraps a minimizer function to count number of evaluations
  429. # and to easily provide an args kwd.
  430. ncalls = [0]
  431. if function is None:
  432. return ncalls, None
  433. def function_wrapper(x, *wrapper_args):
  434. ncalls[0] += 1
  435. # A copy of x is sent to the user function (gh13740)
  436. fx = function(np.copy(x), *(wrapper_args + args))
  437. # Ideally, we'd like to a have a true scalar returned from f(x). For
  438. # backwards-compatibility, also allow np.array([1.3]), np.array([[1.3]]) etc.
  439. if not np.isscalar(fx):
  440. try:
  441. fx = np.asarray(fx).item()
  442. except (TypeError, ValueError) as e:
  443. raise ValueError("The user-provided objective function "
  444. "must return a scalar value.") from e
  445. return fx
  446. return ncalls, function_wrapper
  447. class _MaxFuncCallError(RuntimeError):
  448. pass
  449. def _wrap_scalar_function_maxfun_validation(function, args, maxfun):
  450. # wraps a minimizer function to count number of evaluations
  451. # and to easily provide an args kwd.
  452. ncalls = [0]
  453. if function is None:
  454. return ncalls, None
  455. def function_wrapper(x, *wrapper_args):
  456. if ncalls[0] >= maxfun:
  457. raise _MaxFuncCallError("Too many function calls")
  458. ncalls[0] += 1
  459. # A copy of x is sent to the user function (gh13740)
  460. fx = function(np.copy(x), *(wrapper_args + args))
  461. # Ideally, we'd like to a have a true scalar returned from f(x). For
  462. # backwards-compatibility, also allow np.array([1.3]),
  463. # np.array([[1.3]]) etc.
  464. if not np.isscalar(fx):
  465. try:
  466. fx = np.asarray(fx).item()
  467. except (TypeError, ValueError) as e:
  468. raise ValueError("The user-provided objective function "
  469. "must return a scalar value.") from e
  470. return fx
  471. return ncalls, function_wrapper
  472. def fmin(func, x0, args=(), xtol=1e-4, ftol=1e-4, maxiter=None, maxfun=None,
  473. full_output=0, disp=1, retall=0, callback=None, initial_simplex=None):
  474. """
  475. Minimize a function using the downhill simplex algorithm.
  476. This algorithm only uses function values, not derivatives or second
  477. derivatives.
  478. Parameters
  479. ----------
  480. func : callable func(x,*args)
  481. The objective function to be minimized.
  482. x0 : ndarray
  483. Initial guess.
  484. args : tuple, optional
  485. Extra arguments passed to func, i.e., ``f(x,*args)``.
  486. xtol : float, optional
  487. Absolute error in xopt between iterations that is acceptable for
  488. convergence.
  489. ftol : number, optional
  490. Absolute error in func(xopt) between iterations that is acceptable for
  491. convergence.
  492. maxiter : int, optional
  493. Maximum number of iterations to perform.
  494. maxfun : number, optional
  495. Maximum number of function evaluations to make.
  496. full_output : bool, optional
  497. Set to True if fopt and warnflag outputs are desired.
  498. disp : bool, optional
  499. Set to True to print convergence messages.
  500. retall : bool, optional
  501. Set to True to return list of solutions at each iteration.
  502. callback : callable, optional
  503. Called after each iteration, as callback(xk), where xk is the
  504. current parameter vector.
  505. initial_simplex : array_like of shape (N + 1, N), optional
  506. Initial simplex. If given, overrides `x0`.
  507. ``initial_simplex[j,:]`` should contain the coordinates of
  508. the jth vertex of the ``N+1`` vertices in the simplex, where
  509. ``N`` is the dimension.
  510. Returns
  511. -------
  512. xopt : ndarray
  513. Parameter that minimizes function.
  514. fopt : float
  515. Value of function at minimum: ``fopt = func(xopt)``.
  516. iter : int
  517. Number of iterations performed.
  518. funcalls : int
  519. Number of function calls made.
  520. warnflag : int
  521. 1 : Maximum number of function evaluations made.
  522. 2 : Maximum number of iterations reached.
  523. allvecs : list
  524. Solution at each iteration.
  525. See also
  526. --------
  527. minimize: Interface to minimization algorithms for multivariate
  528. functions. See the 'Nelder-Mead' `method` in particular.
  529. Notes
  530. -----
  531. Uses a Nelder-Mead simplex algorithm to find the minimum of function of
  532. one or more variables.
  533. This algorithm has a long history of successful use in applications.
  534. But it will usually be slower than an algorithm that uses first or
  535. second derivative information. In practice, it can have poor
  536. performance in high-dimensional problems and is not robust to
  537. minimizing complicated functions. Additionally, there currently is no
  538. complete theory describing when the algorithm will successfully
  539. converge to the minimum, or how fast it will if it does. Both the ftol and
  540. xtol criteria must be met for convergence.
  541. Examples
  542. --------
  543. >>> def f(x):
  544. ... return x**2
  545. >>> from scipy import optimize
  546. >>> minimum = optimize.fmin(f, 1)
  547. Optimization terminated successfully.
  548. Current function value: 0.000000
  549. Iterations: 17
  550. Function evaluations: 34
  551. >>> minimum[0]
  552. -8.8817841970012523e-16
  553. References
  554. ----------
  555. .. [1] Nelder, J.A. and Mead, R. (1965), "A simplex method for function
  556. minimization", The Computer Journal, 7, pp. 308-313
  557. .. [2] Wright, M.H. (1996), "Direct Search Methods: Once Scorned, Now
  558. Respectable", in Numerical Analysis 1995, Proceedings of the
  559. 1995 Dundee Biennial Conference in Numerical Analysis, D.F.
  560. Griffiths and G.A. Watson (Eds.), Addison Wesley Longman,
  561. Harlow, UK, pp. 191-208.
  562. """
  563. opts = {'xatol': xtol,
  564. 'fatol': ftol,
  565. 'maxiter': maxiter,
  566. 'maxfev': maxfun,
  567. 'disp': disp,
  568. 'return_all': retall,
  569. 'initial_simplex': initial_simplex}
  570. callback = _wrap_callback(callback)
  571. res = _minimize_neldermead(func, x0, args, callback=callback, **opts)
  572. if full_output:
  573. retlist = res['x'], res['fun'], res['nit'], res['nfev'], res['status']
  574. if retall:
  575. retlist += (res['allvecs'], )
  576. return retlist
  577. else:
  578. if retall:
  579. return res['x'], res['allvecs']
  580. else:
  581. return res['x']
  582. def _minimize_neldermead(func, x0, args=(), callback=None,
  583. maxiter=None, maxfev=None, disp=False,
  584. return_all=False, initial_simplex=None,
  585. xatol=1e-4, fatol=1e-4, adaptive=False, bounds=None,
  586. **unknown_options):
  587. """
  588. Minimization of scalar function of one or more variables using the
  589. Nelder-Mead algorithm.
  590. Options
  591. -------
  592. disp : bool
  593. Set to True to print convergence messages.
  594. maxiter, maxfev : int
  595. Maximum allowed number of iterations and function evaluations.
  596. Will default to ``N*200``, where ``N`` is the number of
  597. variables, if neither `maxiter` or `maxfev` is set. If both
  598. `maxiter` and `maxfev` are set, minimization will stop at the
  599. first reached.
  600. return_all : bool, optional
  601. Set to True to return a list of the best solution at each of the
  602. iterations.
  603. initial_simplex : array_like of shape (N + 1, N)
  604. Initial simplex. If given, overrides `x0`.
  605. ``initial_simplex[j,:]`` should contain the coordinates of
  606. the jth vertex of the ``N+1`` vertices in the simplex, where
  607. ``N`` is the dimension.
  608. xatol : float, optional
  609. Absolute error in xopt between iterations that is acceptable for
  610. convergence.
  611. fatol : number, optional
  612. Absolute error in func(xopt) between iterations that is acceptable for
  613. convergence.
  614. adaptive : bool, optional
  615. Adapt algorithm parameters to dimensionality of problem. Useful for
  616. high-dimensional minimization [1]_.
  617. bounds : sequence or `Bounds`, optional
  618. Bounds on variables. There are two ways to specify the bounds:
  619. 1. Instance of `Bounds` class.
  620. 2. Sequence of ``(min, max)`` pairs for each element in `x`. None
  621. is used to specify no bound.
  622. Note that this just clips all vertices in simplex based on
  623. the bounds.
  624. References
  625. ----------
  626. .. [1] Gao, F. and Han, L.
  627. Implementing the Nelder-Mead simplex algorithm with adaptive
  628. parameters. 2012. Computational Optimization and Applications.
  629. 51:1, pp. 259-277
  630. """
  631. _check_unknown_options(unknown_options)
  632. maxfun = maxfev
  633. retall = return_all
  634. x0 = np.atleast_1d(x0).flatten()
  635. dtype = x0.dtype if np.issubdtype(x0.dtype, np.inexact) else np.float64
  636. x0 = np.asarray(x0, dtype=dtype)
  637. if adaptive:
  638. dim = float(len(x0))
  639. rho = 1
  640. chi = 1 + 2/dim
  641. psi = 0.75 - 1/(2*dim)
  642. sigma = 1 - 1/dim
  643. else:
  644. rho = 1
  645. chi = 2
  646. psi = 0.5
  647. sigma = 0.5
  648. nonzdelt = 0.05
  649. zdelt = 0.00025
  650. if bounds is not None:
  651. lower_bound, upper_bound = bounds.lb, bounds.ub
  652. # check bounds
  653. if (lower_bound > upper_bound).any():
  654. raise ValueError("Nelder Mead - one of the lower bounds "
  655. "is greater than an upper bound.")
  656. if np.any(lower_bound > x0) or np.any(x0 > upper_bound):
  657. warnings.warn("Initial guess is not within the specified bounds",
  658. OptimizeWarning, stacklevel=3)
  659. if bounds is not None:
  660. x0 = np.clip(x0, lower_bound, upper_bound)
  661. if initial_simplex is None:
  662. N = len(x0)
  663. sim = np.empty((N + 1, N), dtype=x0.dtype)
  664. sim[0] = x0
  665. for k in range(N):
  666. y = np.array(x0, copy=True)
  667. if y[k] != 0:
  668. y[k] = (1 + nonzdelt)*y[k]
  669. else:
  670. y[k] = zdelt
  671. sim[k + 1] = y
  672. else:
  673. sim = np.atleast_2d(initial_simplex).copy()
  674. dtype = sim.dtype if np.issubdtype(sim.dtype, np.inexact) else np.float64
  675. sim = np.asarray(sim, dtype=dtype)
  676. if sim.ndim != 2 or sim.shape[0] != sim.shape[1] + 1:
  677. raise ValueError("`initial_simplex` should be an array of shape (N+1,N)")
  678. if len(x0) != sim.shape[1]:
  679. raise ValueError("Size of `initial_simplex` is not consistent with `x0`")
  680. N = sim.shape[1]
  681. if retall:
  682. allvecs = [sim[0]]
  683. # If neither are set, then set both to default
  684. if maxiter is None and maxfun is None:
  685. maxiter = N * 200
  686. maxfun = N * 200
  687. elif maxiter is None:
  688. # Convert remaining Nones, to np.inf, unless the other is np.inf, in
  689. # which case use the default to avoid unbounded iteration
  690. if maxfun == np.inf:
  691. maxiter = N * 200
  692. else:
  693. maxiter = np.inf
  694. elif maxfun is None:
  695. if maxiter == np.inf:
  696. maxfun = N * 200
  697. else:
  698. maxfun = np.inf
  699. if bounds is not None:
  700. # The default simplex construction may make all entries (for a given
  701. # parameter) greater than an upper bound if x0 is very close to the
  702. # upper bound. If one simply clips the simplex to the bounds this could
  703. # make the simplex entries degenerate. If that occurs reflect into the
  704. # interior.
  705. msk = sim > upper_bound
  706. # reflect into the interior
  707. sim = np.where(msk, 2*upper_bound - sim, sim)
  708. # but make sure the reflection is no less than the lower_bound
  709. sim = np.clip(sim, lower_bound, upper_bound)
  710. one2np1 = list(range(1, N + 1))
  711. fsim = np.full((N + 1,), np.inf, dtype=float)
  712. fcalls, func = _wrap_scalar_function_maxfun_validation(func, args, maxfun)
  713. try:
  714. for k in range(N + 1):
  715. fsim[k] = func(sim[k])
  716. except _MaxFuncCallError:
  717. pass
  718. finally:
  719. ind = np.argsort(fsim)
  720. sim = np.take(sim, ind, 0)
  721. fsim = np.take(fsim, ind, 0)
  722. ind = np.argsort(fsim)
  723. fsim = np.take(fsim, ind, 0)
  724. # sort so sim[0,:] has the lowest function value
  725. sim = np.take(sim, ind, 0)
  726. iterations = 1
  727. while (fcalls[0] < maxfun and iterations < maxiter):
  728. try:
  729. if (np.max(np.ravel(np.abs(sim[1:] - sim[0]))) <= xatol and
  730. np.max(np.abs(fsim[0] - fsim[1:])) <= fatol):
  731. break
  732. xbar = np.add.reduce(sim[:-1], 0) / N
  733. xr = (1 + rho) * xbar - rho * sim[-1]
  734. if bounds is not None:
  735. xr = np.clip(xr, lower_bound, upper_bound)
  736. fxr = func(xr)
  737. doshrink = 0
  738. if fxr < fsim[0]:
  739. xe = (1 + rho * chi) * xbar - rho * chi * sim[-1]
  740. if bounds is not None:
  741. xe = np.clip(xe, lower_bound, upper_bound)
  742. fxe = func(xe)
  743. if fxe < fxr:
  744. sim[-1] = xe
  745. fsim[-1] = fxe
  746. else:
  747. sim[-1] = xr
  748. fsim[-1] = fxr
  749. else: # fsim[0] <= fxr
  750. if fxr < fsim[-2]:
  751. sim[-1] = xr
  752. fsim[-1] = fxr
  753. else: # fxr >= fsim[-2]
  754. # Perform contraction
  755. if fxr < fsim[-1]:
  756. xc = (1 + psi * rho) * xbar - psi * rho * sim[-1]
  757. if bounds is not None:
  758. xc = np.clip(xc, lower_bound, upper_bound)
  759. fxc = func(xc)
  760. if fxc <= fxr:
  761. sim[-1] = xc
  762. fsim[-1] = fxc
  763. else:
  764. doshrink = 1
  765. else:
  766. # Perform an inside contraction
  767. xcc = (1 - psi) * xbar + psi * sim[-1]
  768. if bounds is not None:
  769. xcc = np.clip(xcc, lower_bound, upper_bound)
  770. fxcc = func(xcc)
  771. if fxcc < fsim[-1]:
  772. sim[-1] = xcc
  773. fsim[-1] = fxcc
  774. else:
  775. doshrink = 1
  776. if doshrink:
  777. for j in one2np1:
  778. sim[j] = sim[0] + sigma * (sim[j] - sim[0])
  779. if bounds is not None:
  780. sim[j] = np.clip(
  781. sim[j], lower_bound, upper_bound)
  782. fsim[j] = func(sim[j])
  783. iterations += 1
  784. except _MaxFuncCallError:
  785. pass
  786. ind = np.argsort(fsim)
  787. sim = np.take(sim, ind, 0)
  788. fsim = np.take(fsim, ind, 0)
  789. if retall:
  790. allvecs.append(sim[0])
  791. intermediate_result = OptimizeResult(x=sim[0], fun=fsim[0])
  792. if _call_callback_maybe_halt(callback, intermediate_result):
  793. break
  794. x = sim[0]
  795. fval = np.min(fsim)
  796. warnflag = 0
  797. if fcalls[0] >= maxfun:
  798. warnflag = 1
  799. msg = _status_message['maxfev']
  800. if disp:
  801. warnings.warn(msg, RuntimeWarning, stacklevel=3)
  802. elif iterations >= maxiter:
  803. warnflag = 2
  804. msg = _status_message['maxiter']
  805. if disp:
  806. warnings.warn(msg, RuntimeWarning, stacklevel=3)
  807. else:
  808. msg = _status_message['success']
  809. if disp:
  810. print(msg)
  811. print(f" Current function value: {fval:f}")
  812. print(f" Iterations: {iterations:d}")
  813. print(f" Function evaluations: {fcalls[0]:d}")
  814. result = OptimizeResult(fun=fval, nit=iterations, nfev=fcalls[0],
  815. status=warnflag, success=(warnflag == 0),
  816. message=msg, x=x, final_simplex=(sim, fsim))
  817. if retall:
  818. result['allvecs'] = allvecs
  819. return result
  820. def approx_fprime(xk, f, epsilon=_epsilon, *args):
  821. """Finite difference approximation of the derivatives of a
  822. scalar or vector-valued function.
  823. If a function maps from :math:`R^n` to :math:`R^m`, its derivatives form
  824. an m-by-n matrix
  825. called the Jacobian, where an element :math:`(i, j)` is a partial
  826. derivative of f[i] with respect to ``xk[j]``.
  827. Parameters
  828. ----------
  829. xk : array_like
  830. The coordinate vector at which to determine the gradient of `f`.
  831. f : callable
  832. Function of which to estimate the derivatives of. Has the signature
  833. ``f(xk, *args)`` where `xk` is the argument in the form of a 1-D array
  834. and `args` is a tuple of any additional fixed parameters needed to
  835. completely specify the function. The argument `xk` passed to this
  836. function is an ndarray of shape (n,) (never a scalar even if n=1).
  837. It must return a 1-D array_like of shape (m,) or a scalar.
  838. Suppose the callable has signature ``f0(x, *my_args, **my_kwargs)``, where
  839. ``my_args`` and ``my_kwargs`` are required positional and keyword arguments.
  840. Rather than passing ``f0`` as the callable, wrap it to accept
  841. only ``x``; e.g., pass ``fun=lambda x: f0(x, *my_args, **my_kwargs)`` as the
  842. callable, where ``my_args`` (tuple) and ``my_kwargs`` (dict) have been
  843. gathered before invoking this function.
  844. .. versionchanged:: 1.9.0
  845. `f` is now able to return a 1-D array-like, with the :math:`(m, n)`
  846. Jacobian being estimated.
  847. epsilon : {float, array_like}, optional
  848. Increment to `xk` to use for determining the function gradient.
  849. If a scalar, uses the same finite difference delta for all partial
  850. derivatives. If an array, should contain one value per element of
  851. `xk`. Defaults to ``sqrt(np.finfo(float).eps)``, which is approximately
  852. 1.49e-08.
  853. \\*args : args, optional
  854. Any other arguments that are to be passed to `f`.
  855. Returns
  856. -------
  857. jac : ndarray
  858. The partial derivatives of `f` to `xk`.
  859. See Also
  860. --------
  861. check_grad : Check correctness of gradient function against approx_fprime.
  862. Notes
  863. -----
  864. The function gradient is determined by the forward finite difference
  865. formula::
  866. f(xk[i] + epsilon[i]) - f(xk[i])
  867. f'[i] = ---------------------------------
  868. epsilon[i]
  869. Examples
  870. --------
  871. >>> import numpy as np
  872. >>> from scipy import optimize
  873. >>> def func(x, c0, c1):
  874. ... "Coordinate vector `x` should be an array of size two."
  875. ... return c0 * x[0]**2 + c1*x[1]**2
  876. >>> x = np.ones(2)
  877. >>> c0, c1 = (1, 200)
  878. >>> eps = np.sqrt(np.finfo(float).eps)
  879. >>> optimize.approx_fprime(x, func, [eps, np.sqrt(200) * eps], c0, c1)
  880. array([ 2. , 400.00004208])
  881. """
  882. xk = np.asarray(xk, float)
  883. f0 = f(xk, *args)
  884. return approx_derivative(f, xk, method='2-point', abs_step=epsilon,
  885. args=args, f0=f0)
  886. @_transition_to_rng("seed", position_num=6)
  887. def check_grad(func, grad, x0, *args, epsilon=_epsilon,
  888. direction='all', rng=None):
  889. r"""Check the correctness of a gradient function by comparing it against a
  890. (forward) finite-difference approximation of the gradient.
  891. Parameters
  892. ----------
  893. func : callable ``func(x0, *args)``
  894. Function whose derivative is to be checked.
  895. grad : callable ``grad(x0, *args)``
  896. Jacobian of `func`.
  897. x0 : ndarray
  898. Points to check `grad` against forward difference approximation of grad
  899. using `func`.
  900. args : \\*args, optional
  901. Extra arguments passed to `func` and `grad`.
  902. epsilon : float, optional
  903. Step size used for the finite difference approximation. It defaults to
  904. ``sqrt(np.finfo(float).eps)``, which is approximately 1.49e-08.
  905. direction : str, optional
  906. If set to ``'random'``, then gradients along a random vector
  907. are used to check `grad` against forward difference approximation
  908. using `func`. By default it is ``'all'``, in which case, all
  909. the one hot direction vectors are considered to check `grad`.
  910. If `func` is a vector valued function then only ``'all'`` can be used.
  911. rng : `numpy.random.Generator`, optional
  912. Pseudorandom number generator state. When `rng` is None, a new
  913. `numpy.random.Generator` is created using entropy from the
  914. operating system. Types other than `numpy.random.Generator` are
  915. passed to `numpy.random.default_rng` to instantiate a ``Generator``.
  916. The random numbers generated affect the random vector along which gradients
  917. are computed to check ``grad``. Note that `rng` is only used when `direction`
  918. argument is set to `'random'`.
  919. Returns
  920. -------
  921. err : float
  922. The square root of the sum of squares (i.e., the 2-norm) of the
  923. difference between ``grad(x0, *args)`` and the finite difference
  924. approximation of `grad` using func at the points `x0`.
  925. See Also
  926. --------
  927. approx_fprime
  928. Examples
  929. --------
  930. >>> import numpy as np
  931. >>> def func(x):
  932. ... return x[0]**2 - 0.5 * x[1]**3
  933. >>> def grad(x):
  934. ... return [2 * x[0], -1.5 * x[1]**2]
  935. >>> from scipy.optimize import check_grad
  936. >>> check_grad(func, grad, [1.5, -1.5])
  937. 2.9802322387695312e-08 # may vary
  938. >>> rng = np.random.default_rng()
  939. >>> check_grad(func, grad, [1.5, -1.5],
  940. ... direction='random', seed=rng)
  941. 2.9802322387695312e-08
  942. """
  943. step = epsilon
  944. x0 = np.asarray(x0)
  945. def g(w, func, x0, v, *args):
  946. return func(x0 + w*v, *args)
  947. if direction == 'random':
  948. _grad = np.asanyarray(grad(x0, *args))
  949. if _grad.ndim > 1:
  950. raise ValueError("'random' can only be used with scalar valued"
  951. " func")
  952. rng_gen = check_random_state(rng)
  953. v = rng_gen.standard_normal(size=(x0.shape))
  954. _args = (func, x0, v) + args
  955. _func = g
  956. vars = np.zeros((1,))
  957. analytical_grad = np.dot(_grad, v)
  958. elif direction == 'all':
  959. _args = args
  960. _func = func
  961. vars = x0
  962. analytical_grad = grad(x0, *args)
  963. else:
  964. raise ValueError(f"{direction} is not a valid string for "
  965. "``direction`` argument")
  966. return np.sqrt(np.sum(np.abs(
  967. (analytical_grad - approx_fprime(vars, _func, step, *_args))**2
  968. )))
  969. def approx_fhess_p(x0, p, fprime, epsilon, *args):
  970. # calculate fprime(x0) first, as this may be cached by ScalarFunction
  971. f1 = fprime(*((x0,) + args))
  972. f2 = fprime(*((x0 + epsilon*p,) + args))
  973. return (f2 - f1) / epsilon
  974. class _LineSearchError(RuntimeError):
  975. pass
  976. def _line_search_wolfe12(f, fprime, xk, pk, gfk, old_fval, old_old_fval,
  977. **kwargs):
  978. """
  979. Same as line_search_wolfe1, but fall back to line_search_wolfe2 if
  980. suitable step length is not found, and raise an exception if a
  981. suitable step length is not found.
  982. Raises
  983. ------
  984. _LineSearchError
  985. If no suitable step size is found
  986. """
  987. extra_condition = kwargs.pop('extra_condition', None)
  988. ret = line_search_wolfe1(f, fprime, xk, pk, gfk,
  989. old_fval, old_old_fval,
  990. **kwargs)
  991. if ret[0] is not None and extra_condition is not None:
  992. xp1 = xk + ret[0] * pk
  993. if not extra_condition(ret[0], xp1, ret[3], ret[5]):
  994. # Reject step if extra_condition fails
  995. ret = (None,)
  996. if ret[0] is None:
  997. # line search failed: try different one.
  998. with warnings.catch_warnings():
  999. warnings.simplefilter('ignore', LineSearchWarning)
  1000. kwargs2 = {}
  1001. for key in ('c1', 'c2', 'amax'):
  1002. if key in kwargs:
  1003. kwargs2[key] = kwargs[key]
  1004. ret = line_search_wolfe2(f, fprime, xk, pk, gfk,
  1005. old_fval, old_old_fval,
  1006. extra_condition=extra_condition,
  1007. **kwargs2)
  1008. if ret[0] is None:
  1009. raise _LineSearchError()
  1010. return ret
  1011. def fmin_bfgs(f, x0, fprime=None, args=(), gtol=1e-5, norm=np.inf,
  1012. epsilon=_epsilon, maxiter=None, full_output=0, disp=1,
  1013. retall=0, callback=None, xrtol=0, c1=1e-4, c2=0.9,
  1014. hess_inv0=None):
  1015. """
  1016. Minimize a function using the BFGS algorithm.
  1017. Parameters
  1018. ----------
  1019. f : callable ``f(x,*args)``
  1020. Objective function to be minimized.
  1021. x0 : ndarray
  1022. Initial guess, shape (n,)
  1023. fprime : callable ``f'(x,*args)``, optional
  1024. Gradient of f.
  1025. args : tuple, optional
  1026. Extra arguments passed to f and fprime.
  1027. gtol : float, optional
  1028. Terminate successfully if gradient norm is less than `gtol`
  1029. norm : float, optional
  1030. Order of norm (Inf is max, -Inf is min)
  1031. epsilon : int or ndarray, optional
  1032. If `fprime` is approximated, use this value for the step size.
  1033. callback : callable, optional
  1034. An optional user-supplied function to call after each
  1035. iteration. Called as ``callback(xk)``, where ``xk`` is the
  1036. current parameter vector.
  1037. maxiter : int, optional
  1038. Maximum number of iterations to perform.
  1039. full_output : bool, optional
  1040. If True, return ``fopt``, ``func_calls``, ``grad_calls``, and
  1041. ``warnflag`` in addition to ``xopt``.
  1042. disp : bool, optional
  1043. Print convergence message if True.
  1044. retall : bool, optional
  1045. Return a list of results at each iteration if True.
  1046. xrtol : float, default: 0
  1047. Relative tolerance for `x`. Terminate successfully if step
  1048. size is less than ``xk * xrtol`` where ``xk`` is the current
  1049. parameter vector.
  1050. c1 : float, default: 1e-4
  1051. Parameter for Armijo condition rule.
  1052. c2 : float, default: 0.9
  1053. Parameter for curvature condition rule.
  1054. hess_inv0 : None or ndarray, optional``
  1055. Initial inverse hessian estimate, shape (n, n). If None (default) then
  1056. the identity matrix is used.
  1057. Returns
  1058. -------
  1059. xopt : ndarray
  1060. Parameters which minimize f, i.e., ``f(xopt) == fopt``.
  1061. fopt : float
  1062. Minimum value.
  1063. gopt : ndarray
  1064. Value of gradient at minimum, f'(xopt), which should be near 0.
  1065. Bopt : ndarray
  1066. Value of 1/f''(xopt), i.e., the inverse Hessian matrix.
  1067. func_calls : int
  1068. Number of function_calls made.
  1069. grad_calls : int
  1070. Number of gradient calls made.
  1071. warnflag : integer
  1072. 1 : Maximum number of iterations exceeded.
  1073. 2 : Gradient and/or function calls not changing.
  1074. 3 : NaN result encountered.
  1075. allvecs : list
  1076. The value of `xopt` at each iteration. Only returned if `retall` is
  1077. True.
  1078. Notes
  1079. -----
  1080. Optimize the function, `f`, whose gradient is given by `fprime`
  1081. using the quasi-Newton method of Broyden, Fletcher, Goldfarb,
  1082. and Shanno (BFGS).
  1083. Parameters `c1` and `c2` must satisfy ``0 < c1 < c2 < 1``.
  1084. See Also
  1085. --------
  1086. minimize: Interface to minimization algorithms for multivariate
  1087. functions. See ``method='BFGS'`` in particular.
  1088. References
  1089. ----------
  1090. Wright, and Nocedal 'Numerical Optimization', 1999, p. 198.
  1091. Examples
  1092. --------
  1093. >>> import numpy as np
  1094. >>> from scipy.optimize import fmin_bfgs
  1095. >>> def quadratic_cost(x, Q):
  1096. ... return x @ Q @ x
  1097. ...
  1098. >>> x0 = np.array([-3, -4])
  1099. >>> cost_weight = np.diag([1., 10.])
  1100. >>> # Note that a trailing comma is necessary for a tuple with single element
  1101. >>> fmin_bfgs(quadratic_cost, x0, args=(cost_weight,))
  1102. Optimization terminated successfully.
  1103. Current function value: 0.000000
  1104. Iterations: 7 # may vary
  1105. Function evaluations: 24 # may vary
  1106. Gradient evaluations: 8 # may vary
  1107. array([ 2.85169950e-06, -4.61820139e-07])
  1108. >>> def quadratic_cost_grad(x, Q):
  1109. ... return 2 * Q @ x
  1110. ...
  1111. >>> fmin_bfgs(quadratic_cost, x0, quadratic_cost_grad, args=(cost_weight,))
  1112. Optimization terminated successfully.
  1113. Current function value: 0.000000
  1114. Iterations: 7
  1115. Function evaluations: 8
  1116. Gradient evaluations: 8
  1117. array([ 2.85916637e-06, -4.54371951e-07])
  1118. """
  1119. opts = {'gtol': gtol,
  1120. 'norm': norm,
  1121. 'eps': epsilon,
  1122. 'disp': disp,
  1123. 'maxiter': maxiter,
  1124. 'return_all': retall,
  1125. 'xrtol': xrtol,
  1126. 'c1': c1,
  1127. 'c2': c2,
  1128. 'hess_inv0': hess_inv0}
  1129. callback = _wrap_callback(callback)
  1130. res = _minimize_bfgs(f, x0, args, fprime, callback=callback, **opts)
  1131. if full_output:
  1132. retlist = (res['x'], res['fun'], res['jac'], res['hess_inv'],
  1133. res['nfev'], res['njev'], res['status'])
  1134. if retall:
  1135. retlist += (res['allvecs'], )
  1136. return retlist
  1137. else:
  1138. if retall:
  1139. return res['x'], res['allvecs']
  1140. else:
  1141. return res['x']
  1142. def _minimize_bfgs(fun, x0, args=(), jac=None, callback=None,
  1143. gtol=1e-5, norm=np.inf, eps=_epsilon, maxiter=None,
  1144. disp=False, return_all=False, finite_diff_rel_step=None,
  1145. xrtol=0, c1=1e-4, c2=0.9,
  1146. hess_inv0=None, workers=None, **unknown_options):
  1147. """
  1148. Minimization of scalar function of one or more variables using the
  1149. BFGS algorithm.
  1150. Options
  1151. -------
  1152. disp : bool
  1153. Set to True to print convergence messages.
  1154. maxiter : int
  1155. Maximum number of iterations to perform.
  1156. gtol : float
  1157. Terminate successfully if gradient norm is less than `gtol`.
  1158. norm : float
  1159. Order of norm (Inf is max, -Inf is min).
  1160. eps : float or ndarray
  1161. If `jac is None` the absolute step size used for numerical
  1162. approximation of the jacobian via forward differences.
  1163. return_all : bool, optional
  1164. Set to True to return a list of the best solution at each of the
  1165. iterations.
  1166. finite_diff_rel_step : None or array_like, optional
  1167. If ``jac in ['2-point', '3-point', 'cs']`` the relative step size to
  1168. use for numerical approximation of the jacobian. The absolute step
  1169. size is computed as ``h = rel_step * sign(x) * max(1, abs(x))``,
  1170. possibly adjusted to fit into the bounds. For ``jac='3-point'``
  1171. the sign of `h` is ignored. If None (default) then step is selected
  1172. automatically.
  1173. xrtol : float, default: 0
  1174. Relative tolerance for `x`. Terminate successfully if step size is
  1175. less than ``xk * xrtol`` where ``xk`` is the current parameter vector.
  1176. c1 : float, default: 1e-4
  1177. Parameter for Armijo condition rule.
  1178. c2 : float, default: 0.9
  1179. Parameter for curvature condition rule.
  1180. hess_inv0 : None or ndarray, optional
  1181. Initial inverse hessian estimate, shape (n, n). If None (default) then
  1182. the identity matrix is used.
  1183. workers : int, map-like callable, optional
  1184. A map-like callable, such as `multiprocessing.Pool.map` for evaluating
  1185. any numerical differentiation in parallel.
  1186. This evaluation is carried out as ``workers(fun, iterable)``.
  1187. .. versionadded:: 1.16.0
  1188. Notes
  1189. -----
  1190. Parameters `c1` and `c2` must satisfy ``0 < c1 < c2 < 1``.
  1191. If minimization doesn't complete successfully, with an error message of
  1192. ``Desired error not necessarily achieved due to precision loss``, then
  1193. consider setting `gtol` to a higher value. This precision loss typically
  1194. occurs when the (finite difference) numerical differentiation cannot provide
  1195. sufficient precision to satisfy the `gtol` termination criterion.
  1196. This can happen when working in single precision and a callable jac is not
  1197. provided. For single precision problems a `gtol` of 1e-3 seems to work.
  1198. """
  1199. _check_unknown_options(unknown_options)
  1200. _check_positive_definite(hess_inv0)
  1201. retall = return_all
  1202. x0 = asarray(x0).flatten()
  1203. if x0.ndim == 0:
  1204. x0 = x0.reshape((1,))
  1205. if maxiter is None:
  1206. maxiter = len(x0) * 200
  1207. sf = _prepare_scalar_function(fun, x0, jac, args=args, epsilon=eps,
  1208. finite_diff_rel_step=finite_diff_rel_step,
  1209. workers=workers)
  1210. f = sf.fun
  1211. myfprime = sf.grad
  1212. old_fval = f(x0)
  1213. gfk = myfprime(x0)
  1214. k = 0
  1215. N = len(x0)
  1216. I = np.eye(N, dtype=int)
  1217. Hk = I if hess_inv0 is None else hess_inv0
  1218. # Sets the initial step guess to dx ~ 1
  1219. old_old_fval = old_fval + np.linalg.norm(gfk) / 2
  1220. xk = x0
  1221. if retall:
  1222. allvecs = [x0]
  1223. warnflag = 0
  1224. gnorm = vecnorm(gfk, ord=norm)
  1225. while (gnorm > gtol) and (k < maxiter):
  1226. pk = -np.dot(Hk, gfk)
  1227. try:
  1228. alpha_k, fc, gc, old_fval, old_old_fval, gfkp1 = \
  1229. _line_search_wolfe12(f, myfprime, xk, pk, gfk,
  1230. old_fval, old_old_fval, amin=1e-100,
  1231. amax=1e100, c1=c1, c2=c2)
  1232. except _LineSearchError:
  1233. # Line search failed to find a better solution.
  1234. warnflag = 2
  1235. break
  1236. sk = alpha_k * pk
  1237. xkp1 = xk + sk
  1238. if retall:
  1239. allvecs.append(xkp1)
  1240. xk = xkp1
  1241. if gfkp1 is None:
  1242. gfkp1 = myfprime(xkp1)
  1243. yk = gfkp1 - gfk
  1244. gfk = gfkp1
  1245. k += 1
  1246. intermediate_result = OptimizeResult(x=xk, fun=old_fval)
  1247. if _call_callback_maybe_halt(callback, intermediate_result):
  1248. break
  1249. gnorm = vecnorm(gfk, ord=norm)
  1250. if (gnorm <= gtol):
  1251. break
  1252. # See Chapter 5 in P.E. Frandsen, K. Jonasson, H.B. Nielsen,
  1253. # O. Tingleff: "Unconstrained Optimization", IMM, DTU. 1999.
  1254. # These notes are available here:
  1255. # http://www2.imm.dtu.dk/documents/ftp/publlec.html
  1256. if (alpha_k*vecnorm(pk) <= xrtol*(xrtol + vecnorm(xk))):
  1257. break
  1258. if not np.isfinite(old_fval):
  1259. # We correctly found +-Inf as optimal value, or something went
  1260. # wrong.
  1261. warnflag = 2
  1262. break
  1263. rhok_inv = np.dot(yk, sk)
  1264. # this was handled in numeric, let it remains for more safety
  1265. # Cryptic comment above is preserved for posterity. Future reader:
  1266. # consider change to condition below proposed in gh-1261/gh-17345.
  1267. if rhok_inv == 0.:
  1268. rhok = 1000.0
  1269. if disp:
  1270. msg = "Divide-by-zero encountered: rhok assumed large"
  1271. _print_success_message_or_warn(True, msg)
  1272. else:
  1273. rhok = 1. / rhok_inv
  1274. A1 = I - sk[:, np.newaxis] * yk[np.newaxis, :] * rhok
  1275. A2 = I - yk[:, np.newaxis] * sk[np.newaxis, :] * rhok
  1276. Hk = np.dot(A1, np.dot(Hk, A2)) + (rhok * sk[:, np.newaxis] *
  1277. sk[np.newaxis, :])
  1278. fval = old_fval
  1279. if warnflag == 2:
  1280. msg = _status_message['pr_loss']
  1281. elif k >= maxiter:
  1282. warnflag = 1
  1283. msg = _status_message['maxiter']
  1284. elif np.isnan(gnorm) or np.isnan(fval) or np.isnan(xk).any():
  1285. warnflag = 3
  1286. msg = _status_message['nan']
  1287. else:
  1288. msg = _status_message['success']
  1289. if disp:
  1290. _print_success_message_or_warn(warnflag, msg)
  1291. print(f" Current function value: {fval:f}")
  1292. print(f" Iterations: {k:d}")
  1293. print(f" Function evaluations: {sf.nfev:d}")
  1294. print(f" Gradient evaluations: {sf.ngev:d}")
  1295. result = OptimizeResult(fun=fval, jac=gfk, hess_inv=Hk, nfev=sf.nfev,
  1296. njev=sf.ngev, status=warnflag,
  1297. success=(warnflag == 0), message=msg, x=xk,
  1298. nit=k)
  1299. if retall:
  1300. result['allvecs'] = allvecs
  1301. return result
  1302. def _print_success_message_or_warn(warnflag, message, warntype=None):
  1303. if not warnflag:
  1304. print(message)
  1305. else:
  1306. warnings.warn(message, warntype or OptimizeWarning, stacklevel=3)
  1307. def fmin_cg(f, x0, fprime=None, args=(), gtol=1e-5, norm=np.inf,
  1308. epsilon=_epsilon, maxiter=None, full_output=0, disp=1, retall=0,
  1309. callback=None, c1=1e-4, c2=0.4):
  1310. """
  1311. Minimize a function using a nonlinear conjugate gradient algorithm.
  1312. Parameters
  1313. ----------
  1314. f : callable, ``f(x, *args)``
  1315. Objective function to be minimized. Here `x` must be a 1-D array of
  1316. the variables that are to be changed in the search for a minimum, and
  1317. `args` are the other (fixed) parameters of `f`.
  1318. x0 : ndarray
  1319. A user-supplied initial estimate of `xopt`, the optimal value of `x`.
  1320. It must be a 1-D array of values.
  1321. fprime : callable, ``fprime(x, *args)``, optional
  1322. A function that returns the gradient of `f` at `x`. Here `x` and `args`
  1323. are as described above for `f`. The returned value must be a 1-D array.
  1324. Defaults to None, in which case the gradient is approximated
  1325. numerically (see `epsilon`, below).
  1326. args : tuple, optional
  1327. Parameter values passed to `f` and `fprime`. Must be supplied whenever
  1328. additional fixed parameters are needed to completely specify the
  1329. functions `f` and `fprime`.
  1330. gtol : float, optional
  1331. Stop when the norm of the gradient is less than `gtol`.
  1332. norm : float, optional
  1333. Order to use for the norm of the gradient
  1334. (``-np.inf`` is min, ``np.inf`` is max).
  1335. epsilon : float or ndarray, optional
  1336. Step size(s) to use when `fprime` is approximated numerically. Can be a
  1337. scalar or a 1-D array. Defaults to ``sqrt(eps)``, with eps the
  1338. floating point machine precision. Usually ``sqrt(eps)`` is about
  1339. 1.5e-8.
  1340. maxiter : int, optional
  1341. Maximum number of iterations to perform. Default is ``200 * len(x0)``.
  1342. full_output : bool, optional
  1343. If True, return `fopt`, `func_calls`, `grad_calls`, and `warnflag` in
  1344. addition to `xopt`. See the Returns section below for additional
  1345. information on optional return values.
  1346. disp : bool, optional
  1347. If True, return a convergence message, followed by `xopt`.
  1348. retall : bool, optional
  1349. If True, add to the returned values the results of each iteration.
  1350. callback : callable, optional
  1351. An optional user-supplied function, called after each iteration.
  1352. Called as ``callback(xk)``, where ``xk`` is the current value of `x0`.
  1353. c1 : float, default: 1e-4
  1354. Parameter for Armijo condition rule.
  1355. c2 : float, default: 0.4
  1356. Parameter for curvature condition rule.
  1357. Returns
  1358. -------
  1359. xopt : ndarray
  1360. Parameters which minimize f, i.e., ``f(xopt) == fopt``.
  1361. fopt : float, optional
  1362. Minimum value found, f(xopt). Only returned if `full_output` is True.
  1363. func_calls : int, optional
  1364. The number of function_calls made. Only returned if `full_output`
  1365. is True.
  1366. grad_calls : int, optional
  1367. The number of gradient calls made. Only returned if `full_output` is
  1368. True.
  1369. warnflag : int, optional
  1370. Integer value with warning status, only returned if `full_output` is
  1371. True.
  1372. 0 : Success.
  1373. 1 : The maximum number of iterations was exceeded.
  1374. 2 : Gradient and/or function calls were not changing. May indicate
  1375. that precision was lost, i.e., the routine did not converge.
  1376. 3 : NaN result encountered.
  1377. allvecs : list of ndarray, optional
  1378. List of arrays, containing the results at each iteration.
  1379. Only returned if `retall` is True.
  1380. See Also
  1381. --------
  1382. minimize : common interface to all `scipy.optimize` algorithms for
  1383. unconstrained and constrained minimization of multivariate
  1384. functions. It provides an alternative way to call
  1385. ``fmin_cg``, by specifying ``method='CG'``.
  1386. Notes
  1387. -----
  1388. This conjugate gradient algorithm is based on that of Polak and Ribiere
  1389. [1]_.
  1390. Conjugate gradient methods tend to work better when:
  1391. 1. `f` has a unique global minimizing point, and no local minima or
  1392. other stationary points,
  1393. 2. `f` is, at least locally, reasonably well approximated by a
  1394. quadratic function of the variables,
  1395. 3. `f` is continuous and has a continuous gradient,
  1396. 4. `fprime` is not too large, e.g., has a norm less than 1000,
  1397. 5. The initial guess, `x0`, is reasonably close to `f` 's global
  1398. minimizing point, `xopt`.
  1399. Parameters `c1` and `c2` must satisfy ``0 < c1 < c2 < 1``.
  1400. References
  1401. ----------
  1402. .. [1] Wright & Nocedal, "Numerical Optimization", 1999, pp. 120-122.
  1403. Examples
  1404. --------
  1405. Example 1: seek the minimum value of the expression
  1406. ``a*u**2 + b*u*v + c*v**2 + d*u + e*v + f`` for given values
  1407. of the parameters and an initial guess ``(u, v) = (0, 0)``.
  1408. >>> import numpy as np
  1409. >>> args = (2, 3, 7, 8, 9, 10) # parameter values
  1410. >>> def f(x, *args):
  1411. ... u, v = x
  1412. ... a, b, c, d, e, f = args
  1413. ... return a*u**2 + b*u*v + c*v**2 + d*u + e*v + f
  1414. >>> def gradf(x, *args):
  1415. ... u, v = x
  1416. ... a, b, c, d, e, f = args
  1417. ... gu = 2*a*u + b*v + d # u-component of the gradient
  1418. ... gv = b*u + 2*c*v + e # v-component of the gradient
  1419. ... return np.asarray((gu, gv))
  1420. >>> x0 = np.asarray((0, 0)) # Initial guess.
  1421. >>> from scipy import optimize
  1422. >>> res1 = optimize.fmin_cg(f, x0, fprime=gradf, args=args)
  1423. Optimization terminated successfully.
  1424. Current function value: 1.617021
  1425. Iterations: 4
  1426. Function evaluations: 8
  1427. Gradient evaluations: 8
  1428. >>> res1
  1429. array([-1.80851064, -0.25531915])
  1430. Example 2: solve the same problem using the `minimize` function.
  1431. (This `myopts` dictionary shows all of the available options,
  1432. although in practice only non-default values would be needed.
  1433. The returned value will be a dictionary.)
  1434. >>> opts = {'maxiter' : None, # default value.
  1435. ... 'disp' : True, # non-default value.
  1436. ... 'gtol' : 1e-5, # default value.
  1437. ... 'norm' : np.inf, # default value.
  1438. ... 'eps' : 1.4901161193847656e-08} # default value.
  1439. >>> res2 = optimize.minimize(f, x0, jac=gradf, args=args,
  1440. ... method='CG', options=opts)
  1441. Optimization terminated successfully.
  1442. Current function value: 1.617021
  1443. Iterations: 4
  1444. Function evaluations: 8
  1445. Gradient evaluations: 8
  1446. >>> res2.x # minimum found
  1447. array([-1.80851064, -0.25531915])
  1448. """
  1449. opts = {'gtol': gtol,
  1450. 'norm': norm,
  1451. 'eps': epsilon,
  1452. 'disp': disp,
  1453. 'maxiter': maxiter,
  1454. 'return_all': retall}
  1455. callback = _wrap_callback(callback)
  1456. res = _minimize_cg(f, x0, args, fprime, callback=callback, c1=c1, c2=c2,
  1457. **opts)
  1458. if full_output:
  1459. retlist = res['x'], res['fun'], res['nfev'], res['njev'], res['status']
  1460. if retall:
  1461. retlist += (res['allvecs'], )
  1462. return retlist
  1463. else:
  1464. if retall:
  1465. return res['x'], res['allvecs']
  1466. else:
  1467. return res['x']
  1468. def _minimize_cg(fun, x0, args=(), jac=None, callback=None,
  1469. gtol=1e-5, norm=np.inf, eps=_epsilon, maxiter=None,
  1470. disp=False, return_all=False, finite_diff_rel_step=None,
  1471. c1=1e-4, c2=0.4, workers=None,
  1472. **unknown_options):
  1473. """
  1474. Minimization of scalar function of one or more variables using the
  1475. conjugate gradient algorithm.
  1476. Options
  1477. -------
  1478. disp : bool
  1479. Set to True to print convergence messages.
  1480. maxiter : int
  1481. Maximum number of iterations to perform.
  1482. gtol : float
  1483. Gradient norm must be less than `gtol` before successful
  1484. termination.
  1485. norm : float
  1486. Order of norm (Inf is max, -Inf is min).
  1487. eps : float or ndarray
  1488. If `jac is None` the absolute step size used for numerical
  1489. approximation of the jacobian via forward differences.
  1490. return_all : bool, optional
  1491. Set to True to return a list of the best solution at each of the
  1492. iterations.
  1493. finite_diff_rel_step : None or array_like, optional
  1494. If ``jac in ['2-point', '3-point', 'cs']`` the relative step size to
  1495. use for numerical approximation of the jacobian. The absolute step
  1496. size is computed as ``h = rel_step * sign(x) * max(1, abs(x))``,
  1497. possibly adjusted to fit into the bounds. For ``jac='3-point'``
  1498. the sign of `h` is ignored. If None (default) then step is selected
  1499. automatically.
  1500. c1 : float, default: 1e-4
  1501. Parameter for Armijo condition rule.
  1502. c2 : float, default: 0.4
  1503. Parameter for curvature condition rule.
  1504. workers : int, map-like callable, optional
  1505. A map-like callable, such as `multiprocessing.Pool.map` for evaluating
  1506. any numerical differentiation in parallel.
  1507. This evaluation is carried out as ``workers(fun, iterable)``.
  1508. .. versionadded:: 1.16.0
  1509. Notes
  1510. -----
  1511. Parameters `c1` and `c2` must satisfy ``0 < c1 < c2 < 1``.
  1512. """
  1513. _check_unknown_options(unknown_options)
  1514. retall = return_all
  1515. x0 = asarray(x0).flatten()
  1516. if maxiter is None:
  1517. maxiter = len(x0) * 200
  1518. sf = _prepare_scalar_function(fun, x0, jac=jac, args=args, epsilon=eps,
  1519. finite_diff_rel_step=finite_diff_rel_step,
  1520. workers=workers)
  1521. f = sf.fun
  1522. myfprime = sf.grad
  1523. old_fval = f(x0)
  1524. gfk = myfprime(x0)
  1525. k = 0
  1526. xk = x0
  1527. # Sets the initial step guess to dx ~ 1
  1528. old_old_fval = old_fval + np.linalg.norm(gfk) / 2
  1529. if retall:
  1530. allvecs = [xk]
  1531. warnflag = 0
  1532. pk = -gfk
  1533. gnorm = vecnorm(gfk, ord=norm)
  1534. sigma_3 = 0.01
  1535. while (gnorm > gtol) and (k < maxiter):
  1536. deltak = np.dot(gfk, gfk)
  1537. cached_step = [None]
  1538. def polak_ribiere_powell_step(alpha, gfkp1=None):
  1539. xkp1 = xk + alpha * pk
  1540. if gfkp1 is None:
  1541. gfkp1 = myfprime(xkp1)
  1542. yk = gfkp1 - gfk
  1543. beta_k = max(0, np.dot(yk, gfkp1) / deltak)
  1544. pkp1 = -gfkp1 + beta_k * pk
  1545. gnorm = vecnorm(gfkp1, ord=norm)
  1546. return (alpha, xkp1, pkp1, gfkp1, gnorm)
  1547. def descent_condition(alpha, xkp1, fp1, gfkp1):
  1548. # Polak-Ribiere+ needs an explicit check of a sufficient
  1549. # descent condition, which is not guaranteed by strong Wolfe.
  1550. #
  1551. # See Gilbert & Nocedal, "Global convergence properties of
  1552. # conjugate gradient methods for optimization",
  1553. # SIAM J. Optimization 2, 21 (1992).
  1554. cached_step[:] = polak_ribiere_powell_step(alpha, gfkp1)
  1555. alpha, xk, pk, gfk, gnorm = cached_step
  1556. # Accept step if it leads to convergence.
  1557. if gnorm <= gtol:
  1558. return True
  1559. # Accept step if sufficient descent condition applies.
  1560. return np.dot(pk, gfk) <= -sigma_3 * np.dot(gfk, gfk)
  1561. try:
  1562. alpha_k, fc, gc, old_fval, old_old_fval, gfkp1 = \
  1563. _line_search_wolfe12(f, myfprime, xk, pk, gfk, old_fval,
  1564. old_old_fval, c1=c1, c2=c2, amin=1e-100,
  1565. amax=1e100, extra_condition=descent_condition)
  1566. except _LineSearchError:
  1567. # Line search failed to find a better solution.
  1568. warnflag = 2
  1569. break
  1570. # Reuse already computed results if possible
  1571. if alpha_k == cached_step[0]:
  1572. alpha_k, xk, pk, gfk, gnorm = cached_step
  1573. else:
  1574. alpha_k, xk, pk, gfk, gnorm = polak_ribiere_powell_step(alpha_k, gfkp1)
  1575. if retall:
  1576. allvecs.append(xk)
  1577. k += 1
  1578. intermediate_result = OptimizeResult(x=xk, fun=old_fval)
  1579. if _call_callback_maybe_halt(callback, intermediate_result):
  1580. break
  1581. fval = old_fval
  1582. if warnflag == 2:
  1583. msg = _status_message['pr_loss']
  1584. elif k >= maxiter:
  1585. warnflag = 1
  1586. msg = _status_message['maxiter']
  1587. elif np.isnan(gnorm) or np.isnan(fval) or np.isnan(xk).any():
  1588. warnflag = 3
  1589. msg = _status_message['nan']
  1590. else:
  1591. msg = _status_message['success']
  1592. if disp:
  1593. _print_success_message_or_warn(warnflag, msg)
  1594. print(f" Current function value: {fval:f}")
  1595. print(f" Iterations: {k:d}")
  1596. print(f" Function evaluations: {sf.nfev:d}")
  1597. print(f" Gradient evaluations: {sf.ngev:d}")
  1598. result = OptimizeResult(fun=fval, jac=gfk, nfev=sf.nfev,
  1599. njev=sf.ngev, status=warnflag,
  1600. success=(warnflag == 0), message=msg, x=xk,
  1601. nit=k)
  1602. if retall:
  1603. result['allvecs'] = allvecs
  1604. return result
  1605. def fmin_ncg(f, x0, fprime, fhess_p=None, fhess=None, args=(), avextol=1e-5,
  1606. epsilon=_epsilon, maxiter=None, full_output=0, disp=1, retall=0,
  1607. callback=None, c1=1e-4, c2=0.9):
  1608. """
  1609. Unconstrained minimization of a function using the Newton-CG method.
  1610. Parameters
  1611. ----------
  1612. f : callable ``f(x, *args)``
  1613. Objective function to be minimized.
  1614. x0 : ndarray
  1615. Initial guess.
  1616. fprime : callable ``f'(x, *args)``
  1617. Gradient of f.
  1618. fhess_p : callable ``fhess_p(x, p, *args)``, optional
  1619. Function which computes the Hessian of f times an
  1620. arbitrary vector, p.
  1621. fhess : callable ``fhess(x, *args)``, optional
  1622. Function to compute the Hessian matrix of f.
  1623. args : tuple, optional
  1624. Extra arguments passed to f, fprime, fhess_p, and fhess
  1625. (the same set of extra arguments is supplied to all of
  1626. these functions).
  1627. epsilon : float or ndarray, optional
  1628. If fhess is approximated, use this value for the step size.
  1629. callback : callable, optional
  1630. An optional user-supplied function which is called after
  1631. each iteration. Called as callback(xk), where xk is the
  1632. current parameter vector.
  1633. avextol : float, optional
  1634. Convergence is assumed when the average relative error in
  1635. the minimizer falls below this amount.
  1636. maxiter : int, optional
  1637. Maximum number of iterations to perform.
  1638. full_output : bool, optional
  1639. If True, return the optional outputs.
  1640. disp : bool, optional
  1641. If True, print convergence message.
  1642. retall : bool, optional
  1643. If True, return a list of results at each iteration.
  1644. c1 : float, default: 1e-4
  1645. Parameter for Armijo condition rule.
  1646. c2 : float, default: 0.9
  1647. Parameter for curvature condition rule
  1648. Returns
  1649. -------
  1650. xopt : ndarray
  1651. Parameters which minimize f, i.e., ``f(xopt) == fopt``.
  1652. fopt : float
  1653. Value of the function at xopt, i.e., ``fopt = f(xopt)``.
  1654. fcalls : int
  1655. Number of function calls made.
  1656. gcalls : int
  1657. Number of gradient calls made.
  1658. hcalls : int
  1659. Number of Hessian calls made.
  1660. warnflag : int
  1661. Warnings generated by the algorithm.
  1662. 1 : Maximum number of iterations exceeded.
  1663. 2 : Line search failure (precision loss).
  1664. 3 : NaN result encountered.
  1665. allvecs : list
  1666. The result at each iteration, if retall is True (see below).
  1667. See also
  1668. --------
  1669. minimize: Interface to minimization algorithms for multivariate
  1670. functions. See the 'Newton-CG' `method` in particular.
  1671. Notes
  1672. -----
  1673. Only one of `fhess_p` or `fhess` need to be given. If `fhess`
  1674. is provided, then `fhess_p` will be ignored. If neither `fhess`
  1675. nor `fhess_p` is provided, then the hessian product will be
  1676. approximated using finite differences on `fprime`. `fhess_p`
  1677. must compute the hessian times an arbitrary vector. If it is not
  1678. given, finite-differences on `fprime` are used to compute
  1679. it.
  1680. Newton-CG methods are also called truncated Newton methods. This
  1681. function differs from scipy.optimize.fmin_tnc because
  1682. 1. scipy.optimize.fmin_ncg is written purely in Python using NumPy
  1683. and scipy while scipy.optimize.fmin_tnc calls a C function.
  1684. 2. scipy.optimize.fmin_ncg is only for unconstrained minimization
  1685. while scipy.optimize.fmin_tnc is for unconstrained minimization
  1686. or box constrained minimization. (Box constraints give
  1687. lower and upper bounds for each variable separately.)
  1688. Parameters `c1` and `c2` must satisfy ``0 < c1 < c2 < 1``.
  1689. References
  1690. ----------
  1691. Wright & Nocedal, 'Numerical Optimization', 1999, p. 140.
  1692. """
  1693. opts = {'xtol': avextol,
  1694. 'eps': epsilon,
  1695. 'maxiter': maxiter,
  1696. 'disp': disp,
  1697. 'return_all': retall}
  1698. callback = _wrap_callback(callback)
  1699. res = _minimize_newtoncg(f, x0, args, fprime, fhess, fhess_p,
  1700. callback=callback, c1=c1, c2=c2, **opts)
  1701. if full_output:
  1702. retlist = (res['x'], res['fun'], res['nfev'], res['njev'],
  1703. res['nhev'], res['status'])
  1704. if retall:
  1705. retlist += (res['allvecs'], )
  1706. return retlist
  1707. else:
  1708. if retall:
  1709. return res['x'], res['allvecs']
  1710. else:
  1711. return res['x']
  1712. def _minimize_newtoncg(fun, x0, args=(), jac=None, hess=None, hessp=None,
  1713. callback=None, xtol=1e-5, eps=_epsilon, maxiter=None,
  1714. disp=False, return_all=False, c1=1e-4, c2=0.9, workers=None,
  1715. **unknown_options):
  1716. """
  1717. Minimization of scalar function of one or more variables using the
  1718. Newton-CG algorithm.
  1719. Note that the `jac` parameter (Jacobian) is required.
  1720. Options
  1721. -------
  1722. disp : bool
  1723. Set to True to print convergence messages.
  1724. xtol : float
  1725. Average relative error in solution `xopt` acceptable for
  1726. convergence.
  1727. maxiter : int
  1728. Maximum number of iterations to perform.
  1729. eps : float or ndarray
  1730. If `hessp` is approximated, use this value for the step size.
  1731. return_all : bool, optional
  1732. Set to True to return a list of the best solution at each of the
  1733. iterations.
  1734. c1 : float, default: 1e-4
  1735. Parameter for Armijo condition rule.
  1736. c2 : float, default: 0.9
  1737. Parameter for curvature condition rule.
  1738. workers : int, map-like callable, optional
  1739. A map-like callable, such as `multiprocessing.Pool.map` for evaluating
  1740. any numerical differentiation in parallel.
  1741. This evaluation is carried out as ``workers(fun, iterable)``.
  1742. .. versionadded:: 1.16.0
  1743. Notes
  1744. -----
  1745. Parameters `c1` and `c2` must satisfy ``0 < c1 < c2 < 1``.
  1746. """
  1747. _check_unknown_options(unknown_options)
  1748. if jac is None:
  1749. raise ValueError('Jacobian is required for Newton-CG method')
  1750. fhess_p = hessp
  1751. fhess = hess
  1752. avextol = xtol
  1753. epsilon = eps
  1754. retall = return_all
  1755. x0 = asarray(x0).flatten()
  1756. # TODO: add hessp (callable or FD) to ScalarFunction?
  1757. sf = _prepare_scalar_function(
  1758. fun, x0, jac, args=args, epsilon=eps, hess=hess, workers=workers
  1759. )
  1760. f = sf.fun
  1761. fprime = sf.grad
  1762. _h = sf.hess(x0)
  1763. # Logic for hess/hessp
  1764. # - If a callable(hess) is provided, then use that
  1765. # - If hess is a FD_METHOD, or the output from hess(x) is a LinearOperator
  1766. # then create a hessp function using those.
  1767. # - If hess is None but you have callable(hessp) then use the hessp.
  1768. # - If hess and hessp are None then approximate hessp using the grad/jac.
  1769. if (hess in FD_METHODS or isinstance(_h, LinearOperator)):
  1770. fhess = None
  1771. def _hessp(x, p, *args):
  1772. return sf.hess(x).dot(p)
  1773. fhess_p = _hessp
  1774. def terminate(warnflag, msg):
  1775. if disp:
  1776. _print_success_message_or_warn(warnflag, msg)
  1777. print(f" Current function value: {old_fval:f}")
  1778. print(f" Iterations: {k:d}")
  1779. print(f" Function evaluations: {sf.nfev:d}")
  1780. print(f" Gradient evaluations: {sf.ngev:d}")
  1781. print(f" Hessian evaluations: {hcalls:d}")
  1782. fval = old_fval
  1783. result = OptimizeResult(fun=fval, jac=gfk, nfev=sf.nfev,
  1784. njev=sf.ngev, nhev=hcalls, status=warnflag,
  1785. success=(warnflag == 0), message=msg, x=xk,
  1786. nit=k)
  1787. if retall:
  1788. result['allvecs'] = allvecs
  1789. return result
  1790. hcalls = 0
  1791. if maxiter is None:
  1792. maxiter = len(x0)*200
  1793. cg_maxiter = 20*len(x0)
  1794. xtol = len(x0) * avextol
  1795. # Make sure we enter the while loop.
  1796. update_l1norm = np.finfo(float).max
  1797. xk = np.copy(x0)
  1798. if retall:
  1799. allvecs = [xk]
  1800. k = 0
  1801. gfk = None
  1802. old_fval = f(x0)
  1803. old_old_fval = None
  1804. float64eps = np.finfo(np.float64).eps
  1805. while update_l1norm > xtol:
  1806. if k >= maxiter:
  1807. msg = "Warning: " + _status_message['maxiter']
  1808. return terminate(1, msg)
  1809. # Compute a search direction pk by applying the CG method to
  1810. # del2 f(xk) p = - grad f(xk) starting from 0.
  1811. b = -fprime(xk)
  1812. maggrad = np.linalg.norm(b, ord=1)
  1813. eta = min(0.5, math.sqrt(maggrad))
  1814. termcond = eta * maggrad
  1815. xsupi = zeros(len(x0), dtype=x0.dtype)
  1816. ri = -b
  1817. psupi = -ri
  1818. i = 0
  1819. dri0 = np.dot(ri, ri)
  1820. if fhess is not None: # you want to compute hessian once.
  1821. A = sf.hess(xk)
  1822. hcalls += 1
  1823. for k2 in range(cg_maxiter):
  1824. if np.add.reduce(np.abs(ri)) <= termcond:
  1825. break
  1826. if fhess is None:
  1827. if fhess_p is None:
  1828. Ap = approx_fhess_p(xk, psupi, fprime, epsilon)
  1829. else:
  1830. Ap = fhess_p(xk, psupi, *args)
  1831. hcalls += 1
  1832. else:
  1833. # hess was supplied as a callable or hessian update strategy, so
  1834. # A is a dense numpy array or sparse array
  1835. Ap = A.dot(psupi)
  1836. # check curvature
  1837. Ap = asarray(Ap).squeeze() # get rid of matrices...
  1838. curv = np.dot(psupi, Ap)
  1839. if 0 <= curv <= 3 * float64eps:
  1840. break
  1841. elif curv < 0:
  1842. if (i > 0):
  1843. break
  1844. else:
  1845. # fall back to steepest descent direction
  1846. xsupi = dri0 / (-curv) * b
  1847. break
  1848. alphai = dri0 / curv
  1849. xsupi += alphai * psupi
  1850. ri += alphai * Ap
  1851. dri1 = np.dot(ri, ri)
  1852. betai = dri1 / dri0
  1853. psupi = -ri + betai * psupi
  1854. i += 1
  1855. dri0 = dri1 # update np.dot(ri,ri) for next time.
  1856. else:
  1857. # curvature keeps increasing, bail out
  1858. msg = ("Warning: CG iterations didn't converge. The Hessian is not "
  1859. "positive definite.")
  1860. return terminate(3, msg)
  1861. pk = xsupi # search direction is solution to system.
  1862. gfk = -b # gradient at xk
  1863. try:
  1864. alphak, fc, gc, old_fval, old_old_fval, gfkp1 = \
  1865. _line_search_wolfe12(f, fprime, xk, pk, gfk,
  1866. old_fval, old_old_fval, c1=c1, c2=c2)
  1867. except _LineSearchError:
  1868. # Line search failed to find a better solution.
  1869. msg = "Warning: " + _status_message['pr_loss']
  1870. return terminate(2, msg)
  1871. update = alphak * pk
  1872. xk += update # upcast if necessary
  1873. if retall:
  1874. allvecs.append(xk)
  1875. k += 1
  1876. intermediate_result = OptimizeResult(x=xk, fun=old_fval)
  1877. if _call_callback_maybe_halt(callback, intermediate_result):
  1878. return terminate(5, "")
  1879. update_l1norm = np.linalg.norm(update, ord=1)
  1880. else:
  1881. if np.isnan(old_fval) or np.isnan(update_l1norm):
  1882. return terminate(3, _status_message['nan'])
  1883. msg = _status_message['success']
  1884. return terminate(0, msg)
  1885. def fminbound(func, x1, x2, args=(), xtol=1e-5, maxfun=500,
  1886. full_output=0, disp=1):
  1887. """Bounded minimization for scalar functions.
  1888. Parameters
  1889. ----------
  1890. func : callable f(x,*args)
  1891. Objective function to be minimized (must accept and return scalars).
  1892. x1, x2 : float or array scalar
  1893. Finite optimization bounds.
  1894. args : tuple, optional
  1895. Extra arguments passed to function.
  1896. xtol : float, optional
  1897. The convergence tolerance.
  1898. maxfun : int, optional
  1899. Maximum number of function evaluations allowed.
  1900. full_output : bool, optional
  1901. If True, return optional outputs.
  1902. disp: int, optional
  1903. If non-zero, print messages.
  1904. ``0`` : no message printing.
  1905. ``1`` : non-convergence notification messages only.
  1906. ``2`` : print a message on convergence too.
  1907. ``3`` : print iteration results.
  1908. Returns
  1909. -------
  1910. xopt : ndarray
  1911. Parameters (over given interval) which minimize the
  1912. objective function.
  1913. fval : number
  1914. (Optional output) The function value evaluated at the minimizer.
  1915. ierr : int
  1916. (Optional output) An error flag (0 if converged, 1 if maximum number of
  1917. function calls reached).
  1918. numfunc : int
  1919. (Optional output) The number of function calls made.
  1920. See also
  1921. --------
  1922. minimize_scalar: Interface to minimization algorithms for scalar
  1923. univariate functions. See the 'Bounded' `method` in particular.
  1924. Notes
  1925. -----
  1926. Finds a local minimizer of the scalar function `func` in the
  1927. interval x1 < xopt < x2 using Brent's method. (See `brent`
  1928. for auto-bracketing.)
  1929. References
  1930. ----------
  1931. .. [1] Forsythe, G.E., M. A. Malcolm, and C. B. Moler. "Computer Methods
  1932. for Mathematical Computations." Prentice-Hall Series in Automatic
  1933. Computation 259 (1977).
  1934. .. [2] Brent, Richard P. Algorithms for Minimization Without Derivatives.
  1935. Courier Corporation, 2013.
  1936. Examples
  1937. --------
  1938. `fminbound` finds the minimizer of the function in the given range.
  1939. The following examples illustrate this.
  1940. >>> from scipy import optimize
  1941. >>> def f(x):
  1942. ... return (x-1)**2
  1943. >>> minimizer = optimize.fminbound(f, -4, 4)
  1944. >>> minimizer
  1945. 1.0
  1946. >>> minimum = f(minimizer)
  1947. >>> minimum
  1948. 0.0
  1949. >>> res = optimize.fminbound(f, 3, 4, full_output=True)
  1950. >>> minimizer, fval, ierr, numfunc = res
  1951. >>> minimizer
  1952. 3.000005960860986
  1953. >>> minimum = f(minimizer)
  1954. >>> minimum, fval
  1955. (4.000023843479476, 4.000023843479476)
  1956. """
  1957. options = {'xatol': xtol,
  1958. 'maxiter': maxfun,
  1959. 'disp': disp}
  1960. res = _minimize_scalar_bounded(func, (x1, x2), args, **options)
  1961. if full_output:
  1962. return res['x'], res['fun'], res['status'], res['nfev']
  1963. else:
  1964. return res['x']
  1965. def _minimize_scalar_bounded(func, bounds, args=(),
  1966. xatol=1e-5, maxiter=500, disp=0,
  1967. **unknown_options):
  1968. """
  1969. Options
  1970. -------
  1971. maxiter : int
  1972. Maximum number of iterations to perform.
  1973. disp: int, optional
  1974. If non-zero, print messages.
  1975. ``0`` : no message printing.
  1976. ``1`` : non-convergence notification messages only.
  1977. ``2`` : print a message on convergence too.
  1978. ``3`` : print iteration results.
  1979. xatol : float
  1980. Absolute error in solution `xopt` acceptable for convergence.
  1981. """
  1982. _check_unknown_options(unknown_options)
  1983. maxfun = maxiter
  1984. # Test bounds are of correct form
  1985. if len(bounds) != 2:
  1986. raise ValueError('bounds must have two elements.')
  1987. x1, x2 = bounds
  1988. if not (is_finite_scalar(x1) and is_finite_scalar(x2)):
  1989. raise ValueError("Optimization bounds must be finite scalars.")
  1990. if x1 > x2:
  1991. raise ValueError("The lower bound exceeds the upper bound.")
  1992. flag = 0
  1993. header = ' Func-count x f(x) Procedure'
  1994. step = ' initial'
  1995. sqrt_eps = sqrt(2.2e-16)
  1996. golden_mean = 0.5 * (3.0 - sqrt(5.0))
  1997. a, b = x1, x2
  1998. fulc = a + golden_mean * (b - a)
  1999. nfc, xf = fulc, fulc
  2000. rat = e = 0.0
  2001. x = xf
  2002. fx = func(x, *args)
  2003. num = 1
  2004. fmin_data = (1, xf, fx)
  2005. fu = np.inf
  2006. ffulc = fnfc = fx
  2007. xm = 0.5 * (a + b)
  2008. tol1 = sqrt_eps * np.abs(xf) + xatol / 3.0
  2009. tol2 = 2.0 * tol1
  2010. if disp > 2:
  2011. print(" ")
  2012. print(header)
  2013. print("%5.0f %12.6g %12.6g %s" % (fmin_data + (step,)))
  2014. while (np.abs(xf - xm) > (tol2 - 0.5 * (b - a))):
  2015. golden = 1
  2016. # Check for parabolic fit
  2017. if np.abs(e) > tol1:
  2018. golden = 0
  2019. r = (xf - nfc) * (fx - ffulc)
  2020. q = (xf - fulc) * (fx - fnfc)
  2021. p = (xf - fulc) * q - (xf - nfc) * r
  2022. q = 2.0 * (q - r)
  2023. if q > 0.0:
  2024. p = -p
  2025. q = np.abs(q)
  2026. r = e
  2027. e = rat
  2028. # Check for acceptability of parabola
  2029. if ((np.abs(p) < np.abs(0.5*q*r)) and (p > q*(a - xf)) and
  2030. (p < q * (b - xf))):
  2031. rat = (p + 0.0) / q
  2032. x = xf + rat
  2033. step = ' parabolic'
  2034. if ((x - a) < tol2) or ((b - x) < tol2):
  2035. si = np.sign(xm - xf) + ((xm - xf) == 0)
  2036. rat = tol1 * si
  2037. else: # do a golden-section step
  2038. golden = 1
  2039. if golden: # do a golden-section step
  2040. if xf >= xm:
  2041. e = a - xf
  2042. else:
  2043. e = b - xf
  2044. rat = golden_mean*e
  2045. step = ' golden'
  2046. si = np.sign(rat) + (rat == 0)
  2047. x = xf + si * np.maximum(np.abs(rat), tol1)
  2048. fu = func(x, *args)
  2049. num += 1
  2050. fmin_data = (num, x, fu)
  2051. if disp > 2:
  2052. print("%5.0f %12.6g %12.6g %s" % (fmin_data + (step,)))
  2053. if fu <= fx:
  2054. if x >= xf:
  2055. a = xf
  2056. else:
  2057. b = xf
  2058. fulc, ffulc = nfc, fnfc
  2059. nfc, fnfc = xf, fx
  2060. xf, fx = x, fu
  2061. else:
  2062. if x < xf:
  2063. a = x
  2064. else:
  2065. b = x
  2066. if (fu <= fnfc) or (nfc == xf):
  2067. fulc, ffulc = nfc, fnfc
  2068. nfc, fnfc = x, fu
  2069. elif (fu <= ffulc) or (fulc == xf) or (fulc == nfc):
  2070. fulc, ffulc = x, fu
  2071. xm = 0.5 * (a + b)
  2072. tol1 = sqrt_eps * np.abs(xf) + xatol / 3.0
  2073. tol2 = 2.0 * tol1
  2074. if num >= maxfun:
  2075. flag = 1
  2076. break
  2077. if np.isnan(xf) or np.isnan(fx) or np.isnan(fu):
  2078. flag = 2
  2079. fval = fx
  2080. if disp > 0:
  2081. _endprint(x, flag, fval, maxfun, xatol, disp)
  2082. result = OptimizeResult(fun=fval, status=flag, success=(flag == 0),
  2083. message={0: 'Solution found.',
  2084. 1: 'Maximum number of function calls '
  2085. 'reached.',
  2086. 2: _status_message['nan']}.get(flag, ''),
  2087. x=xf, nfev=num, nit=num)
  2088. return result
  2089. class Brent:
  2090. #need to rethink design of __init__
  2091. def __init__(self, func, args=(), tol=1.48e-8, maxiter=500,
  2092. full_output=0, disp=0):
  2093. self.func = func
  2094. self.args = args
  2095. self.tol = tol
  2096. self.maxiter = maxiter
  2097. self._mintol = 1.0e-11
  2098. self._cg = 0.3819660
  2099. self.xmin = None
  2100. self.fval = None
  2101. self.iter = 0
  2102. self.funcalls = 0
  2103. self.disp = disp
  2104. # need to rethink design of set_bracket (new options, etc.)
  2105. def set_bracket(self, brack=None):
  2106. self.brack = brack
  2107. def get_bracket_info(self):
  2108. #set up
  2109. func = self.func
  2110. args = self.args
  2111. brack = self.brack
  2112. ### BEGIN core bracket_info code ###
  2113. ### carefully DOCUMENT any CHANGES in core ##
  2114. if brack is None:
  2115. xa, xb, xc, fa, fb, fc, funcalls = bracket(func, args=args)
  2116. elif len(brack) == 2:
  2117. xa, xb, xc, fa, fb, fc, funcalls = bracket(func, xa=brack[0],
  2118. xb=brack[1], args=args)
  2119. elif len(brack) == 3:
  2120. xa, xb, xc = brack
  2121. if (xa > xc): # swap so xa < xc can be assumed
  2122. xc, xa = xa, xc
  2123. if not ((xa < xb) and (xb < xc)):
  2124. raise ValueError(
  2125. "Bracketing values (xa, xb, xc) do not"
  2126. " fulfill this requirement: (xa < xb) and (xb < xc)"
  2127. )
  2128. fa = func(*((xa,) + args))
  2129. fb = func(*((xb,) + args))
  2130. fc = func(*((xc,) + args))
  2131. if not ((fb < fa) and (fb < fc)):
  2132. raise ValueError(
  2133. "Bracketing values (xa, xb, xc) do not fulfill"
  2134. " this requirement: (f(xb) < f(xa)) and (f(xb) < f(xc))"
  2135. )
  2136. funcalls = 3
  2137. else:
  2138. raise ValueError("Bracketing interval must be "
  2139. "length 2 or 3 sequence.")
  2140. ### END core bracket_info code ###
  2141. return xa, xb, xc, fa, fb, fc, funcalls
  2142. def optimize(self):
  2143. # set up for optimization
  2144. func = self.func
  2145. xa, xb, xc, fa, fb, fc, funcalls = self.get_bracket_info()
  2146. _mintol = self._mintol
  2147. _cg = self._cg
  2148. #################################
  2149. #BEGIN CORE ALGORITHM
  2150. #################################
  2151. x = w = v = xb
  2152. fw = fv = fx = fb
  2153. if (xa < xc):
  2154. a = xa
  2155. b = xc
  2156. else:
  2157. a = xc
  2158. b = xa
  2159. deltax = 0.0
  2160. iter = 0
  2161. if self.disp > 2:
  2162. print(" ")
  2163. print(f"{'Func-count':^12} {'x':^12} {'f(x)': ^12}")
  2164. print(f"{funcalls:^12g} {x:^12.6g} {fx:^12.6g}")
  2165. while (iter < self.maxiter):
  2166. tol1 = self.tol * np.abs(x) + _mintol
  2167. tol2 = 2.0 * tol1
  2168. xmid = 0.5 * (a + b)
  2169. # check for convergence
  2170. if np.abs(x - xmid) < (tol2 - 0.5 * (b - a)):
  2171. break
  2172. # XXX In the first iteration, rat is only bound in the true case
  2173. # of this conditional. This used to cause an UnboundLocalError
  2174. # (gh-4140). It should be set before the if (but to what?).
  2175. if (np.abs(deltax) <= tol1):
  2176. if (x >= xmid):
  2177. deltax = a - x # do a golden section step
  2178. else:
  2179. deltax = b - x
  2180. rat = _cg * deltax
  2181. else: # do a parabolic step
  2182. tmp1 = (x - w) * (fx - fv)
  2183. tmp2 = (x - v) * (fx - fw)
  2184. p = (x - v) * tmp2 - (x - w) * tmp1
  2185. tmp2 = 2.0 * (tmp2 - tmp1)
  2186. if (tmp2 > 0.0):
  2187. p = -p
  2188. tmp2 = np.abs(tmp2)
  2189. dx_temp = deltax
  2190. deltax = rat
  2191. # check parabolic fit
  2192. if ((p > tmp2 * (a - x)) and (p < tmp2 * (b - x)) and
  2193. (np.abs(p) < np.abs(0.5 * tmp2 * dx_temp))):
  2194. rat = p * 1.0 / tmp2 # if parabolic step is useful.
  2195. u = x + rat
  2196. if ((u - a) < tol2 or (b - u) < tol2):
  2197. if xmid - x >= 0:
  2198. rat = tol1
  2199. else:
  2200. rat = -tol1
  2201. else:
  2202. if (x >= xmid):
  2203. deltax = a - x # if it's not do a golden section step
  2204. else:
  2205. deltax = b - x
  2206. rat = _cg * deltax
  2207. if (np.abs(rat) < tol1): # update by at least tol1
  2208. if rat >= 0:
  2209. u = x + tol1
  2210. else:
  2211. u = x - tol1
  2212. else:
  2213. u = x + rat
  2214. fu = func(*((u,) + self.args)) # calculate new output value
  2215. funcalls += 1
  2216. if (fu > fx): # if it's bigger than current
  2217. if (u < x):
  2218. a = u
  2219. else:
  2220. b = u
  2221. if (fu <= fw) or (w == x):
  2222. v = w
  2223. w = u
  2224. fv = fw
  2225. fw = fu
  2226. elif (fu <= fv) or (v == x) or (v == w):
  2227. v = u
  2228. fv = fu
  2229. else:
  2230. if (u >= x):
  2231. a = x
  2232. else:
  2233. b = x
  2234. v = w
  2235. w = x
  2236. x = u
  2237. fv = fw
  2238. fw = fx
  2239. fx = fu
  2240. if self.disp > 2:
  2241. print(f"{funcalls:^12g} {x:^12.6g} {fx:^12.6g}")
  2242. iter += 1
  2243. #################################
  2244. #END CORE ALGORITHM
  2245. #################################
  2246. self.xmin = x
  2247. self.fval = fx
  2248. self.iter = iter
  2249. self.funcalls = funcalls
  2250. def get_result(self, full_output=False):
  2251. if full_output:
  2252. return self.xmin, self.fval, self.iter, self.funcalls
  2253. else:
  2254. return self.xmin
  2255. def brent(func, args=(), brack=None, tol=1.48e-8, full_output=0, maxiter=500):
  2256. """
  2257. Given a function of one variable and a possible bracket, return
  2258. a local minimizer of the function isolated to a fractional precision
  2259. of tol.
  2260. Parameters
  2261. ----------
  2262. func : callable f(x,*args)
  2263. Objective function.
  2264. args : tuple, optional
  2265. Additional arguments (if present).
  2266. brack : tuple, optional
  2267. Either a triple ``(xa, xb, xc)`` satisfying ``xa < xb < xc`` and
  2268. ``func(xb) < func(xa) and func(xb) < func(xc)``, or a pair
  2269. ``(xa, xb)`` to be used as initial points for a downhill bracket search
  2270. (see `scipy.optimize.bracket`).
  2271. The minimizer ``x`` will not necessarily satisfy ``xa <= x <= xb``.
  2272. tol : float, optional
  2273. Relative error in solution `xopt` acceptable for convergence.
  2274. full_output : bool, optional
  2275. If True, return all output args (xmin, fval, iter,
  2276. funcalls).
  2277. maxiter : int, optional
  2278. Maximum number of iterations in solution.
  2279. Returns
  2280. -------
  2281. xmin : ndarray
  2282. Optimum point.
  2283. fval : float
  2284. (Optional output) Optimum function value.
  2285. iter : int
  2286. (Optional output) Number of iterations.
  2287. funcalls : int
  2288. (Optional output) Number of objective function evaluations made.
  2289. See also
  2290. --------
  2291. minimize_scalar: Interface to minimization algorithms for scalar
  2292. univariate functions. See the 'Brent' `method` in particular.
  2293. Notes
  2294. -----
  2295. Uses inverse parabolic interpolation when possible to speed up
  2296. convergence of golden section method.
  2297. Does not ensure that the minimum lies in the range specified by
  2298. `brack`. See `scipy.optimize.fminbound`.
  2299. Examples
  2300. --------
  2301. We illustrate the behaviour of the function when `brack` is of
  2302. size 2 and 3 respectively. In the case where `brack` is of the
  2303. form ``(xa, xb)``, we can see for the given values, the output does
  2304. not necessarily lie in the range ``(xa, xb)``.
  2305. >>> def f(x):
  2306. ... return (x-1)**2
  2307. >>> from scipy import optimize
  2308. >>> minimizer = optimize.brent(f, brack=(1, 2))
  2309. >>> minimizer
  2310. 1
  2311. >>> res = optimize.brent(f, brack=(-1, 0.5, 2), full_output=True)
  2312. >>> xmin, fval, iter, funcalls = res
  2313. >>> f(xmin), fval
  2314. (0.0, 0.0)
  2315. """
  2316. options = {'xtol': tol,
  2317. 'maxiter': maxiter}
  2318. res = _minimize_scalar_brent(func, brack, args, **options)
  2319. if full_output:
  2320. return res['x'], res['fun'], res['nit'], res['nfev']
  2321. else:
  2322. return res['x']
  2323. def _minimize_scalar_brent(func, brack=None, args=(), xtol=1.48e-8,
  2324. maxiter=500, disp=0,
  2325. **unknown_options):
  2326. """
  2327. Options
  2328. -------
  2329. maxiter : int
  2330. Maximum number of iterations to perform.
  2331. xtol : float
  2332. Relative error in solution `xopt` acceptable for convergence.
  2333. disp : int, optional
  2334. If non-zero, print messages.
  2335. ``0`` : no message printing.
  2336. ``1`` : non-convergence notification messages only.
  2337. ``2`` : print a message on convergence too.
  2338. ``3`` : print iteration results.
  2339. Notes
  2340. -----
  2341. Uses inverse parabolic interpolation when possible to speed up
  2342. convergence of golden section method.
  2343. """
  2344. _check_unknown_options(unknown_options)
  2345. tol = xtol
  2346. if tol < 0:
  2347. raise ValueError(f'tolerance should be >= 0, got {tol!r}')
  2348. brent = Brent(func=func, args=args, tol=tol,
  2349. full_output=True, maxiter=maxiter, disp=disp)
  2350. brent.set_bracket(brack)
  2351. brent.optimize()
  2352. x, fval, nit, nfev = brent.get_result(full_output=True)
  2353. success = nit < maxiter and not (np.isnan(x) or np.isnan(fval))
  2354. if success:
  2355. message = ("\nOptimization terminated successfully;\n"
  2356. "The returned value satisfies the termination criteria\n"
  2357. f"(using xtol = {xtol} )")
  2358. else:
  2359. if nit >= maxiter:
  2360. message = "\nMaximum number of iterations exceeded"
  2361. if np.isnan(x) or np.isnan(fval):
  2362. message = f"{_status_message['nan']}"
  2363. if disp:
  2364. _print_success_message_or_warn(not success, message)
  2365. return OptimizeResult(fun=fval, x=x, nit=nit, nfev=nfev,
  2366. success=success, message=message)
  2367. def golden(func, args=(), brack=None, tol=_epsilon,
  2368. full_output=0, maxiter=5000):
  2369. """
  2370. Return the minimizer of a function of one variable using the golden section
  2371. method.
  2372. Given a function of one variable and a possible bracketing interval,
  2373. return a minimizer of the function isolated to a fractional precision of
  2374. tol.
  2375. Parameters
  2376. ----------
  2377. func : callable func(x,*args)
  2378. Objective function to minimize.
  2379. args : tuple, optional
  2380. Additional arguments (if present), passed to func.
  2381. brack : tuple, optional
  2382. Either a triple ``(xa, xb, xc)`` where ``xa < xb < xc`` and
  2383. ``func(xb) < func(xa) and func(xb) < func(xc)``, or a pair (xa, xb)
  2384. to be used as initial points for a downhill bracket search (see
  2385. `scipy.optimize.bracket`).
  2386. The minimizer ``x`` will not necessarily satisfy ``xa <= x <= xb``.
  2387. tol : float, optional
  2388. x tolerance stop criterion
  2389. full_output : bool, optional
  2390. If True, return optional outputs.
  2391. maxiter : int
  2392. Maximum number of iterations to perform.
  2393. Returns
  2394. -------
  2395. xmin : ndarray
  2396. Optimum point.
  2397. fval : float
  2398. (Optional output) Optimum function value.
  2399. funcalls : int
  2400. (Optional output) Number of objective function evaluations made.
  2401. See also
  2402. --------
  2403. minimize_scalar: Interface to minimization algorithms for scalar
  2404. univariate functions. See the 'Golden' `method` in particular.
  2405. Notes
  2406. -----
  2407. Uses analog of bisection method to decrease the bracketed
  2408. interval.
  2409. Examples
  2410. --------
  2411. We illustrate the behaviour of the function when `brack` is of
  2412. size 2 and 3, respectively. In the case where `brack` is of the
  2413. form (xa,xb), we can see for the given values, the output need
  2414. not necessarily lie in the range ``(xa, xb)``.
  2415. >>> def f(x):
  2416. ... return (x-1)**2
  2417. >>> from scipy import optimize
  2418. >>> minimizer = optimize.golden(f, brack=(1, 2))
  2419. >>> minimizer
  2420. 1
  2421. >>> res = optimize.golden(f, brack=(-1, 0.5, 2), full_output=True)
  2422. >>> xmin, fval, funcalls = res
  2423. >>> f(xmin), fval
  2424. (9.925165290385052e-18, 9.925165290385052e-18)
  2425. """
  2426. options = {'xtol': tol, 'maxiter': maxiter}
  2427. res = _minimize_scalar_golden(func, brack, args, **options)
  2428. if full_output:
  2429. return res['x'], res['fun'], res['nfev']
  2430. else:
  2431. return res['x']
  2432. def _minimize_scalar_golden(func, brack=None, args=(),
  2433. xtol=_epsilon, maxiter=5000, disp=0,
  2434. **unknown_options):
  2435. """
  2436. Options
  2437. -------
  2438. xtol : float
  2439. Relative error in solution `xopt` acceptable for convergence.
  2440. maxiter : int
  2441. Maximum number of iterations to perform.
  2442. disp: int, optional
  2443. If non-zero, print messages.
  2444. ``0`` : no message printing.
  2445. ``1`` : non-convergence notification messages only.
  2446. ``2`` : print a message on convergence too.
  2447. ``3`` : print iteration results.
  2448. """
  2449. _check_unknown_options(unknown_options)
  2450. tol = xtol
  2451. if brack is None:
  2452. xa, xb, xc, fa, fb, fc, funcalls = bracket(func, args=args)
  2453. elif len(brack) == 2:
  2454. xa, xb, xc, fa, fb, fc, funcalls = bracket(func, xa=brack[0],
  2455. xb=brack[1], args=args)
  2456. elif len(brack) == 3:
  2457. xa, xb, xc = brack
  2458. if (xa > xc): # swap so xa < xc can be assumed
  2459. xc, xa = xa, xc
  2460. if not ((xa < xb) and (xb < xc)):
  2461. raise ValueError(
  2462. "Bracketing values (xa, xb, xc) do not"
  2463. " fulfill this requirement: (xa < xb) and (xb < xc)"
  2464. )
  2465. fa = func(*((xa,) + args))
  2466. fb = func(*((xb,) + args))
  2467. fc = func(*((xc,) + args))
  2468. if not ((fb < fa) and (fb < fc)):
  2469. raise ValueError(
  2470. "Bracketing values (xa, xb, xc) do not fulfill"
  2471. " this requirement: (f(xb) < f(xa)) and (f(xb) < f(xc))"
  2472. )
  2473. funcalls = 3
  2474. else:
  2475. raise ValueError("Bracketing interval must be length 2 or 3 sequence.")
  2476. _gR = 0.61803399 # golden ratio conjugate: 2.0/(1.0+sqrt(5.0))
  2477. _gC = 1.0 - _gR
  2478. x3 = xc
  2479. x0 = xa
  2480. if (np.abs(xc - xb) > np.abs(xb - xa)):
  2481. x1 = xb
  2482. x2 = xb + _gC * (xc - xb)
  2483. else:
  2484. x2 = xb
  2485. x1 = xb - _gC * (xb - xa)
  2486. f1 = func(*((x1,) + args))
  2487. f2 = func(*((x2,) + args))
  2488. funcalls += 2
  2489. nit = 0
  2490. if disp > 2:
  2491. print(" ")
  2492. print(f"{'Func-count':^12} {'x':^12} {'f(x)': ^12}")
  2493. for i in range(maxiter):
  2494. if np.abs(x3 - x0) <= tol * (np.abs(x1) + np.abs(x2)):
  2495. break
  2496. if (f2 < f1):
  2497. x0 = x1
  2498. x1 = x2
  2499. x2 = _gR * x1 + _gC * x3
  2500. f1 = f2
  2501. f2 = func(*((x2,) + args))
  2502. else:
  2503. x3 = x2
  2504. x2 = x1
  2505. x1 = _gR * x2 + _gC * x0
  2506. f2 = f1
  2507. f1 = func(*((x1,) + args))
  2508. funcalls += 1
  2509. if disp > 2:
  2510. if (f1 < f2):
  2511. xmin, fval = x1, f1
  2512. else:
  2513. xmin, fval = x2, f2
  2514. print(f"{funcalls:^12g} {xmin:^12.6g} {fval:^12.6g}")
  2515. nit += 1
  2516. # end of iteration loop
  2517. if (f1 < f2):
  2518. xmin = x1
  2519. fval = f1
  2520. else:
  2521. xmin = x2
  2522. fval = f2
  2523. success = nit < maxiter and not (np.isnan(fval) or np.isnan(xmin))
  2524. if success:
  2525. message = ("\nOptimization terminated successfully;\n"
  2526. "The returned value satisfies the termination criteria\n"
  2527. f"(using xtol = {xtol} )")
  2528. else:
  2529. if nit >= maxiter:
  2530. message = "\nMaximum number of iterations exceeded"
  2531. if np.isnan(xmin) or np.isnan(fval):
  2532. message = f"{_status_message['nan']}"
  2533. if disp:
  2534. _print_success_message_or_warn(not success, message)
  2535. return OptimizeResult(fun=fval, nfev=funcalls, x=xmin, nit=nit,
  2536. success=success, message=message)
  2537. def bracket(func, xa=0.0, xb=1.0, args=(), grow_limit=110.0, maxiter=1000):
  2538. """
  2539. Bracket the minimum of a function.
  2540. Given a function and distinct initial points, search in the
  2541. downhill direction (as defined by the initial points) and return
  2542. three points that bracket the minimum of the function.
  2543. Parameters
  2544. ----------
  2545. func : callable f(x,*args)
  2546. Objective function to minimize.
  2547. xa, xb : float, optional
  2548. Initial points. Defaults `xa` to 0.0, and `xb` to 1.0.
  2549. A local minimum need not be contained within this interval.
  2550. args : tuple, optional
  2551. Additional arguments (if present), passed to `func`.
  2552. grow_limit : float, optional
  2553. Maximum grow limit. Defaults to 110.0
  2554. maxiter : int, optional
  2555. Maximum number of iterations to perform. Defaults to 1000.
  2556. Returns
  2557. -------
  2558. xa, xb, xc : float
  2559. Final points of the bracket.
  2560. fa, fb, fc : float
  2561. Objective function values at the bracket points.
  2562. funcalls : int
  2563. Number of function evaluations made.
  2564. Raises
  2565. ------
  2566. BracketError
  2567. If no valid bracket is found before the algorithm terminates.
  2568. See notes for conditions of a valid bracket.
  2569. Notes
  2570. -----
  2571. The algorithm attempts to find three strictly ordered points (i.e.
  2572. :math:`x_a < x_b < x_c` or :math:`x_c < x_b < x_a`) satisfying
  2573. :math:`f(x_b) ≤ f(x_a)` and :math:`f(x_b) ≤ f(x_c)`, where one of the
  2574. inequalities must be satisfied strictly and all :math:`x_i` must be
  2575. finite.
  2576. Examples
  2577. --------
  2578. This function can find a downward convex region of a function:
  2579. >>> import numpy as np
  2580. >>> import matplotlib.pyplot as plt
  2581. >>> from scipy.optimize import bracket
  2582. >>> def f(x):
  2583. ... return 10*x**2 + 3*x + 5
  2584. >>> x = np.linspace(-2, 2)
  2585. >>> y = f(x)
  2586. >>> init_xa, init_xb = 0.1, 1
  2587. >>> xa, xb, xc, fa, fb, fc, funcalls = bracket(f, xa=init_xa, xb=init_xb)
  2588. >>> plt.axvline(x=init_xa, color="k", linestyle="--")
  2589. >>> plt.axvline(x=init_xb, color="k", linestyle="--")
  2590. >>> plt.plot(x, y, "-k")
  2591. >>> plt.plot(xa, fa, "bx")
  2592. >>> plt.plot(xb, fb, "rx")
  2593. >>> plt.plot(xc, fc, "bx")
  2594. >>> plt.show()
  2595. Note that both initial points were to the right of the minimum, and the
  2596. third point was found in the "downhill" direction: the direction
  2597. in which the function appeared to be decreasing (to the left).
  2598. The final points are strictly ordered, and the function value
  2599. at the middle point is less than the function values at the endpoints;
  2600. it follows that a minimum must lie within the bracket.
  2601. """
  2602. _gold = 1.618034 # golden ratio: (1.0+sqrt(5.0))/2.0
  2603. _verysmall_num = 1e-21
  2604. # convert to numpy floats if not already
  2605. xa, xb = np.asarray([xa, xb])
  2606. fa = func(*(xa,) + args)
  2607. fb = func(*(xb,) + args)
  2608. if (fa < fb): # Switch so fa > fb
  2609. xa, xb = xb, xa
  2610. fa, fb = fb, fa
  2611. xc = xb + _gold * (xb - xa)
  2612. fc = func(*((xc,) + args))
  2613. funcalls = 3
  2614. iter = 0
  2615. while (fc < fb):
  2616. tmp1 = (xb - xa) * (fb - fc)
  2617. tmp2 = (xb - xc) * (fb - fa)
  2618. val = tmp2 - tmp1
  2619. if np.abs(val) < _verysmall_num:
  2620. denom = 2.0 * _verysmall_num
  2621. else:
  2622. denom = 2.0 * val
  2623. w = xb - ((xb - xc) * tmp2 - (xb - xa) * tmp1) / denom
  2624. wlim = xb + grow_limit * (xc - xb)
  2625. msg = ("No valid bracket was found before the iteration limit was "
  2626. "reached. Consider trying different initial points or "
  2627. "increasing `maxiter`.")
  2628. if iter > maxiter:
  2629. raise RuntimeError(msg)
  2630. iter += 1
  2631. if (w - xc) * (xb - w) > 0.0:
  2632. fw = func(*((w,) + args))
  2633. funcalls += 1
  2634. if (fw < fc):
  2635. xa = xb
  2636. xb = w
  2637. fa = fb
  2638. fb = fw
  2639. break
  2640. elif (fw > fb):
  2641. xc = w
  2642. fc = fw
  2643. break
  2644. w = xc + _gold * (xc - xb)
  2645. fw = func(*((w,) + args))
  2646. funcalls += 1
  2647. elif (w - wlim)*(wlim - xc) >= 0.0:
  2648. w = wlim
  2649. fw = func(*((w,) + args))
  2650. funcalls += 1
  2651. elif (w - wlim)*(xc - w) > 0.0:
  2652. fw = func(*((w,) + args))
  2653. funcalls += 1
  2654. if (fw < fc):
  2655. xb = xc
  2656. xc = w
  2657. w = xc + _gold * (xc - xb)
  2658. fb = fc
  2659. fc = fw
  2660. fw = func(*((w,) + args))
  2661. funcalls += 1
  2662. else:
  2663. w = xc + _gold * (xc - xb)
  2664. fw = func(*((w,) + args))
  2665. funcalls += 1
  2666. xa = xb
  2667. xb = xc
  2668. xc = w
  2669. fa = fb
  2670. fb = fc
  2671. fc = fw
  2672. # three conditions for a valid bracket
  2673. cond1 = (fb < fc and fb <= fa) or (fb < fa and fb <= fc)
  2674. cond2 = (xa < xb < xc or xc < xb < xa)
  2675. cond3 = np.isfinite(xa) and np.isfinite(xb) and np.isfinite(xc)
  2676. msg = ("The algorithm terminated without finding a valid bracket. "
  2677. "Consider trying different initial points.")
  2678. if not (cond1 and cond2 and cond3):
  2679. e = BracketError(msg)
  2680. e.data = (xa, xb, xc, fa, fb, fc, funcalls)
  2681. raise e
  2682. return xa, xb, xc, fa, fb, fc, funcalls
  2683. class BracketError(RuntimeError):
  2684. pass
  2685. def _recover_from_bracket_error(solver, fun, bracket, args, **options):
  2686. # `bracket` was originally written without checking whether the resulting
  2687. # bracket is valid. `brent` and `golden` built on top of it without
  2688. # checking the returned bracket for validity, and their output can be
  2689. # incorrect without warning/error if the original bracket is invalid.
  2690. # gh-14858 noticed the problem, and the following is the desired
  2691. # behavior:
  2692. # - `scipy.optimize.bracket`, `scipy.optimize.brent`, and
  2693. # `scipy.optimize.golden` should raise an error if the bracket is
  2694. # invalid, as opposed to silently returning garbage
  2695. # - `scipy.optimize.minimize_scalar` should return with `success=False`
  2696. # and other information
  2697. # The changes that would be required to achieve this the traditional
  2698. # way (`return`ing all the required information from bracket all the way
  2699. # up to `minimizer_scalar`) are extensive and invasive. (See a6aa40d.)
  2700. # We can achieve the same thing by raising the error in `bracket`, but
  2701. # storing the information needed by `minimize_scalar` in the error object,
  2702. # and intercepting it here.
  2703. try:
  2704. res = solver(fun, bracket, args, **options)
  2705. except BracketError as e:
  2706. msg = str(e)
  2707. xa, xb, xc, fa, fb, fc, funcalls = e.data
  2708. xs, fs = [xa, xb, xc], [fa, fb, fc]
  2709. if np.any(np.isnan([xs, fs])):
  2710. x, fun = np.nan, np.nan
  2711. else:
  2712. imin = np.argmin(fs)
  2713. x, fun = xs[imin], fs[imin]
  2714. return OptimizeResult(fun=fun, nfev=funcalls, x=x,
  2715. nit=0, success=False, message=msg)
  2716. return res
  2717. def _line_for_search(x0, alpha, lower_bound, upper_bound):
  2718. """
  2719. Given a parameter vector ``x0`` with length ``n`` and a direction
  2720. vector ``alpha`` with length ``n``, and lower and upper bounds on
  2721. each of the ``n`` parameters, what are the bounds on a scalar
  2722. ``l`` such that ``lower_bound <= x0 + alpha * l <= upper_bound``.
  2723. Parameters
  2724. ----------
  2725. x0 : np.array.
  2726. The vector representing the current location.
  2727. Note ``np.shape(x0) == (n,)``.
  2728. alpha : np.array.
  2729. The vector representing the direction.
  2730. Note ``np.shape(alpha) == (n,)``.
  2731. lower_bound : np.array.
  2732. The lower bounds for each parameter in ``x0``. If the ``i``th
  2733. parameter in ``x0`` is unbounded below, then ``lower_bound[i]``
  2734. should be ``-np.inf``.
  2735. Note ``np.shape(lower_bound) == (n,)``.
  2736. upper_bound : np.array.
  2737. The upper bounds for each parameter in ``x0``. If the ``i``th
  2738. parameter in ``x0`` is unbounded above, then ``upper_bound[i]``
  2739. should be ``np.inf``.
  2740. Note ``np.shape(upper_bound) == (n,)``.
  2741. Returns
  2742. -------
  2743. res : tuple ``(lmin, lmax)``
  2744. The bounds for ``l`` such that
  2745. ``lower_bound[i] <= x0[i] + alpha[i] * l <= upper_bound[i]``
  2746. for all ``i``.
  2747. """
  2748. # get nonzero indices of alpha so we don't get any zero division errors.
  2749. # alpha will not be all zero, since it is called from _linesearch_powell
  2750. # where we have a check for this.
  2751. nonzero, = alpha.nonzero()
  2752. lower_bound, upper_bound = lower_bound[nonzero], upper_bound[nonzero]
  2753. x0, alpha = x0[nonzero], alpha[nonzero]
  2754. low = (lower_bound - x0) / alpha
  2755. high = (upper_bound - x0) / alpha
  2756. # positive and negative indices
  2757. pos = alpha > 0
  2758. lmin_pos = np.where(pos, low, 0)
  2759. lmin_neg = np.where(pos, 0, high)
  2760. lmax_pos = np.where(pos, high, 0)
  2761. lmax_neg = np.where(pos, 0, low)
  2762. lmin = np.max(lmin_pos + lmin_neg)
  2763. lmax = np.min(lmax_pos + lmax_neg)
  2764. # if x0 is outside the bounds, then it is possible that there is
  2765. # no way to get back in the bounds for the parameters being updated
  2766. # with the current direction alpha.
  2767. # when this happens, lmax < lmin.
  2768. # If this is the case, then we can just return (0, 0)
  2769. return (lmin, lmax) if lmax >= lmin else (0, 0)
  2770. def _linesearch_powell(func, p, xi, tol=1e-3,
  2771. lower_bound=None, upper_bound=None, fval=None):
  2772. """Line-search algorithm using fminbound.
  2773. Find the minimum of the function ``func(x0 + alpha*direc)``.
  2774. lower_bound : np.array.
  2775. The lower bounds for each parameter in ``x0``. If the ``i``th
  2776. parameter in ``x0`` is unbounded below, then ``lower_bound[i]``
  2777. should be ``-np.inf``.
  2778. Note ``np.shape(lower_bound) == (n,)``.
  2779. upper_bound : np.array.
  2780. The upper bounds for each parameter in ``x0``. If the ``i``th
  2781. parameter in ``x0`` is unbounded above, then ``upper_bound[i]``
  2782. should be ``np.inf``.
  2783. Note ``np.shape(upper_bound) == (n,)``.
  2784. fval : number.
  2785. ``fval`` is equal to ``func(p)``, the idea is just to avoid
  2786. recomputing it so we can limit the ``fevals``.
  2787. """
  2788. def myfunc(alpha):
  2789. return func(p + alpha*xi)
  2790. # if xi is zero, then don't optimize
  2791. if not np.any(xi):
  2792. return ((fval, p, xi) if fval is not None else (func(p), p, xi))
  2793. elif lower_bound is None and upper_bound is None:
  2794. # non-bounded minimization
  2795. res = _recover_from_bracket_error(_minimize_scalar_brent,
  2796. myfunc, None, tuple(), xtol=tol)
  2797. alpha_min, fret = res.x, res.fun
  2798. xi = alpha_min * xi
  2799. return fret, p + xi, xi
  2800. else:
  2801. bound = _line_for_search(p, xi, lower_bound, upper_bound)
  2802. if np.isneginf(bound[0]) and np.isposinf(bound[1]):
  2803. # equivalent to unbounded
  2804. return _linesearch_powell(func, p, xi, fval=fval, tol=tol)
  2805. elif not np.isneginf(bound[0]) and not np.isposinf(bound[1]):
  2806. # we can use a bounded scalar minimization
  2807. res = _minimize_scalar_bounded(myfunc, bound, xatol=tol / 100)
  2808. xi = res.x * xi
  2809. return res.fun, p + xi, xi
  2810. else:
  2811. # only bounded on one side. use the tangent function to convert
  2812. # the infinity bound to a finite bound. The new bounded region
  2813. # is a subregion of the region bounded by -np.pi/2 and np.pi/2.
  2814. bound = np.arctan(bound[0]), np.arctan(bound[1])
  2815. res = _minimize_scalar_bounded(
  2816. lambda x: myfunc(np.tan(x)),
  2817. bound,
  2818. xatol=tol / 100)
  2819. xi = np.tan(res.x) * xi
  2820. return res.fun, p + xi, xi
  2821. def fmin_powell(func, x0, args=(), xtol=1e-4, ftol=1e-4, maxiter=None,
  2822. maxfun=None, full_output=0, disp=1, retall=0, callback=None,
  2823. direc=None):
  2824. """
  2825. Minimize a function using modified Powell's method.
  2826. This method only uses function values, not derivatives.
  2827. Parameters
  2828. ----------
  2829. func : callable f(x,*args)
  2830. Objective function to be minimized.
  2831. x0 : ndarray
  2832. Initial guess.
  2833. args : tuple, optional
  2834. Extra arguments passed to func.
  2835. xtol : float, optional
  2836. Line-search error tolerance.
  2837. ftol : float, optional
  2838. Relative error in ``func(xopt)`` acceptable for convergence.
  2839. maxiter : int, optional
  2840. Maximum number of iterations to perform.
  2841. maxfun : int, optional
  2842. Maximum number of function evaluations to make.
  2843. full_output : bool, optional
  2844. If True, ``fopt``, ``xi``, ``direc``, ``iter``, ``funcalls``, and
  2845. ``warnflag`` are returned.
  2846. disp : bool, optional
  2847. If True, print convergence messages.
  2848. retall : bool, optional
  2849. If True, return a list of the solution at each iteration.
  2850. callback : callable, optional
  2851. An optional user-supplied function, called after each
  2852. iteration. Called as ``callback(xk)``, where ``xk`` is the
  2853. current parameter vector.
  2854. direc : ndarray, optional
  2855. Initial fitting step and parameter order set as an (N, N) array, where N
  2856. is the number of fitting parameters in `x0`. Defaults to step size 1.0
  2857. fitting all parameters simultaneously (``np.eye((N, N))``). To
  2858. prevent initial consideration of values in a step or to change initial
  2859. step size, set to 0 or desired step size in the Jth position in the Mth
  2860. block, where J is the position in `x0` and M is the desired evaluation
  2861. step, with steps being evaluated in index order. Step size and ordering
  2862. will change freely as minimization proceeds.
  2863. Returns
  2864. -------
  2865. xopt : ndarray
  2866. Parameter which minimizes `func`.
  2867. fopt : number
  2868. Value of function at minimum: ``fopt = func(xopt)``.
  2869. direc : ndarray
  2870. Current direction set.
  2871. iter : int
  2872. Number of iterations.
  2873. funcalls : int
  2874. Number of function calls made.
  2875. warnflag : int
  2876. Integer warning flag:
  2877. 1 : Maximum number of function evaluations.
  2878. 2 : Maximum number of iterations.
  2879. 3 : NaN result encountered.
  2880. 4 : The result is out of the provided bounds.
  2881. allvecs : list
  2882. List of solutions at each iteration.
  2883. See also
  2884. --------
  2885. minimize: Interface to unconstrained minimization algorithms for
  2886. multivariate functions. See the 'Powell' method in particular.
  2887. Notes
  2888. -----
  2889. Uses a modification of Powell's method to find the minimum of
  2890. a function of N variables. Powell's method is a conjugate
  2891. direction method.
  2892. The algorithm has two loops. The outer loop merely iterates over the inner
  2893. loop. The inner loop minimizes over each current direction in the direction
  2894. set. At the end of the inner loop, if certain conditions are met, the
  2895. direction that gave the largest decrease is dropped and replaced with the
  2896. difference between the current estimated x and the estimated x from the
  2897. beginning of the inner-loop.
  2898. The technical conditions for replacing the direction of greatest
  2899. increase amount to checking that
  2900. 1. No further gain can be made along the direction of greatest increase
  2901. from that iteration.
  2902. 2. The direction of greatest increase accounted for a large sufficient
  2903. fraction of the decrease in the function value from that iteration of
  2904. the inner loop.
  2905. References
  2906. ----------
  2907. Powell M.J.D. (1964) An efficient method for finding the minimum of a
  2908. function of several variables without calculating derivatives,
  2909. Computer Journal, 7 (2):155-162.
  2910. Press W., Teukolsky S.A., Vetterling W.T., and Flannery B.P.:
  2911. Numerical Recipes (any edition), Cambridge University Press
  2912. Examples
  2913. --------
  2914. >>> def f(x):
  2915. ... return x**2
  2916. >>> from scipy import optimize
  2917. >>> minimum = optimize.fmin_powell(f, -1)
  2918. Optimization terminated successfully.
  2919. Current function value: 0.000000
  2920. Iterations: 2
  2921. Function evaluations: 16
  2922. >>> minimum
  2923. array(0.0)
  2924. """
  2925. opts = {'xtol': xtol,
  2926. 'ftol': ftol,
  2927. 'maxiter': maxiter,
  2928. 'maxfev': maxfun,
  2929. 'disp': disp,
  2930. 'direc': direc,
  2931. 'return_all': retall}
  2932. callback = _wrap_callback(callback)
  2933. res = _minimize_powell(func, x0, args, callback=callback, **opts)
  2934. if full_output:
  2935. retlist = (res['x'], res['fun'], res['direc'], res['nit'],
  2936. res['nfev'], res['status'])
  2937. if retall:
  2938. retlist += (res['allvecs'], )
  2939. return retlist
  2940. else:
  2941. if retall:
  2942. return res['x'], res['allvecs']
  2943. else:
  2944. return res['x']
  2945. def _minimize_powell(func, x0, args=(), callback=None, bounds=None,
  2946. xtol=1e-4, ftol=1e-4, maxiter=None, maxfev=None,
  2947. disp=False, direc=None, return_all=False,
  2948. **unknown_options):
  2949. """
  2950. Minimization of scalar function of one or more variables using the
  2951. modified Powell algorithm.
  2952. Parameters
  2953. ----------
  2954. fun : callable
  2955. The objective function to be minimized::
  2956. fun(x, *args) -> float
  2957. where ``x`` is a 1-D array with shape (n,) and ``args``
  2958. is a tuple of the fixed parameters needed to completely
  2959. specify the function.
  2960. x0 : ndarray, shape (n,)
  2961. Initial guess. Array of real elements of size (n,),
  2962. where ``n`` is the number of independent variables.
  2963. args : tuple, optional
  2964. Extra arguments passed to the objective function and its
  2965. derivatives (`fun`, `jac` and `hess` functions).
  2966. method : str or callable, optional
  2967. The present documentation is specific to ``method='powell'``, but other
  2968. options are available. See documentation for `scipy.optimize.minimize`.
  2969. bounds : sequence or `Bounds`, optional
  2970. Bounds on decision variables. There are two ways to specify the bounds:
  2971. 1. Instance of `Bounds` class.
  2972. 2. Sequence of ``(min, max)`` pairs for each element in `x`. None
  2973. is used to specify no bound.
  2974. If bounds are not provided, then an unbounded line search will be used.
  2975. If bounds are provided and the initial guess is within the bounds, then
  2976. every function evaluation throughout the minimization procedure will be
  2977. within the bounds. If bounds are provided, the initial guess is outside
  2978. the bounds, and `direc` is full rank (or left to default), then some
  2979. function evaluations during the first iteration may be outside the
  2980. bounds, but every function evaluation after the first iteration will be
  2981. within the bounds. If `direc` is not full rank, then some parameters
  2982. may not be optimized and the solution is not guaranteed to be within
  2983. the bounds.
  2984. options : dict, optional
  2985. A dictionary of solver options. All methods accept the following
  2986. generic options:
  2987. maxiter : int
  2988. Maximum number of iterations to perform. Depending on the
  2989. method each iteration may use several function evaluations.
  2990. disp : bool
  2991. Set to True to print convergence messages.
  2992. See method-specific options for ``method='powell'`` below.
  2993. callback : callable, optional
  2994. Called after each iteration. The signature is::
  2995. callback(xk)
  2996. where ``xk`` is the current parameter vector.
  2997. Returns
  2998. -------
  2999. res : OptimizeResult
  3000. The optimization result represented as a ``OptimizeResult`` object.
  3001. Important attributes are: ``x`` the solution array, ``success`` a
  3002. Boolean flag indicating if the optimizer exited successfully and
  3003. ``message`` which describes the cause of the termination. See
  3004. `OptimizeResult` for a description of other attributes.
  3005. Options
  3006. -------
  3007. disp : bool
  3008. Set to True to print convergence messages.
  3009. xtol : float
  3010. Relative error in solution `xopt` acceptable for convergence.
  3011. ftol : float
  3012. Relative error in ``fun(xopt)`` acceptable for convergence.
  3013. maxiter, maxfev : int
  3014. Maximum allowed number of iterations and function evaluations.
  3015. Will default to ``N*1000``, where ``N`` is the number of
  3016. variables, if neither `maxiter` or `maxfev` is set. If both
  3017. `maxiter` and `maxfev` are set, minimization will stop at the
  3018. first reached.
  3019. direc : ndarray
  3020. Initial set of direction vectors for the Powell method.
  3021. return_all : bool, optional
  3022. Set to True to return a list of the best solution at each of the
  3023. iterations.
  3024. """
  3025. _check_unknown_options(unknown_options)
  3026. maxfun = maxfev
  3027. retall = return_all
  3028. x = asarray(x0).flatten()
  3029. if retall:
  3030. allvecs = [x]
  3031. N = len(x)
  3032. # If neither are set, then set both to default
  3033. if maxiter is None and maxfun is None:
  3034. maxiter = N * 1000
  3035. maxfun = N * 1000
  3036. elif maxiter is None:
  3037. # Convert remaining Nones, to np.inf, unless the other is np.inf, in
  3038. # which case use the default to avoid unbounded iteration
  3039. if maxfun == np.inf:
  3040. maxiter = N * 1000
  3041. else:
  3042. maxiter = np.inf
  3043. elif maxfun is None:
  3044. if maxiter == np.inf:
  3045. maxfun = N * 1000
  3046. else:
  3047. maxfun = np.inf
  3048. # we need to use a mutable object here that we can update in the
  3049. # wrapper function
  3050. fcalls, func = _wrap_scalar_function_maxfun_validation(func, args, maxfun)
  3051. if direc is None:
  3052. direc = eye(N, dtype=float)
  3053. else:
  3054. direc = asarray(direc, dtype=float)
  3055. if np.linalg.matrix_rank(direc) != direc.shape[0]:
  3056. warnings.warn("direc input is not full rank, some parameters may "
  3057. "not be optimized",
  3058. OptimizeWarning, stacklevel=3)
  3059. if bounds is None:
  3060. # don't make these arrays of all +/- inf. because
  3061. # _linesearch_powell will do an unnecessary check of all the elements.
  3062. # just keep them None, _linesearch_powell will not have to check
  3063. # all the elements.
  3064. lower_bound, upper_bound = None, None
  3065. else:
  3066. # bounds is standardized in _minimize.py.
  3067. lower_bound, upper_bound = bounds.lb, bounds.ub
  3068. if np.any(lower_bound > x0) or np.any(x0 > upper_bound):
  3069. warnings.warn("Initial guess is not within the specified bounds",
  3070. OptimizeWarning, stacklevel=3)
  3071. fval = func(x)
  3072. x1 = x.copy()
  3073. iter = 0
  3074. while True:
  3075. try:
  3076. fx = fval
  3077. bigind = 0
  3078. delta = 0.0
  3079. for i in range(N):
  3080. direc1 = direc[i]
  3081. fx2 = fval
  3082. fval, x, direc1 = _linesearch_powell(func, x, direc1,
  3083. tol=xtol * 100,
  3084. lower_bound=lower_bound,
  3085. upper_bound=upper_bound,
  3086. fval=fval)
  3087. if (fx2 - fval) > delta:
  3088. delta = fx2 - fval
  3089. bigind = i
  3090. iter += 1
  3091. if retall:
  3092. allvecs.append(x)
  3093. intermediate_result = OptimizeResult(x=x, fun=fval)
  3094. if _call_callback_maybe_halt(callback, intermediate_result):
  3095. break
  3096. bnd = ftol * (np.abs(fx) + np.abs(fval)) + 1e-20
  3097. if 2.0 * (fx - fval) <= bnd:
  3098. break
  3099. if fcalls[0] >= maxfun:
  3100. break
  3101. if iter >= maxiter:
  3102. break
  3103. if np.isnan(fx) and np.isnan(fval):
  3104. # Ended up in a nan-region: bail out
  3105. break
  3106. # Construct the extrapolated point
  3107. direc1 = x - x1
  3108. x1 = x.copy()
  3109. # make sure that we don't go outside the bounds when extrapolating
  3110. if lower_bound is None and upper_bound is None:
  3111. lmax = 1
  3112. else:
  3113. _, lmax = _line_for_search(x, direc1, lower_bound, upper_bound)
  3114. x2 = x + min(lmax, 1) * direc1
  3115. fx2 = func(x2)
  3116. if (fx > fx2):
  3117. t = 2.0*(fx + fx2 - 2.0*fval)
  3118. temp = (fx - fval - delta)
  3119. t *= temp*temp
  3120. temp = fx - fx2
  3121. t -= delta*temp*temp
  3122. if t < 0.0:
  3123. fval, x, direc1 = _linesearch_powell(
  3124. func, x, direc1,
  3125. tol=xtol * 100,
  3126. lower_bound=lower_bound,
  3127. upper_bound=upper_bound,
  3128. fval=fval
  3129. )
  3130. if np.any(direc1):
  3131. direc[bigind] = direc[-1]
  3132. direc[-1] = direc1
  3133. except _MaxFuncCallError:
  3134. break
  3135. warnflag = 0
  3136. msg = _status_message['success']
  3137. # out of bounds is more urgent than exceeding function evals or iters,
  3138. # but I don't want to cause inconsistencies by changing the
  3139. # established warning flags for maxfev and maxiter, so the out of bounds
  3140. # warning flag becomes 3, but is checked for first.
  3141. if bounds and (np.any(lower_bound > x) or np.any(x > upper_bound)):
  3142. warnflag = 4
  3143. msg = _status_message['out_of_bounds']
  3144. elif fcalls[0] >= maxfun:
  3145. warnflag = 1
  3146. msg = _status_message['maxfev']
  3147. elif iter >= maxiter:
  3148. warnflag = 2
  3149. msg = _status_message['maxiter']
  3150. elif np.isnan(fval) or np.isnan(x).any():
  3151. warnflag = 3
  3152. msg = _status_message['nan']
  3153. if disp:
  3154. _print_success_message_or_warn(warnflag, msg, RuntimeWarning)
  3155. print(f" Current function value: {fval:f}")
  3156. print(f" Iterations: {iter:d}")
  3157. print(f" Function evaluations: {fcalls[0]:d}")
  3158. result = OptimizeResult(fun=fval, direc=direc, nit=iter, nfev=fcalls[0],
  3159. status=warnflag, success=(warnflag == 0),
  3160. message=msg, x=x)
  3161. if retall:
  3162. result['allvecs'] = allvecs
  3163. return result
  3164. def _endprint(x, flag, fval, maxfun, xtol, disp):
  3165. if flag == 0:
  3166. if disp > 1:
  3167. print("\nOptimization terminated successfully;\n"
  3168. "The returned value satisfies the termination criteria\n"
  3169. "(using xtol = ", xtol, ")")
  3170. return
  3171. if flag == 1:
  3172. msg = ("\nMaximum number of function evaluations exceeded --- "
  3173. "increase maxfun argument.\n")
  3174. elif flag == 2:
  3175. msg = f"\n{_status_message['nan']}"
  3176. _print_success_message_or_warn(flag, msg)
  3177. return
  3178. def brute(func, ranges, args=(), Ns=20, full_output=0, finish=fmin,
  3179. disp=False, workers=1):
  3180. """Minimize a function over a given range by brute force.
  3181. Uses the "brute force" method, i.e., computes the function's value
  3182. at each point of a multidimensional grid of points, to find the global
  3183. minimum of the function.
  3184. The function is evaluated everywhere in the range with the datatype of the
  3185. first call to the function, as enforced by the ``vectorize`` NumPy
  3186. function. The value and type of the function evaluation returned when
  3187. ``full_output=True`` are affected in addition by the ``finish`` argument
  3188. (see Notes).
  3189. The brute force approach is inefficient because the number of grid points
  3190. increases exponentially - the number of grid points to evaluate is
  3191. ``Ns ** len(x)``. Consequently, even with coarse grid spacing, even
  3192. moderately sized problems can take a long time to run, and/or run into
  3193. memory limitations.
  3194. Parameters
  3195. ----------
  3196. func : callable
  3197. The objective function to be minimized. Must be in the
  3198. form ``f(x, *args)``, where ``x`` is the argument in
  3199. the form of a 1-D array and ``args`` is a tuple of any
  3200. additional fixed parameters needed to completely specify
  3201. the function.
  3202. ranges : tuple
  3203. Each component of the `ranges` tuple must be either a
  3204. "slice object" or a range tuple of the form ``(low, high)``.
  3205. The program uses these to create the grid of points on which
  3206. the objective function will be computed. See `Note 2` for
  3207. more detail.
  3208. args : tuple, optional
  3209. Any additional fixed parameters needed to completely specify
  3210. the function.
  3211. Ns : int, optional
  3212. Number of grid points along the axes, if not otherwise
  3213. specified. See `Note2`.
  3214. full_output : bool, optional
  3215. If True, return the evaluation grid and the objective function's
  3216. values on it.
  3217. finish : callable, optional
  3218. An optimization function that is called with the result of brute force
  3219. minimization as initial guess. `finish` should take `func` and
  3220. the initial guess as positional arguments, and take `args` as
  3221. keyword arguments. It may additionally take `full_output`
  3222. and/or `disp` as keyword arguments. Use None if no "polishing"
  3223. function is to be used. See Notes for more details.
  3224. disp : bool, optional
  3225. Set to True to print convergence messages from the `finish` callable.
  3226. workers : int or map-like callable, optional
  3227. If `workers` is an int the grid is subdivided into `workers`
  3228. sections and evaluated in parallel (uses
  3229. `multiprocessing.Pool <multiprocessing>`).
  3230. Supply `-1` to use all cores available to the Process.
  3231. Alternatively supply a map-like callable, such as
  3232. `multiprocessing.Pool.map` for evaluating the grid in parallel.
  3233. This evaluation is carried out as ``workers(func, iterable)``.
  3234. Requires that `func` be pickleable.
  3235. .. versionadded:: 1.3.0
  3236. Returns
  3237. -------
  3238. x0 : ndarray
  3239. A 1-D array containing the coordinates of a point at which the
  3240. objective function had its minimum value. (See `Note 1` for
  3241. which point is returned.)
  3242. fval : float
  3243. Function value at the point `x0`. (Returned when `full_output` is
  3244. True.)
  3245. grid : tuple
  3246. Representation of the evaluation grid. It has the same
  3247. length as `x0`. (Returned when `full_output` is True.)
  3248. Jout : ndarray
  3249. Function values at each point of the evaluation
  3250. grid, i.e., ``Jout = func(*grid)``. (Returned
  3251. when `full_output` is True.)
  3252. See Also
  3253. --------
  3254. basinhopping, differential_evolution
  3255. Notes
  3256. -----
  3257. *Note 1*: The program finds the gridpoint at which the lowest value
  3258. of the objective function occurs. If `finish` is None, that is the
  3259. point returned. When the global minimum occurs within (or not very far
  3260. outside) the grid's boundaries, and the grid is fine enough, that
  3261. point will be in the neighborhood of the global minimum.
  3262. However, users often employ some other optimization program to
  3263. "polish" the gridpoint values, i.e., to seek a more precise
  3264. (local) minimum near `brute's` best gridpoint.
  3265. The `brute` function's `finish` option provides a convenient way to do
  3266. that. Any polishing program used must take `brute's` output as its
  3267. initial guess as a positional argument, and take `brute's` input values
  3268. for `args` as keyword arguments, otherwise an error will be raised.
  3269. It may additionally take `full_output` and/or `disp` as keyword arguments.
  3270. `brute` assumes that the `finish` function returns either an
  3271. `OptimizeResult` object or a tuple in the form:
  3272. ``(xmin, Jmin, ... , statuscode)``, where ``xmin`` is the minimizing
  3273. value of the argument, ``Jmin`` is the minimum value of the objective
  3274. function, "..." may be some other returned values (which are not used
  3275. by `brute`), and ``statuscode`` is the status code of the `finish` program.
  3276. Note that when `finish` is not None, the values returned are those
  3277. of the `finish` program, *not* the gridpoint ones. Consequently,
  3278. while `brute` confines its search to the input grid points,
  3279. the `finish` program's results usually will not coincide with any
  3280. gridpoint, and may fall outside the grid's boundary. Thus, if a
  3281. minimum only needs to be found over the provided grid points, make
  3282. sure to pass in ``finish=None``.
  3283. *Note 2*: The grid of points is a `numpy.mgrid` object.
  3284. For `brute` the `ranges` and `Ns` inputs have the following effect.
  3285. Each component of the `ranges` tuple can be either a slice object or a
  3286. two-tuple giving a range of values, such as (0, 5). If the component is a
  3287. slice object, `brute` uses it directly. If the component is a two-tuple
  3288. range, `brute` internally converts it to a slice object that interpolates
  3289. `Ns` points from its low-value to its high-value, inclusive.
  3290. Examples
  3291. --------
  3292. We illustrate the use of `brute` to seek the global minimum of a function
  3293. of two variables that is given as the sum of a positive-definite
  3294. quadratic and two deep "Gaussian-shaped" craters. Specifically, define
  3295. the objective function `f` as the sum of three other functions,
  3296. ``f = f1 + f2 + f3``. We suppose each of these has a signature
  3297. ``(z, *params)``, where ``z = (x, y)``, and ``params`` and the functions
  3298. are as defined below.
  3299. >>> import numpy as np
  3300. >>> params = (2, 3, 7, 8, 9, 10, 44, -1, 2, 26, 1, -2, 0.5)
  3301. >>> def f1(z, *params):
  3302. ... x, y = z
  3303. ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params
  3304. ... return (a * x**2 + b * x * y + c * y**2 + d*x + e*y + f)
  3305. >>> def f2(z, *params):
  3306. ... x, y = z
  3307. ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params
  3308. ... return (-g*np.exp(-((x-h)**2 + (y-i)**2) / scale))
  3309. >>> def f3(z, *params):
  3310. ... x, y = z
  3311. ... a, b, c, d, e, f, g, h, i, j, k, l, scale = params
  3312. ... return (-j*np.exp(-((x-k)**2 + (y-l)**2) / scale))
  3313. >>> def f(z, *params):
  3314. ... return f1(z, *params) + f2(z, *params) + f3(z, *params)
  3315. Thus, the objective function may have local minima near the minimum
  3316. of each of the three functions of which it is composed. To
  3317. use `fmin` to polish its gridpoint result, we may then continue as
  3318. follows:
  3319. >>> rranges = (slice(-4, 4, 0.25), slice(-4, 4, 0.25))
  3320. >>> from scipy import optimize
  3321. >>> resbrute = optimize.brute(f, rranges, args=params, full_output=True,
  3322. ... finish=optimize.fmin)
  3323. >>> resbrute[0] # global minimum
  3324. array([-1.05665192, 1.80834843])
  3325. >>> resbrute[1] # function value at global minimum
  3326. -3.4085818767
  3327. Note that if `finish` had been set to None, we would have gotten the
  3328. gridpoint [-1.0 1.75] where the rounded function value is -2.892.
  3329. """
  3330. N = len(ranges)
  3331. if N > 40:
  3332. raise ValueError("Brute Force not possible with more "
  3333. "than 40 variables.")
  3334. lrange = list(ranges)
  3335. for k in range(N):
  3336. if not isinstance(lrange[k], slice):
  3337. if len(lrange[k]) < 3:
  3338. lrange[k] = tuple(lrange[k]) + (complex(Ns),)
  3339. lrange[k] = slice(*lrange[k])
  3340. if (N == 1):
  3341. lrange = lrange[0]
  3342. grid = np.mgrid[lrange]
  3343. # obtain an array of parameters that is iterable by a map-like callable
  3344. inpt_shape = grid.shape
  3345. if (N > 1):
  3346. grid = np.reshape(grid, (inpt_shape[0], np.prod(inpt_shape[1:]))).T
  3347. if not np.iterable(args):
  3348. args = (args,)
  3349. wrapped_func = _Brute_Wrapper(func, args)
  3350. # iterate over input arrays, possibly in parallel
  3351. with MapWrapper(pool=workers) as mapper:
  3352. Jout = np.array(list(mapper(wrapped_func, grid)))
  3353. if (N == 1):
  3354. grid = (grid,)
  3355. Jout = np.squeeze(Jout)
  3356. elif (N > 1):
  3357. Jout = np.reshape(Jout, inpt_shape[1:])
  3358. grid = np.reshape(grid.T, inpt_shape)
  3359. Nshape = shape(Jout)
  3360. indx = argmin(Jout.ravel(), axis=-1)
  3361. Nindx = np.empty(N, int)
  3362. xmin = np.empty(N, float)
  3363. for k in range(N - 1, -1, -1):
  3364. thisN = Nshape[k]
  3365. Nindx[k] = indx % Nshape[k]
  3366. indx = indx // thisN
  3367. for k in range(N):
  3368. xmin[k] = grid[k][tuple(Nindx)]
  3369. Jmin = Jout[tuple(Nindx)]
  3370. if (N == 1):
  3371. grid = grid[0]
  3372. xmin = xmin[0]
  3373. if callable(finish):
  3374. # set up kwargs for `finish` function
  3375. finish_args = _getfullargspec(finish).args
  3376. finish_kwargs = dict()
  3377. if 'full_output' in finish_args:
  3378. finish_kwargs['full_output'] = 1
  3379. if 'disp' in finish_args:
  3380. finish_kwargs['disp'] = disp
  3381. elif 'options' in finish_args:
  3382. # pass 'disp' as `options`
  3383. # (e.g., if `finish` is `minimize`)
  3384. finish_kwargs['options'] = {'disp': disp}
  3385. # run minimizer
  3386. res = finish(func, xmin, args=args, **finish_kwargs)
  3387. if isinstance(res, OptimizeResult):
  3388. xmin = res.x
  3389. Jmin = res.fun
  3390. success = res.success
  3391. else:
  3392. xmin = res[0]
  3393. Jmin = res[1]
  3394. success = res[-1] == 0
  3395. if not success:
  3396. if disp:
  3397. warnings.warn("Either final optimization did not succeed or `finish` "
  3398. "does not return `statuscode` as its last argument.",
  3399. RuntimeWarning, stacklevel=2)
  3400. if full_output:
  3401. return xmin, Jmin, grid, Jout
  3402. else:
  3403. return xmin
  3404. class _Brute_Wrapper:
  3405. """
  3406. Object to wrap user cost function for optimize.brute, allowing picklability
  3407. """
  3408. def __init__(self, f, args):
  3409. self.f = f
  3410. self.args = [] if args is None else args
  3411. def __call__(self, x):
  3412. # flatten needed for one dimensional case.
  3413. return self.f(np.asarray(x).flatten(), *self.args)
  3414. def show_options(solver=None, method=None, disp=True):
  3415. """
  3416. Show documentation for additional options of optimization solvers.
  3417. These are method-specific options that can be supplied through the
  3418. ``options`` dict.
  3419. Parameters
  3420. ----------
  3421. solver : str
  3422. Type of optimization solver. One of 'minimize', 'minimize_scalar',
  3423. 'root', 'root_scalar', 'linprog', or 'quadratic_assignment'.
  3424. method : str, optional
  3425. If not given, shows all methods of the specified solver. Otherwise,
  3426. show only the options for the specified method. Valid values
  3427. corresponds to methods' names of respective solver (e.g., 'BFGS' for
  3428. 'minimize').
  3429. disp : bool, optional
  3430. Whether to print the result rather than returning it.
  3431. Returns
  3432. -------
  3433. text
  3434. Either None (for disp=True) or the text string (disp=False)
  3435. Notes
  3436. -----
  3437. The solver-specific methods are:
  3438. `scipy.optimize.minimize`
  3439. - :ref:`Nelder-Mead <optimize.minimize-neldermead>`
  3440. - :ref:`Powell <optimize.minimize-powell>`
  3441. - :ref:`CG <optimize.minimize-cg>`
  3442. - :ref:`BFGS <optimize.minimize-bfgs>`
  3443. - :ref:`Newton-CG <optimize.minimize-newtoncg>`
  3444. - :ref:`L-BFGS-B <optimize.minimize-lbfgsb>`
  3445. - :ref:`TNC <optimize.minimize-tnc>`
  3446. - :ref:`COBYLA <optimize.minimize-cobyla>`
  3447. - :ref:`COBYQA <optimize.minimize-cobyqa>`
  3448. - :ref:`SLSQP <optimize.minimize-slsqp>`
  3449. - :ref:`dogleg <optimize.minimize-dogleg>`
  3450. - :ref:`trust-ncg <optimize.minimize-trustncg>`
  3451. `scipy.optimize.root`
  3452. - :ref:`hybr <optimize.root-hybr>`
  3453. - :ref:`lm <optimize.root-lm>`
  3454. - :ref:`broyden1 <optimize.root-broyden1>`
  3455. - :ref:`broyden2 <optimize.root-broyden2>`
  3456. - :ref:`anderson <optimize.root-anderson>`
  3457. - :ref:`linearmixing <optimize.root-linearmixing>`
  3458. - :ref:`diagbroyden <optimize.root-diagbroyden>`
  3459. - :ref:`excitingmixing <optimize.root-excitingmixing>`
  3460. - :ref:`krylov <optimize.root-krylov>`
  3461. - :ref:`df-sane <optimize.root-dfsane>`
  3462. `scipy.optimize.minimize_scalar`
  3463. - :ref:`brent <optimize.minimize_scalar-brent>`
  3464. - :ref:`golden <optimize.minimize_scalar-golden>`
  3465. - :ref:`bounded <optimize.minimize_scalar-bounded>`
  3466. `scipy.optimize.root_scalar`
  3467. - :ref:`bisect <optimize.root_scalar-bisect>`
  3468. - :ref:`brentq <optimize.root_scalar-brentq>`
  3469. - :ref:`brenth <optimize.root_scalar-brenth>`
  3470. - :ref:`ridder <optimize.root_scalar-ridder>`
  3471. - :ref:`toms748 <optimize.root_scalar-toms748>`
  3472. - :ref:`newton <optimize.root_scalar-newton>`
  3473. - :ref:`secant <optimize.root_scalar-secant>`
  3474. - :ref:`halley <optimize.root_scalar-halley>`
  3475. `scipy.optimize.linprog`
  3476. - :ref:`simplex <optimize.linprog-simplex>`
  3477. - :ref:`interior-point <optimize.linprog-interior-point>`
  3478. - :ref:`revised simplex <optimize.linprog-revised_simplex>`
  3479. - :ref:`highs <optimize.linprog-highs>`
  3480. - :ref:`highs-ds <optimize.linprog-highs-ds>`
  3481. - :ref:`highs-ipm <optimize.linprog-highs-ipm>`
  3482. `scipy.optimize.quadratic_assignment`
  3483. - :ref:`faq <optimize.qap-faq>`
  3484. - :ref:`2opt <optimize.qap-2opt>`
  3485. Examples
  3486. --------
  3487. We can print documentations of a solver in stdout:
  3488. >>> from scipy.optimize import show_options
  3489. >>> show_options(solver="minimize")
  3490. ...
  3491. Specifying a method is possible:
  3492. >>> show_options(solver="minimize", method="Nelder-Mead")
  3493. ...
  3494. We can also get the documentations as a string:
  3495. >>> show_options(solver="minimize", method="Nelder-Mead", disp=False)
  3496. Minimization of scalar function of one or more variables using the ...
  3497. """
  3498. import textwrap
  3499. doc_routines = {
  3500. 'minimize': (
  3501. ('bfgs', 'scipy.optimize._optimize._minimize_bfgs'),
  3502. ('cg', 'scipy.optimize._optimize._minimize_cg'),
  3503. ('cobyla', 'scipy.optimize._cobyla_py._minimize_cobyla'),
  3504. ('cobyqa', 'scipy.optimize._cobyqa_py._minimize_cobyqa'),
  3505. ('dogleg', 'scipy.optimize._trustregion_dogleg._minimize_dogleg'),
  3506. ('l-bfgs-b', 'scipy.optimize._lbfgsb_py._minimize_lbfgsb'),
  3507. ('nelder-mead', 'scipy.optimize._optimize._minimize_neldermead'),
  3508. ('newton-cg', 'scipy.optimize._optimize._minimize_newtoncg'),
  3509. ('powell', 'scipy.optimize._optimize._minimize_powell'),
  3510. ('slsqp', 'scipy.optimize._slsqp_py._minimize_slsqp'),
  3511. ('tnc', 'scipy.optimize._tnc._minimize_tnc'),
  3512. ('trust-ncg',
  3513. 'scipy.optimize._trustregion_ncg._minimize_trust_ncg'),
  3514. ('trust-constr',
  3515. 'scipy.optimize._trustregion_constr.'
  3516. '_minimize_trustregion_constr'),
  3517. ('trust-exact',
  3518. 'scipy.optimize._trustregion_exact._minimize_trustregion_exact'),
  3519. ('trust-krylov',
  3520. 'scipy.optimize._trustregion_krylov._minimize_trust_krylov'),
  3521. ),
  3522. 'root': (
  3523. ('hybr', 'scipy.optimize._minpack_py._root_hybr'),
  3524. ('lm', 'scipy.optimize._root._root_leastsq'),
  3525. ('broyden1', 'scipy.optimize._root._root_broyden1_doc'),
  3526. ('broyden2', 'scipy.optimize._root._root_broyden2_doc'),
  3527. ('anderson', 'scipy.optimize._root._root_anderson_doc'),
  3528. ('diagbroyden', 'scipy.optimize._root._root_diagbroyden_doc'),
  3529. ('excitingmixing', 'scipy.optimize._root._root_excitingmixing_doc'),
  3530. ('linearmixing', 'scipy.optimize._root._root_linearmixing_doc'),
  3531. ('krylov', 'scipy.optimize._root._root_krylov_doc'),
  3532. ('df-sane', 'scipy.optimize._spectral._root_df_sane'),
  3533. ),
  3534. 'root_scalar': (
  3535. ('bisect', 'scipy.optimize._root_scalar._root_scalar_bisect_doc'),
  3536. ('brentq', 'scipy.optimize._root_scalar._root_scalar_brentq_doc'),
  3537. ('brenth', 'scipy.optimize._root_scalar._root_scalar_brenth_doc'),
  3538. ('ridder', 'scipy.optimize._root_scalar._root_scalar_ridder_doc'),
  3539. ('toms748', 'scipy.optimize._root_scalar._root_scalar_toms748_doc'),
  3540. ('secant', 'scipy.optimize._root_scalar._root_scalar_secant_doc'),
  3541. ('newton', 'scipy.optimize._root_scalar._root_scalar_newton_doc'),
  3542. ('halley', 'scipy.optimize._root_scalar._root_scalar_halley_doc'),
  3543. ),
  3544. 'linprog': (
  3545. ('simplex', 'scipy.optimize._linprog._linprog_simplex_doc'),
  3546. ('interior-point', 'scipy.optimize._linprog._linprog_ip_doc'),
  3547. ('revised simplex', 'scipy.optimize._linprog._linprog_rs_doc'),
  3548. ('highs-ipm', 'scipy.optimize._linprog._linprog_highs_ipm_doc'),
  3549. ('highs-ds', 'scipy.optimize._linprog._linprog_highs_ds_doc'),
  3550. ('highs', 'scipy.optimize._linprog._linprog_highs_doc'),
  3551. ),
  3552. 'quadratic_assignment': (
  3553. ('faq', 'scipy.optimize._qap._quadratic_assignment_faq'),
  3554. ('2opt', 'scipy.optimize._qap._quadratic_assignment_2opt'),
  3555. ),
  3556. 'minimize_scalar': (
  3557. ('brent', 'scipy.optimize._optimize._minimize_scalar_brent'),
  3558. ('bounded', 'scipy.optimize._optimize._minimize_scalar_bounded'),
  3559. ('golden', 'scipy.optimize._optimize._minimize_scalar_golden'),
  3560. ),
  3561. }
  3562. if solver is None:
  3563. text = ["\n\n\n========\n", "minimize\n", "========\n"]
  3564. text.append(show_options('minimize', disp=False))
  3565. text.extend(["\n\n===============\n", "minimize_scalar\n",
  3566. "===============\n"])
  3567. text.append(show_options('minimize_scalar', disp=False))
  3568. text.extend(["\n\n\n====\n", "root\n",
  3569. "====\n"])
  3570. text.append(show_options('root', disp=False))
  3571. text.extend(['\n\n\n=======\n', 'linprog\n',
  3572. '=======\n'])
  3573. text.append(show_options('linprog', disp=False))
  3574. text = "".join(text)
  3575. else:
  3576. solver = solver.lower()
  3577. if solver not in doc_routines:
  3578. raise ValueError(f'Unknown solver {solver!r}')
  3579. if method is None:
  3580. text = []
  3581. for name, _ in doc_routines[solver]:
  3582. text.extend(["\n\n" + name, "\n" + "="*len(name) + "\n\n"])
  3583. text.append(show_options(solver, name, disp=False))
  3584. text = "".join(text)
  3585. else:
  3586. method = method.lower()
  3587. methods = dict(doc_routines[solver])
  3588. if method not in methods:
  3589. raise ValueError(f"Unknown method {method!r}")
  3590. name = methods[method]
  3591. # Import function object
  3592. parts = name.split('.')
  3593. mod_name = ".".join(parts[:-1])
  3594. __import__(mod_name)
  3595. obj = getattr(sys.modules[mod_name], parts[-1])
  3596. # Get doc
  3597. doc = obj.__doc__
  3598. if doc is not None:
  3599. text = textwrap.dedent(doc).strip()
  3600. else:
  3601. text = ""
  3602. if disp:
  3603. print(text)
  3604. return
  3605. else:
  3606. return text