[WIP] entropic_partial_wasserstein_logscale: stable log-domain solver (rescue of #724)#811
Open
hinanohart wants to merge 1 commit into
Open
[WIP] entropic_partial_wasserstein_logscale: stable log-domain solver (rescue of #724)#811hinanohart wants to merge 1 commit into
hinanohart wants to merge 1 commit into
Conversation
… (rescue of PythonOT#724) Re-applies the function from PR PythonOT#724 by wzm2256 on top of current master (the original PR is stuck at CONFLICTING since 2025-09; this takes the additive parts and skips the obsolete merges through the March-2025 single-file layout). Subject is [WIP] because the original PR is also [WIP] and maintainer review is still required. Changes vs master: ot/partial/partial_solvers.py + entropic_partial_wasserstein_logscale (function body verbatim from PR PythonOT#724 modulo: (a) duplicate sphinx label removed to avoid build failure, (b) print warning -> warnings.warn(stacklevel=2) for convention). ot/partial/__init__.py + entropic_partial_wasserstein_logscale export test/test_partial.py + test_entropic_partial_wasserstein_logscale_matches_old_at_large_reg (machine-precision agreement at reg in {10.0, 1.0}: atol=1e-10) + test_entropic_partial_wasserstein_logscale_no_nan_at_small_reg (parametrised over reg in {0.1, 0.05, 0.01, 5e-3, 1e-3, 5e-4}) + test_entropic_partial_wasserstein_logscale_approaches_exact_at_small_reg (plan-cost gap vs exact partial OT at reg=1e-3) + test_entropic_partial_wasserstein_logscale_log_dict + test_entropic_partial_wasserstein_logscale_input_validation examples/unbalanced-partial/plot_entropic_partial_wasserstein_logscale.py + Sphinx-Gallery example reproducing issue PythonOT#723 + the fix (MPLBACKEND=Agg-safe; narrative softened to acknowledge BLAS/platform-dependent underflow boundary). docs/source/user_guide.rst + one-paragraph mention next to entropic_partial_wasserstein. RELEASES.md + entry under 0.9.7.dev0 (phrased as "mitigated via new log-domain variant", not "fixed", since the standard solver itself is unchanged). Verified locally on master at 41a4d57: pytest test/ -> 1939 passed, 97 skipped, 6 xfailed (no regressions). pytest test/test_partial.py -> 19 passed (8 originals + 11 new parametrised cases for the logscale function). Example script runs end-to-end with MPLBACKEND=Agg. The new function agrees with the standard solver at reg >= 1.0 to ~1e-18 absolute (atol=1e-10 in tests is conservative) and stays finite at reg down to 5e-4 on a 50x50 cost-scale-~50 problem (the exact failure mode of issue PythonOT#723); std solver returns NaN at reg ~ 0.05-0.01 on the same problem. References Issue PythonOT#723. Maintainer review needed before merge — author attribution to wzm2256 retained via Co-authored-by trailer. Co-authored-by: wzm2256 <wzm2256@qq.com>
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
This is a rescue follow-up to PR #724 (and issue #723), both opened by @wzm2256 in March 2025. The original PR adds a numerically-stable
entropic_partial_wasserstein_logscaleto fix the NaN regime that #723 documents, but has been stuckCONFLICTINGsince 2025-09 — the author wrote in the PR body that they could not (a) build the docs locally (sphinx_rtd_thememissing) or (b) write pytest cases, and asked for help.I hit the same NaN regime as a downstream user of
entropic_partial_wasserstein, so this PR re-applies @wzm2256's function on top of currentmasterand supplies the missing pieces.Why a new PR rather than pushing to #724's branch
When PR #724 was opened,
ot/partial.pywas a single file. The maintainers later split it into theot/partial/package, so the diff between #724's branch and currentmasteris now +2k / −13k lines of mostly unrelated movement. Re-applying just the new function on the new layout is cleaner than fighting that rebase.If maintainers prefer to keep #724 as the canonical PR, I'm happy to close this and instead push these changes to that branch (write access permitting).
What's added (additive only; nothing removed)
ot/partial/partial_solvers.py—entropic_partial_wasserstein_logscalefunction, identical algorithm to PR [WIP] Add a stablized function entropic_partial_wasserstein_logscale #724 re-applied on the current layout.ot/partial/__init__.py— export +__all__entry.test/test_partial.py— 5 new test functions / 11 parametrised cases:[0.1, 0.05, 0.01, 5e-3, 1e-3, 5e-4]— reproduces issue entropic_partial_wasserstein not stable #723's failure mode and verifies the logscale solver stays finite.atol=1e-10, rtol=1e-10) across[1.0, 10.0].approaches_exact_at_small_reg— checks the plan-cost vs. exact partial-OT gap atreg=1e-3(not just NaN-freeness; verifies mathematical correctness).examples/unbalanced-partial/plot_entropic_partial_wasserstein_logscale.py— Sphinx-Gallery example reproducing entropic_partial_wasserstein not stable #723's failure and showing the fix. Adapted from @wzm2256'scompare_logscale_POT.py.docs/source/user_guide.rst— one-paragraph mention next toentropic_partial_wasserstein.RELEASES.md— one-line entry under0.9.7.dev0, phrased as mitigation (the standard solver itself is unchanged; callers opt into the log-domain variant).Local verification
pytest test/test_partial.py -q→ 19 passed (8 originals + 11 new parametrised cases).pytest test/(full suite) → 1939 passed, 97 skipped, 6 xfailed — no regression outsidepartial.MPLBACKEND=Agg. Standard solver returns NaN atreg ∈ {0.05, 0.01}on the 50×50 cost-scale-50 problem; logscale solver stays finite over the full sweep.git diff master -- ot/partial/partial_solvers.pyshows exactly one hunk: the new function block. Nothing else drifts.Co-authorship
Credit for the actual numerical work belongs to @wzm2256. If you'd prefer me to mark the commit
Co-authored-by: wzm2256 <wzm2256@qq.com>and amend, I'm happy to — it just wasn't clear from the PR conventions here whether you prefer trailers or PR description acknowledgements.cc @rflamary @cedricvincentcuaz — you both did
master-merges on #724 earlier this year so it looked like a "we want this in" signal. Happy to do whatever's least friction here: this PR can be the canonical one, or I can close it and push to #724's branch.The
[WIP]prefix matches the original PR's convention and signals this is open for re-titling to[MRG]once you've had a look.