From b1003321fc7bacce318b01159eee6f7319c3a1c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=97=A4=E6=9C=A8=E6=BD=A4=E4=B8=80?= Date: Thu, 24 Sep 2026 06:49:04 +0900 Subject: [PATCH 1/2] Use stable logsumexp in grid plots --- cosmosis/plotting/grid_plots.py | 11 ++++++++--- cosmosis/test/test_grid_plots.py | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 cosmosis/test/test_grid_plots.py diff --git a/cosmosis/plotting/grid_plots.py b/cosmosis/plotting/grid_plots.py index 3877b1e6..c50994fa 100644 --- a/cosmosis/plotting/grid_plots.py +++ b/cosmosis/plotting/grid_plots.py @@ -23,6 +23,7 @@ from .plotter import Plotter import itertools import scipy.optimize +from scipy.special import logsumexp try: from cosmosis import output as output_module except ImportError: @@ -30,6 +31,11 @@ class GridPlotter(Plotter): + @staticmethod + def _logsumexp(values): + """Stable log(sum(exp(values))) for grid marginalization.""" + return logsumexp(values) + #def __init__(self, *args, **kwargs): # super(GridPlotter, self).__init__(*args, **kwargs) # convert the loaded chain data sets into grids @@ -69,7 +75,7 @@ def _plot_1d(self, name1): #marginalize for k,v1 in enumerate(vals1): w = np.where(cols1==v1) - like_sum[k] = np.log(np.exp(like[w]).sum()) + like_sum[k] = self._logsumexp(like[w]) like = like_sum.flatten() #linearly interpolate @@ -149,7 +155,7 @@ def _plot_2d(self, name1, name2, log_like=True): for k,(v1, v2) in enumerate(itertools.product(vals1, vals2)): w = np.where((cols1==v1)&(cols2==v2)) i,j = np.unravel_index(k, like_sum.shape) - like_sum[i,j] = np.log(np.exp(like[w]).sum()) + like_sum[i,j] = self._logsumexp(like[w]) like = like_sum.flatten() #Normalize the log-likelihood to peak=0 @@ -210,4 +216,3 @@ def toggle_edge(edges, x1,y1,x2,y2): sm = pylab.cm.ScalarMappable(cmap=colormap, norm=norm) sm._A = [] #hack from StackOverflow to make this work pylab.colorbar(sm, label='Likelihood') - diff --git a/cosmosis/test/test_grid_plots.py b/cosmosis/test/test_grid_plots.py new file mode 100644 index 00000000..e70552a1 --- /dev/null +++ b/cosmosis/test/test_grid_plots.py @@ -0,0 +1,16 @@ +import numpy as np + +from cosmosis.plotting.grid_plots import GridPlotter + + +def test_grid_logsumexp_handles_extreme_log_likelihoods(): + values = np.array([1000.0, 999.0, -1000.0]) + result = GridPlotter._logsumexp(values) + expected = 1000.0 + np.log1p(np.exp(-1.0)) + np.testing.assert_allclose(result, expected) + assert np.isfinite(result) + + +def test_grid_logsumexp_empty_group_is_negative_infinity(): + result = GridPlotter._logsumexp(np.array([])) + assert result == -np.inf From c10ef96299fe067e846a221db410bcee9ab52cfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=97=A4=E6=9C=A8=E6=BD=A4=E4=B8=80?= Date: Thu, 24 Sep 2026 07:33:59 +0900 Subject: [PATCH 2/2] Handle empty grid marginalization groups --- cosmosis/plotting/grid_plots.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cosmosis/plotting/grid_plots.py b/cosmosis/plotting/grid_plots.py index c50994fa..3a2a39ef 100644 --- a/cosmosis/plotting/grid_plots.py +++ b/cosmosis/plotting/grid_plots.py @@ -34,6 +34,8 @@ class GridPlotter(Plotter): @staticmethod def _logsumexp(values): """Stable log(sum(exp(values))) for grid marginalization.""" + if np.size(values) == 0: + return -np.inf return logsumexp(values) #def __init__(self, *args, **kwargs):