Skip to content
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

BUG: make C-implemented root finders work with functools.lru_cache #10891

Merged
merged 3 commits into from
Oct 6, 2019

Conversation

jbweston
Copy link
Contributor

@jbweston jbweston commented Oct 1, 2019

Reference issue

Closes #10846.

What does this implement/fix?

C-implemented root finders in scipy.optimize raise SystemError when passed a function wrapped with functools.lru_cache. This is because when calling C-implemented root finders we create the tuple of arguments to pass to the underlying function once, and modify only the first entry on subsequent calls. This breaks when the argument tuple is stored internally by functools.lru_cache.

My fix is to instead construct a new argument tuple each time the underlying function is called.

As this change has the potential to slow down the root finders I ran the following benchmark:

from scipy.optimize.zeros import bisect

def f(x):
    return x

# The slowest root finder
%timeit bisect(f, -1, 1 + 1/3)

on master this gives:
4.78 µs ± 277 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
on this branch this gives:
5.18 µs ± 204 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

which represents an 8% slowdown. I think that this is pretty much an upper bound on the slowdown, as the function we're finding the root of is trivial, and this is using the most naive root-finder (i.e. it does the least amount of work per function call).

Additional information

This bug is present in older versions of Scipy, but I have applied the fix on top of master. I could not find any information on Scipy's policy regarding how far back bugfixes should be applied. Let me know if I should apply this fix to one of the maintenance/* branches instead.

Previously a single tuple was created and the first element
updated on each call to the underlying function. This broke
the immutability condition of tuples, and caused problems
e.g. when passing functions wrapped in functools.lru_cache.

Closes scipy#10846.
@jbweston
Copy link
Contributor Author

jbweston commented Oct 1, 2019

Doc building failures don't seem to have anything to do with this PR.

@ewmoore
Copy link
Member

ewmoore commented Oct 1, 2019

I think the bulk of the code you’ve added can probably be replaced with a call to PySequence_Concat.

@jbweston
Copy link
Contributor Author

jbweston commented Oct 1, 2019

@ewmoore the last commit uses PySequence_Concat, however the timings have deteriorated.

Running the above benchmark with this new commit added gives:
7.98 µs ± 106 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
which is a much larger slowdown.

@ewmoore
Copy link
Member

ewmoore commented Oct 1, 2019 via email

@jbweston jbweston force-pushed the fix/10846-lrucache-zeros branch 2 times, most recently from f0884f8 to 92b0e93 Compare October 1, 2019 17:04
@jbweston
Copy link
Contributor Author

jbweston commented Oct 1, 2019

I just removed the commit that used PySequence_Concat.

@jbweston jbweston changed the title MAINT: make C-implemented root finders work with functools.lru_cache BUG: make C-implemented root finders work with functools.lru_cache Oct 2, 2019
@pv pv merged commit 085330f into scipy:master Oct 6, 2019
@pv pv added this to the 1.4.0 milestone Oct 6, 2019
@jbweston
Copy link
Contributor Author

jbweston commented Oct 6, 2019

@pv I think this fix should also be backported to previous scipy versions, but I don't know scipy's policy on providing bugfixes for older versions.

@jbweston jbweston deleted the fix/10846-lrucache-zeros branch October 6, 2019 14:34
@pv pv added the backport-candidate This fix should be ported by a maintainer to previous SciPy versions. label Oct 6, 2019
@tylerjereddy tylerjereddy modified the milestones: 1.4.0, 1.3.2 Oct 31, 2019
@tylerjereddy tylerjereddy added defect A clear bug or issue that prevents SciPy from being installed or used as expected and removed backport-candidate This fix should be ported by a maintainer to previous SciPy versions. labels Nov 29, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
defect A clear bug or issue that prevents SciPy from being installed or used as expected scipy.optimize
Projects
None yet
Development

Successfully merging this pull request may close these issues.

root_scalar fails when passed a function wrapped with functools.lru_cache
5 participants