-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
ENH: Add full_output support to optimize.newton() #8803
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Added keyword args full_output=False, disp=True to optimize.newton(...) to better match the other zero finders. The default values preserve the current behavior. Setting full_output=True causes a RootResults object to be returned with information on the total number of function_calls and iterations. Setting disp=False suppresses the RuntimeError associated with non-convergence, and is likely best combined with full_output=True.
# Newton-Raphson method | ||
def newton(func, x0, fprime=None, args=(), tol=1.48e-8, maxiter=50, | ||
fprime2=None): | ||
fprime2=None, | ||
full_output=False, disp=True): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New keyword arguments need to be added last (otherwise they can break backward compat)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aren't the new keywords full_output
and disp
added last? fprime2
was the last argument, and full_output
and disp
appear after fprime2
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, sorry I didn't notice also disp was new...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem, thanks for looking at it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some comments, otherwise LGTM.
Please also add a test for the full_output option.
msg = "Failed to converge after %d iterations, value is %s" % (maxiter, p) | ||
raise RuntimeError(msg) | ||
funcalls += 1 | ||
if disp: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
... this then becomes if not full_output:
.
True, the return value is ``(x, r)``, where `x` is the root, and `r` is | ||
a RootResults object. | ||
disp : bool, optional | ||
If True, display a RuntimeError if the algorithm didn't converge. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if disp
is the right name for this, because the old behavior is to raise an exception on convergence failure, not only display it. Typically I think disp
was used to print progress during iterations to stdout, which is not what it means here.
I'd suggest removing the disp
keyword argument, and retain the error-raising behavior only for not full_output
. This is how it works e.g. in fsolve
and elsewhere, so here we probably should follow suit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One reason I added the disp
keyword was for compatibility with all the other solvers in zeros.py
: bisect
, brentq
, brenth
, ridder
. It is also the case that testing all root-finder methods within a uniform testing framework is much simpler if both the full_output
and disp
keywords are present.
I looked for the actual usages of disp
and found call_solver
in optimize/zeros.c
which sets PyExc_RuntimeError
with an error message and returns NULL if the solver fails to converge. I didn't find any progress reporting in these solvers, only reporting of convergence errors.
Are you suggesting that perhaps all the zeros solvers (brentq/ridder/...
) should match fsolve
and not have the disp
keyword?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I did not remember the 1D solvers are inconsistent with fsolve. Then I guess it's best to have this as it is and follow the 1D solver example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests for full_output
and disp
options are now added; newton()
consistent with the 1D solvers; pytest.raises
is used instead of numpy.testing.assert_raises_regex
. Any other changes needed?
scipy/optimize/tests/test_zeros.py
Outdated
from numpy.testing import assert_raises | ||
|
||
def _assert_raises_regex(exception_class, _, *args, **kwargs): | ||
assert_raises(exception_class, *args, **kwargs) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use with pytest.raises(SomeException, match="message regex"): some_call(...)
instead.
Numpy's assert_raises requires nose, which we'd like to deprecate eventually.
Use pytest.raises() instead of numpy._assert_raises_regex() Replace transcendental functions with polynomials when testing the number of iterations in optimize.zeros.newton() to avoid platform-dependent exp/sin/cos.
Thanks, merged. Sorry for not fully awake review... |
Signed-off-by: Mark Mikofski <[email protected]>
Added keyword args
full_output=False
,disp=True
tooptimize.newton(...)
to better match the other zero finders. The signature is now
The default values preserve the current behavior.
Setting
full_output=True
causes aRootResults
object to be returned withinformation on the total number of function_calls and iterations.
Setting
disp=False
suppresses the RuntimeError associated withnon-convergence, and is likely best combined with
full_output=True
.