BUG: `special.betaincinv` / `stats.beta.ppf` wrong when `min(a, b) == 1000` exactly (Boost `ibeta_inv` falls between two strict comparisons)
メンテナーはふだん 1 日以内に返信
関連するプルリクエストがすでにマージされています。
- #1512 @NAThompson による — マージ済み
評価
調査の方向性
初期推定値が選択される boost/math/special_functions/detail/ibeta_inverse.hpp の ibeta_inv_imp 付近、735~745 行を読んでください。まず ibeta_inv(1000, 1e9, 0.025) の回帰テストを実行するか追加してください。逆関数が期待値を返し、その点で正則化ベータ関数を評価すると 0.025 が得られ、鏡像の場合も含まれることをもって完了とします。
索引モデルが issue の本文から書いたものです。
説明
Summary
betaincinv(a, b, y) returns a wrong value when the smaller shape parameter is exactly 1000 and the other one is large (from about 2e7). a = 999.999 and a = 1000.001 are both fine. The error is not small: for betaincinv(1000, 1e9, 0.025) the result is 2x too large and betainc at it is 1.0, not 0.025. stats.beta.ppf goes through the same code. It reproduces on 1.17.1 and 1.18.1.
Reproducer
from scipy.special import betainc, betaincinv
for a in (999.999, 1000.0, 1000.001):
x = betaincinv(a, 1e9, 0.025)
print(f"a={a}: x={x:.6e} betainc(a, b, x)={betainc(a, 1e9, x):.6f}")
a=999.999: x=9.389711e-07 betainc(a, b, x)=0.025000
a=1000.0: x=1.903149e-06 betainc(a, b, x)=1.000000
a=1000.001: x=9.389731e-07 betainc(a, b, x)=0.025000
The correct value is 9.389730e-07 (mpmath, 50 digits). stats.beta.ppf(0.025, 1000, 1e9) gives the same wrong 1.903149e-06. The mirrored case is wrong too: betainc(1e9, 1000, betaincinv(1e9, 1000, 0.975)) is 2.4e-115, not 0.975.
Where it fails
Scanning a = 2…20000 (integers) and b from 1e5 to 1e15, at y = 0.025 and 0.975, the only failing a is 1000. For a = 1000 the failures start at about b = 2e7. Every y we tried fails, not only the tails (betainc at the returned value: y = 1e-6 → 1, 0.1 → 1, 0.9 → 0.864).
Cause
ibeta_inv_imp in boost/math/special_functions/detail/ibeta_inverse.hpp (develop, around lines 735–745). When choosing the initial guess for large a + b:
if((y > 1e-5) && BOOST_MATH_GPU_SAFE_MIN(a, b) < 1000)
{
x = temme_method_3_ibeta_inverse(a, b, p, q, pol);
y = 1 - x;
}
else if ((y > 1e-5) && BOOST_MATH_GPU_SAFE_MIN(a, b) > 1000)
{
// All options have failed, use the saddle point as a starting location:
x = BOOST_MATH_GPU_SAFE_MAX(a, b) / (a + b);
y = BOOST_MATH_GPU_SAFE_MIN(a, b) / (a + b);
}
Both comparisons are strict, so min(a, b) == 1000 takes neither branch: no initial guess is set for it, and the iteration converges to the wrong point. Making one of them inclusive (>= 1000 in the second) would cover the gap.
Suggested fix
- Boost: make the saddle-point branch
min(a, b) >= 1000(or the Temme branch<= 1000), and addibeta_inv(1000, 1e9, 0.025)as a regression case. - SciPy: pick up the fixed Boost, and add the reproducer above to
scipy/specialtests (betainc(a, b, betaincinv(a, b, y)) ≈ yata = 1000,b = 1e9).
Workaround
Solve betainc(a, b, x) = y directly, which is accurate at these arguments:
from scipy.optimize import brentq
from scipy.special import betainc
x = brentq(lambda x: betainc(1000, 1e9, x) - 0.025, 0, 1, xtol=1e-300, rtol=1e-12) # 9.389730e-07
Versions
SciPy 1.17.1 and 1.18.1, NumPy 2.5.1, Python 3.13.5, macOS 26.6 arm64. Not found in existing SciPy or Boost.Math issues; the nearest, boostorg/math#1487, is a different ibeta_inv failure (a = b = 5, p = 0.5).
- 主要言語
- C++
- スター
- 377
- フォーク
- 271
- 平均マージ
- 11時間 23分
- マージ済み PR(30日)
- 78
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
boostorg/math のほかの issue
-
難易度 5/5 1週間以上 初心者へのやさしさ 12/100
boostorg/math#1577 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
Feature Wishlistオープンenhancement
難易度 5/5 1週間以上 初心者へのやさしさ 20/100
boostorg/math#303 · コメント 18 件 ·
メンテナーはふだん 1 日以内に返信
似ている issue
-
Web3 RPC: one-element batch request returns an object instead of an array (breaks ethers.js v6)オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 75/100
FISCO-BCOS/FISCO-BCOS#5706 ·
メンテナーはふだん 3 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 85/100
521xueweihan/HelloGitHub#4011 ·
-
docs(simulation): Quickstart publishes UDP 14550, which the SITL images' own docs say not to doオープンstatus:needs-triage
難易度 1/5 1〜3時間 初心者へのやさしさ 78/100
PX4/PX4-Autopilot#29292 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
I/O internal correctness medium priority rt_lib
難易度 2/5 1〜3時間 初心者へのやさしさ 79/100
メンテナーはふだん 1 日以内に返信
-
GUI
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
sonic-pi-net/sonic-pi#3594 ·