question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ENH: initialize params->error_num to zero in optimize/Zeros/*.c

See original GitHub issue

problem

Currently if you call the c functions in optimize/Zeros/ and they successfully converge, you get garbage b/c the value params->error_num is never initialized, instead it’s only set if there is either SIGNERR or CONVERR.

proposal

The other values in params are initialized to zero, so is there any reason why the error number can’t also be initialized as zero? In the Python extension module _zeros, the flag output is initialized as zero so if params->error_num is neither SIGNERR nor CONVERR, then flag stays zero, which in zeros.RootResults maps to CONVERGED. So is it okay to set params->error_num to zero in the optimizeZeros/*.c for consistency?

Reproducing code example:

In PR #8431 Jupyter notebook there’s an example that calls brentq.c and shows the full output with garbage in params->error_num

>>> %%cython
>>> from scipy.optimize.cython_optimize cimport zeros_tuple
>>> from scipy.optimize.cython_optimize.examples.zeros_tuple_examples cimport f_solarcell

>>> ARGS = (5.25, 6.0, 1e-09, 0.004, 10.0, 0.27456)
>>> XTOL, RTOL, MITR = 0.001, 0.001, 10


>>> cdef scipy_brent_full_output solarcell_brentq_full_output(tuple args, double xa, double xb, double xtol, double rtol, int mitr):
...     cdef scipy_brent_full_output full_output
...     zeros_tuple.brentq(f_solarcell, xa, xb, args, xtol, rtol, mitr,
...                        <zeros_tuple.scipy_zeros_parameters *> &full_output)
...     return full_output  # root = 5.255231961257658 not shown


>>> print(solarcell_brentq_full_output(ARGS, 0.0, 6.0, XTOL, RTOL, MITR))
{'error_num': -1874247292,  # <- this means it converged, since it's not -1 or -2
 'funcalls': 4,
 'iterations': 3}

By contrast, the optimize/cython_optimize/Newton/*.c functions initialize params->error_num = 0 so their output is more meaningful. Here’s another example from the Cython Optimize Zeros API Jupyter notebook that calls newton.c with full output.

>>> %%cython
>>> from scipy.optimize.cython_optimize cimport zeros_tuple
>>> from scipy.optimize.cython_optimize.examples.zeros_tuple_examples cimport f_solarcell, fprime

>>> ARGS = (5.25, 6.0, 1e-09, 0.004, 10.0, 0.27456)
>>> TOL, MAXITER = 1.48e-8, 50

>>> cdef scipy_newton_full_output solarcell_newton_full_output(tuple args, double x0, double tol, int maxiter):
...     cdef scipy_newton_full_output full_output
...     zeros_tuple.newton(f_solarcell, x0, fprime, args, tol, maxiter,
...                        <zeros_tuple.scipy_newton_parameters *> &full_output)
...     return full_output  # root = 5.255320079106907 not shown

>>> print(solarcell_newton_full_output(ARGS, 6.0, TOL, MAXITER))
{'error_num': 0,  # <- **more meaningful in my opinion**
 'funcalls': 6,
 'iterations': 3}

Error message:

There is no error message. The issue is IMO it is more explicit to set the error number to zero instead of forcing the user to infer that functions in optimize/Zeros converged because they did not error.

Scipy/Numpy/Python version information:

1.1.0 1.15.0 sys.version_info(major=3, minor=6, micro=6, releaselevel='final', serial=0)

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
mikofskicommented, Mar 28, 2019

Yes, I can confirm #9465 closes this issue because:

  • it creates a new constant CONVERGED = 0 in zeros.h
  • sets the error number to CONVERGED just prior to successful return in all of the bounded zero search functions, EG: in bisect.c before a successful return, error number is set to CONVERGED

Thanks!

1reaction
mikofskicommented, Aug 30, 2018

I think there may be another good reason to initialize params->error_num because if not initialized, the reference might, by pure coincidence, be the same as either SIGNERR or CONVERR, and so you would get a false negative. Since in the current codebase the initial value is never set, there’s no way to know what value would be at that reference. By initializing the reference to zero, we know it could only be intentionally set to an error.

Read more comments on GitHub >

github_iconTop Results From Across the Web

No results found

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found