Skip to content

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

Merged
merged 5 commits into from
May 15, 2018

Conversation

pvanmulbregt
Copy link
Contributor

Added keyword args full_output=False, disp=True to optimize.newton(...)
to better match the other zero finders. The signature is now

newton(func, x0, fprime=None, args=(), tol=1.48e-08, maxiter=50, fprime2=None, 
       full_output=False, disp=True)

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.

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):
Copy link
Member

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)

Copy link
Contributor Author

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.

Copy link
Member

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...

Copy link
Contributor Author

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.

Copy link
Member

@pv pv left a 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:
Copy link
Member

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.
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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?

from numpy.testing import assert_raises

def _assert_raises_regex(exception_class, _, *args, **kwargs):
assert_raises(exception_class, *args, **kwargs)
Copy link
Member

@pv pv May 10, 2018

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.
@pv pv merged commit 152a2a7 into scipy:master May 15, 2018
@pv
Copy link
Member

pv commented May 15, 2018

Thanks, merged. Sorry for not fully awake review...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants