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

MAINT: Translate binom to C++ #19471

Merged
merged 6 commits into from Nov 11, 2023
Merged

MAINT: Translate binom to C++ #19471

merged 6 commits into from Nov 11, 2023

Conversation

steppi
Copy link
Contributor

@steppi steppi commented Nov 3, 2023

Reference issue

This PR closes no issues, but continues the work discussed in the RFC issue #19404.

What does this implement/fix?

This PR translates the real valued binomial coefficient function binom from Cython into C++. Again, the translation is as literal as possible.

Additional information

Since binom depends on cephes I needed to work out how to include cephes functions in C++ code. This was not immediately possible because cephes has a header cephes_names.h which defines aliases of the form beta -> cephes_beta etc. So far so good, but because of how they are implemented, the aliases bleed into all code in the same translation unit, for instance, expanding expm1 when it appears in boost to cephes_expm1. Rather than trying to sort that out directly, I've created a new header cephes.hh for inclusion in C++ files, which puts cephes functions in the scipy::special::cephes namespace without a prefix in the name, and undefs all of the aliases

For now, I've kept the binom implementation within orthogonal_eval.pxd and it is still used internally there.

As is, this binom implementation is not header only because it depends on cephes. We'll need to discuss the possibility of making cephes or parts of cephes header only in the future.

This PR should unblock the work that is stalled on gh-19287.

cc @izaid, @tirthasheshpatel, @rlucas7, @ilayn

@steppi steppi added scipy.special C/C++ Items related to the internal C/C++ code base maintenance Items related to regular maintenance tasks labels Nov 3, 2023
@steppi
Copy link
Contributor Author

steppi commented Nov 3, 2023

The unrelated failure seems to be due to the recent NumPy integer dtype changes. #19466, #19462, numpy/numpy#24224.

@rlucas7
Copy link
Member

rlucas7 commented Nov 4, 2023

The unrelated failure seems to be due to the recent NumPy integer dtype changes. #19466, #19462, numpy/numpy#24224.

it seems so yeah, there's a discussion on #19466 that seems to (maybe?) address the issue for sobol.

I can take a closer look this weekend once I update #19287 to get merged lambert code incorporated. Thanks for getting this up so quickly @steppi

@ev-br
Copy link
Member

ev-br commented Nov 4, 2023

Let me devil advocate a bit. Since we pull stuff from boost already, can https://beta.boost.org/doc/libs/1_37_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/factorials/sf_binomial.html

replace our implementation?

@steppi
Copy link
Contributor Author

steppi commented Nov 4, 2023

Let me devil advocate a bit. Since we pull stuff from boost already, can https://beta.boost.org/doc/libs/1_37_0/libs/math/doc/sf_and_dist/html/math_toolkit/special/factorials/sf_binomial.html

replace our implementation?

I’d prefer to be able to use boost if we could. We’re avoiding boost for now until they make the changes necessary to get their stuff to run on Cuda.

#include "cephes.hh"


using std::numeric_limits;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should import things like this in header files. Best to keep it fully qualified.

If you really want to do using std::numeric_limits;, you can actually do that within either the functions or namespaces it is used in. But I'd stick with not doing it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good catch. Agreed on not wanting to have unexpected side effects when including a header. There are some imports in _lambertw.h that can be removed in another PR.

using namespace std::complex_literals;
using std::numeric_limits;

scipy/special/_binom.h Outdated Show resolved Hide resolved
}
if (k > 1E8*std::fabs(n)) {
// avoid loss of precision
num = cephes::Gamma(1 + n) / std::fabs(k)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why is it Gamma with a capital 'G'?

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 clue, but cephes gamma function has been capital G in SciPy from the start: 52c64a9.

#include "_lambertw.h"

inline double binom(double n, double k) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want this to be npy_double or just double?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it matters for double. It seems like the convention in other parts of the code base is to just have double. Check out specfun_wrappers for instance.

scipy/special/cephes.hh Outdated Show resolved Hide resolved
#undef kolmogp
#undef kolmogc
#undef kolmogci
#undef owens_t
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah... I've actually messed about with cephes in SciPy before. It has some things going on that are definitely not best practices. Our long term aim should be to not use it like this, and just adapt it to current best practices for C / C++.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I plan to make another mailing list post and RFC issue about what to do with cephes.

@izaid
Copy link
Contributor

izaid commented Nov 4, 2023

@steppi Just read through and left some comments! Generally looks quite good, well done. A few things I think we should change.

Yeah, we'll need to do something to integrate cephes a bit better. I don't think it's so hard, more annoying, but what we have now is certainly not ideal.

Copy link
Member

@rlucas7 rlucas7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This passes all tests for me in stats and special locally, and has a +1 from @izaid so merging to unblock my work on stirling2 Thanks @steppi + @izaid

@rlucas7 rlucas7 merged commit bf819ba into scipy:main Nov 11, 2023
21 of 23 checks passed
@steppi
Copy link
Contributor Author

steppi commented Nov 12, 2023

Thanks @rlucas7!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C/C++ Items related to the internal C/C++ code base maintenance Items related to regular maintenance tasks scipy.special
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants