-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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
ENH: implemented Owen's T function #7120
Conversation
scipy/special/basic.py
Outdated
@@ -32,7 +32,7 @@ | |||
'keip_zeros', 'kelvin_zeros', 'ker_zeros', 'kerp_zeros', 'kv', | |||
'kvp', 'lmbda', 'lpmn', 'lpn', 'lqmn', 'lqn', 'mathieu_a', | |||
'mathieu_b', 'mathieu_even_coef', 'mathieu_odd_coef', 'ndtri', | |||
'obl_cv_seq', 'pbdn_seq', 'pbdv_seq', 'pbvv_seq', 'perm', | |||
'obl_cv_seq', 'owens_t','pbdn_seq', 'pbdv_seq', 'pbvv_seq', 'perm', |
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.
pep8, space after comma
scipy/special/basic.py
Outdated
|
||
Parameters | ||
---------- | ||
h: int or float |
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.
int or float --> scalar
(same 2 lines lower)
scipy/special/basic.py
Outdated
---------- | ||
.. [1] Mike Patefield and David Tandy. "Fast and accurate calculation | ||
of Owen's T-function", 2000. | ||
https://www.jstatsoft.org/article/view/v005i05/t.pdf |
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 link please, but a complete citation:
M. Patefield and D. Tandy, "Fast and accurate calculation of Owen’st function",
Statistical Software vol. 5, pp. 1-25, 2000.
scipy/special/basic.py
Outdated
elif a > 1: | ||
ncdf_h = ndtr(h) | ||
ncdf_ah = ndtr(a * h) | ||
return 0.5 * (ncdf_h + ncdf_ah) - ncdf_h * ncdf_ah -\ |
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.
can you get rid of the \
(replace by brackets)
scipy/special/basic.py
Outdated
owens_t(a * h, 1 / a) | ||
|
||
if a == 0: | ||
return 0 |
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.
blank line here
scipy/special/basic.py
Outdated
if a == 0: | ||
return 0 | ||
if h == 0: | ||
return 1 * np.arctan(a) / (2 * np.pi) |
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.
blank line here
scipy/special/tests/test_basic.py
Outdated
a = 1.5 | ||
assert_almost_equal(special.owens_t(h, a), special.owens_t(h, np.inf)) | ||
|
||
delta = 0.5 * (cephes.ndtr(h) + cephes.ndtr(a * h)) -\ |
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.
same here, remove \
scipy/special/basic.py
Outdated
result += ((-1) ** (i - 1)) * z_curr | ||
z_prev = z_curr | ||
z_curr = ((2 * i - 1) * z_prev - pi_sq * | ||
np.power(a, 2 * i - 1) * np.exp(ah_sq)) / (h * h) |
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.
blank line here
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.
and style nitpick: lines like these should line up with the opening bracket above, not use 4-space indents
scipy/special/basic.py
Outdated
return 0 | ||
if h == 0: | ||
return 1 * np.arctan(a) / (2 * np.pi) | ||
if a >= 0.99: |
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.
there's no test or comment on the PR for the accuracy when approaching 0.99 from either side. did you verify this?
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.
and same question around 1.0
(other if clause above)
scipy/special/basic.py
Outdated
.. [1] Mike Patefield and David Tandy. "Fast and accurate calculation | ||
of Owen's T-function", 2000. | ||
https://www.jstatsoft.org/article/view/v005i05/t.pdf | ||
|
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.
maybe add an example which plots the function?
scipy/special/basic.py
Outdated
|
||
""" | ||
if not (np.isscalar(h) and np.isscalar(a)): | ||
raise ValueError("arguments must be scalars.") |
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.
blank lines after an if-block ends (here and below)
Thanks @evgenyzhurko. Would be good to mention that you want to add this function on the scipy-dev mailing list. |
Would make sense to implement this in Cython, to get a proper ufunc
without restriction to scalar arguments.
|
@rgommers I made a mistake wheni use @pv I'll try to do it, but i have never use Cython before. |
@evgenyzhurko it's likely easiest to start from IPython's magic |
You should import the tests for this function from Boost as well. They have a table of values in https://github.com/boostorg/math/blob/develop/test/owens_t.ipp that can be added to the similar tests as well as a bunch of other tests that can be ported over. No reason not to make use of work already done to construct some good tests. |
You reference M. Patefield and D. Tandy, but it seems that the algorithm used in the paper is much more complex. Is that true, and if so, how did you achieve the simplifications? |
It's the method T2 from Patefield&Tandy. Probably covers only part of
the parameter region, and if so more work is necessary here.
|
Just to second @pv, to make this production-ready it should be rewritten in Cython (or C, or C++, or Fortran) and hooked up to the ufuncs machinery. |
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.
Looking good--the build is failing because you need to add a line to test_cython_special.py
.
@@ -6369,3 +6369,8 @@ def add_newdoc(place, name, doc): | |||
""" | |||
Internal function, do not use. | |||
""") | |||
|
|||
add_newdoc("scipy.special", "owens_t", | |||
""" |
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.
Instead of putting the documentation in owens_t.c
put it here.
scipy/special/cephes/owens_t.c
Outdated
0.60419009528470238773E-02, 0.38862217010742057883E-02, | ||
0.16793031084546090448E-02}; | ||
|
||
static double PI = 3.1415926535897932384626433832795; |
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.
Use NPY_PI
.
scipy/special/cephes/owens_t.c
Outdated
return SELECT_METHOD[iaint* 15 + ihint]; | ||
} | ||
|
||
int get_ord(int index) { |
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.
I don't think this helper function is necessary.
scipy/special/cephes/owens_t.c
Outdated
} | ||
|
||
double owens_t(double h, double a) { | ||
if (cephes_isnan(h) || cephes_isnan(a)) |
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.
Braces.
scipy/special/cephes/owens_t.c
Outdated
} | ||
|
||
double owensT3(double h, double a, double m) { | ||
double a_sq = a * a; |
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.
Can you name them something like a2
or aa
?
scipy/special/cephes/owens_t.c
Outdated
double yi = 1; | ||
double result = 0; | ||
|
||
while (1) { |
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.
Why not for (i = 1; i < maxi; i += 2)
?
scipy/special/cephes/owens_t.c
Outdated
int i = 0; | ||
|
||
for (i = 0; i < 14; i++) { | ||
if (h <= HRANGE[i]) { |
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.
Spacing isn't consistent with the rest of the code here.
scipy/special/tests/test_basic.py
Outdated
@@ -3416,5 +3416,412 @@ def xfunc(delta, r): | |||
assert_func_equal(special.pseudo_huber, w, z, rtol=1e-13, atol=1e-13) | |||
|
|||
|
|||
owenst_dt = [[(1.9508080482482910156250000000000000000000000000000000000000000000000000000000000000000000000000000000e+00), (9.7540378570556640625000000000000000000000000000000000000000000000000000000000000000000000000000000000e-02), (2.2942365980155351117754771526378292708740231264960539316842063696200884829628237039895484898529192823e-03)], |
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.
If this is the test data from boost, it should be put in a file under data/boost/owenst_ipp
and added to the TESTS list in test_data.py:test_boost
. (Also if it's some other test data, long data set like this should be put in a data file.)
After adding the text data, the npz data file needs to be regenerated using utils/makenpz.py
scipy/special/cephes/owens_t.c
Outdated
|
||
for (i = 0; i < 7; i++) { | ||
if (h <= HRANGE[i]) { | ||
ihint = i; |
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.
iahint?
I add |
Now there are different failures--looks like the docstring has some issues and at least one of the builds is getting a segfault. You can go look at the build logs for details. |
How i can correct issue with docstring? |
Something about locale / non-ascii symbols? |
There is no message about locale or ascii. I think it's a result of others error or segmentation foult, because in previous commit all is good with docstring. |
It wasn't really checked in the previous commit because most of the documentation was in the C source; the refguide checker only looks at the Python docstrings. |
Unless the Boost function is actually correctly rounded on all that test data, which would be impressive. |
Relative error for all test cases = from 1e-17 to 7e-18 |
When i wrote aboute absolute error, i made a mistake, 1.7194768829262296883086946763796731829643249511719e-19 is maximal absolute error, minimal absolute error is about 7e-106 for data ~1e-89 |
Relative tolerance for this data is from 1e-17 to 7e-19 |
Is Boost using extended precision internally for the double precision routine? That would explain this. (Would just check myself but am away from computer.) |
I tested If I use T5 algorithm for 2 problem test case, tests will pass with rtol = 5e-14. |
I found a bug in my code. Current |
Very nice! |
@person142 Do you expect more accuracy in computing for this pull request or some other changes? |
Probably the most important thing now is using |
Thanks, i'll try to generate test case for all code branches. |
Boost test cases covers |
@person142 gcov shows 92.5% coverage for lines and 93.3% for functions. As I said, only OwensT4 function not coveraged yet, because |
Josh, @person142, any chance you can take a look? |
Yes, sorry @evgenyzhurko for sitting on this for so long... will try to take a final look; probably won't happen until next week though. |
@evgenyzhurko Can you rebase on |
I rebased this PR on master, fixed all build problem and merge conflicts. Is anyone can review this PR? |
@evgenyzhurko I rebased again (recent changes in Probably most importantly: from reading the code it looks like the Boost implementation was followed closely, so I added the Boost license information to the top of the file. Am I correct? |
@person142 You are right, in many case i follow to boost implementation. I was trying to find values a and h that can be calculated using only T4(that not covered yet) function but it's no use. I calculated that for 0.06 < a < 0.25 and 0.6 < h < 3.5 should be used T4 function. I iterated through this interval with step=0.00001 and T4 wasn't used. |
It appears you were using Boost's arbitrary precision dispatch function instead of the double precision version. I switched to using the double precision version (which covers T4), fixed a bug this revealed in T1, and then removed the no-longer-needed arbitrary precision helper functions. |
@person142 Thanks for your help and my mistakes explanation. Is something else need from me in this PR? |
I made a few more fixes, and I think this is good to go now. We will see what the CIs say, and we should probably ping @pv to do a sanity check since I feel a little too involved in the code editing process to be an objective third party. Pauli, I'm seeing 100% test coverage on |
Ah shoot, looks like |
Ok, cleaned up the history. Now there's one clean commit. |
Ok, got this in at long last. Thanks for your patience @evgenyzhurko. |
#5160