Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-emcee for openSUSE:Factory 
checked in at 2024-04-21 20:27:20
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-emcee (Old)
 and      /work/SRC/openSUSE:Factory/.python-emcee.new.26366 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-emcee"

Sun Apr 21 20:27:20 2024 rev:8 rq:1169367 version:3.1.6

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-emcee/python-emcee.changes        
2023-01-28 19:01:15.896034985 +0100
+++ /work/SRC/openSUSE:Factory/.python-emcee.new.26366/python-emcee.changes     
2024-04-21 20:28:49.081305303 +0200
@@ -1,0 +2,16 @@
+Sat Apr 20 13:53:33 UTC 2024 - Dirk Müller <[email protected]>
+
+- update to 3.1.6:
+  * Compat fix for older numpy versions
+- update to 3.1.5:
+  * Update blobs docs
+  * Fix integrated_time docstring
+  * Fixed DEMove Implementation
+  * Move proposals should match the dtype of original input
+  * Update the Read the Docs configuration
+  * Fix moves documentation typos
+  * Update EnsembleSampler docstring in ensemble.py
+  * Fix typo in assertion message
+  * MAINT: updates for numpy2 closes #509
+
+-------------------------------------------------------------------

Old:
----
  emcee-3.1.4.tar.gz

New:
----
  emcee-3.1.6.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-emcee.spec ++++++
--- /var/tmp/diff_new_pack.10FJDF/_old  2024-04-21 20:28:51.389390028 +0200
+++ /var/tmp/diff_new_pack.10FJDF/_new  2024-04-21 20:28:51.389390028 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-emcee
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -20,7 +20,7 @@
 # NEP 29: python36-numpy and -scipy are no longer available in TW
 %define         skip_python36 1
 Name:           python-emcee
-Version:        3.1.4
+Version:        3.1.6
 Release:        0
 Summary:        Python affine-invariant ensemble MCMC sampling
 License:        MIT

++++++ emcee-3.1.4.tar.gz -> emcee-3.1.6.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/.github/workflows/tests.yml 
new/emcee-3.1.6/.github/workflows/tests.yml
--- old/emcee-3.1.4/.github/workflows/tests.yml 2023-01-27 13:19:09.000000000 
+0100
+++ new/emcee-3.1.6/.github/workflows/tests.yml 2024-04-19 11:49:57.000000000 
+0200
@@ -16,7 +16,7 @@
     runs-on: ${{ matrix.os }}
     strategy:
       matrix:
-        python-version: ["3.7", "3.8", "3.9", "3.10"]
+        python-version: ["3.9", "3.10", "3.11", "3.12"]
         os: ["ubuntu-latest"]
         include:
           - python-version: "3.9"
@@ -26,11 +26,11 @@
 
     steps:
       - name: Checkout
-        uses: actions/checkout@v3
+        uses: actions/checkout@v4
         with:
           fetch-depth: 0
       - name: Setup Python
-        uses: actions/setup-python@v4
+        uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python-version }}
       - name: Install dependencies
@@ -49,12 +49,41 @@
           COVERALLS_PARALLEL: true
           COVERALLS_FLAG_NAME: ${{ matrix.python-version }}-${{ matrix.os }}
 
+  numpy_edge:
+    runs-on: ${{ matrix.os }}
+    strategy:
+      matrix:
+        python-version: ["3.12"]
+        numpy-version: ["numpy>=2.0.0rc1"]
+        os: ["ubuntu-latest"]
+        include:
+          - python-version: "3.9"
+            numpy-version: "numpy<1.25"
+            os: "ubuntu-latest"
+
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+      - name: Setup Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: ${{ matrix.python-version }}
+      - name: Install dependencies
+        run: |
+          python -m pip install -U pip
+          python -m pip install pip install pytest "${{ matrix.numpy-version 
}}"
+          python -m pip install -e.
+      - name: Run tests
+        run: pytest
+
   coverage:
     needs: tests
     runs-on: ubuntu-latest
     steps:
       - name: Setup Python
-        uses: actions/setup-python@v4
+        uses: actions/setup-python@v5
         with:
           python-version: "3.9"
       - name: Finish coverage collection
@@ -68,11 +97,11 @@
   lint:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
         with:
           fetch-depth: 0
       - name: Setup Python
-        uses: actions/setup-python@v4
+        uses: actions/setup-python@v5
         with:
           python-version: "3.9"
       - name: Install dependencies
@@ -85,10 +114,10 @@
   build:
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v3
+      - uses: actions/checkout@v4
         with:
           fetch-depth: 0
-      - uses: actions/setup-python@v4
+      - uses: actions/setup-python@v5
         name: Install Python
         with:
           python-version: "3.9"
@@ -97,7 +126,7 @@
           python -m pip install -U pip
           python -m pip install -U build
           python -m build .
-      - uses: actions/upload-artifact@v3
+      - uses: actions/upload-artifact@v4
         with:
           path: dist/*
 
@@ -106,12 +135,12 @@
     runs-on: ubuntu-latest
     if: startsWith(github.ref, 'refs/tags/')
     steps:
-      - uses: actions/download-artifact@v3
+      - uses: actions/download-artifact@v4
         with:
           name: artifact
           path: dist
 
-      - uses: pypa/[email protected]
+      - uses: pypa/[email protected]
         with:
           user: __token__
           password: ${{ secrets.pypi_password }}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/.pre-commit-config.yaml 
new/emcee-3.1.6/.pre-commit-config.yaml
--- old/emcee-3.1.4/.pre-commit-config.yaml     2023-01-27 13:19:09.000000000 
+0100
+++ new/emcee-3.1.6/.pre-commit-config.yaml     2024-04-19 11:49:57.000000000 
+0200
@@ -1,13 +1,13 @@
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.4.0
+    rev: v4.6.0
     hooks:
       - id: trailing-whitespace
       - id: end-of-file-fixer
       - id: debug-statements
 
   - repo: https://github.com/PyCQA/isort
-    rev: "5.11.4"
+    rev: "5.13.2"
     hooks:
       - id: isort
         args: []
@@ -15,6 +15,6 @@
         exclude: docs/tutorials
 
   - repo: https://github.com/psf/black
-    rev: "22.12.0"
+    rev: "24.4.0"
     hooks:
       - id: black-jupyter
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/.readthedocs.yaml 
new/emcee-3.1.6/.readthedocs.yaml
--- old/emcee-3.1.4/.readthedocs.yaml   1970-01-01 01:00:00.000000000 +0100
+++ new/emcee-3.1.6/.readthedocs.yaml   2024-04-19 11:49:57.000000000 +0200
@@ -0,0 +1,19 @@
+version: 2
+
+build:
+  os: ubuntu-20.04
+  apt_packages:
+    - fonts-liberation
+  tools:
+    python: "3.10"
+
+python:
+  install:
+    - requirements: docs/requirements.txt
+    - method: pip
+      path: .
+
+sphinx:
+  configuration: docs/conf.py
+  fail_on_warning: true
+  builder: dirhtml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/PKG-INFO new/emcee-3.1.6/PKG-INFO
--- old/emcee-3.1.4/PKG-INFO    2023-01-27 13:19:19.915073600 +0100
+++ new/emcee-3.1.6/PKG-INFO    2024-04-19 11:50:06.431932700 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: emcee
-Version: 3.1.4
+Version: 3.1.6
 Summary: The Python ensemble sampling toolkit for MCMC
 Home-page: https://emcee.readthedocs.io
 Author: Daniel Foreman-Mackey
@@ -16,10 +16,16 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Description-Content-Type: text/x-rst
-Provides-Extra: extras
-Provides-Extra: tests
 License-File: LICENSE
 License-File: AUTHORS.rst
+Requires-Dist: numpy
+Provides-Extra: extras
+Requires-Dist: h5py; extra == "extras"
+Requires-Dist: scipy; extra == "extras"
+Provides-Extra: tests
+Requires-Dist: pytest; extra == "tests"
+Requires-Dist: pytest-cov; extra == "tests"
+Requires-Dist: coverage[toml]; extra == "tests"
 
 emcee
 =====
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/docs/tutorials/monitor.ipynb 
new/emcee-3.1.6/docs/tutorials/monitor.ipynb
--- old/emcee-3.1.4/docs/tutorials/monitor.ipynb        2023-01-27 
13:19:09.000000000 +0100
+++ new/emcee-3.1.6/docs/tutorials/monitor.ipynb        2024-04-19 
11:49:57.000000000 +0200
@@ -54,6 +54,7 @@
     "\n",
     "np.random.seed(42)\n",
     "\n",
+    "\n",
     "# The definition of the log probability function\n",
     "# We'll also use the \"blobs\" feature to track the \"log prior\" for 
each step\n",
     "def log_prob(theta):\n",
@@ -338,6 +339,7 @@
    "source": [
     "run2_backend = emcee.backends.HDFBackend(filename, 
name=\"mcmc_second_prior\")\n",
     "\n",
+    "\n",
     "# this time, with a subtly different prior\n",
     "def log_prob2(theta):\n",
     "    log_prior = -0.5 * np.sum((theta - 2.0) ** 2 / 100.0)\n",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/docs/tutorials/moves.ipynb 
new/emcee-3.1.6/docs/tutorials/moves.ipynb
--- old/emcee-3.1.4/docs/tutorials/moves.ipynb  2023-01-27 13:19:09.000000000 
+0100
+++ new/emcee-3.1.6/docs/tutorials/moves.ipynb  2024-04-19 11:49:57.000000000 
+0200
@@ -160,7 +160,7 @@
    "source": [
     "For \"lightly\" multimodal problems like these, some combination of the 
{class}`moves.DEMove` and {class}`moves.DESnookerMove` can often perform better 
than the default.\n",
     "In this case, let's use a weighted mixture of the two moves.\n",
-    "In deatil, this means that, at each step, we'll randomly select either a 
:class:`moves.DEMove` (with 80% probability) or a {class}`moves.DESnookerMove` 
(with 20% probability)."
+    "In detail, this means that, at each step, we'll randomly select either a 
{class}`moves.DEMove` (with 80% probability) or a {class}`moves.DESnookerMove` 
(with 20% probability)."
    ]
   },
   {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/docs/user/blobs.rst 
new/emcee-3.1.6/docs/user/blobs.rst
--- old/emcee-3.1.4/docs/user/blobs.rst 2023-01-27 13:19:09.000000000 +0100
+++ new/emcee-3.1.6/docs/user/blobs.rst 2024-04-19 11:49:57.000000000 +0200
@@ -12,12 +12,22 @@
 the sampler will do type inference to save the simplest possible
 representation of the blobs.
 
+Anything that your ``log_prob`` function returns in addition to the log
+probability is assumed to be a blob and is tracked as part of blobs.
+Put another way, if ``log_prob`` returns more than one thing, all the things
+after the first (which is assumed to be the log probability) are assumed to be
+blobs.
+If ``log_prob`` returns ``-np.inf`` for the log probability, the blobs are not
+inspected or tracked so can be anything (but the correct number of arguments
+must still be returned).
+
 Using blobs to track the value of the prior
 -------------------------------------------
 
 A common pattern is to save the value of the log prior at every step in the
 chain.
-To do this, you could do something like:
+To do this, your ``log_prob`` function should return your blobs (in this case 
log prior) as well as the log probability when called.
+This can be implemented something like:
 
 .. code-block:: python
 
@@ -33,10 +43,19 @@
     def log_prob(params):
         lp = log_prior(params)
         if not np.isfinite(lp):
-            return -np.inf, -np.inf
+            # log prior is not finite, return -np.inf for log probability
+            # and None for log prior as it won't be used anyway (but we
+            # must use the correct number of return values)
+            return -np.inf, None
         ll = log_like(params)
         if not np.isfinite(ll):
-            return lp, -np.inf
+            # log likelihood is not finite, return -np.inf for log
+            # probability and None for log prior (again, this value isn't
+            # used but we have to have the correct number of return values)
+            return -np.inf, None
+
+        # return log probability (sum of log prior and log likelihood)
+        # and log prior. Log prior will be saved as part of the blobs.
         return lp + ll, lp
 
     coords = np.random.randn(32, 3)
@@ -50,8 +69,9 @@
     print(log_prior_samps.shape)  # (100, 32)
     print(flat_log_prior_samps.shape)  # (3200,)
 
-After running this, the "blobs" stored by the sampler will be a ``(nsteps,
-nwalkers)`` NumPy array with the value of the log prior at every sample.
+As shown above, after running this, the "blobs" stored by the sampler will be
+a ``(nsteps, nwalkers)`` NumPy array with the value of the log prior at every
+sample.
 
 Named blobs & custom dtypes
 ---------------------------
@@ -60,6 +80,9 @@
 them.
 To implement this, we use the ``blobs_dtype`` argument in
 :class:`EnsembleSampler`.
+Using this is also helpful to specify types.
+If you don't provide ``blobs_dtype``, the dtype of the extra args is 
automatically guessed the first time ``log_prob`` is called.
+
 For example, let's say that, for some reason, we wanted to save the mean of
 the parameters as well as the log prior.
 To do this, we would update the above example as follows:
@@ -69,16 +92,25 @@
     def log_prob(params):
         lp = log_prior(params)
         if not np.isfinite(lp):
-            return -np.inf, -np.inf, -np.inf
+            # As above, log prior is not finite, so return -np.inf for log
+            # probability and None for everything else (these values aren't
+            # used, but the number of return values must be correct)
+            return -np.inf, None, None
         ll = log_like(params)
         if not np.isfinite(ll):
-            return lp, -np.inf, -np.inf
+            # Log likelihood is not finite so return -np.inf for log
+            # probabilitiy and None for everything else (maintaining the
+            # correct number of return values)
+            return -np.inf, None, None
+
+        # All values are finite, so return desired blobs (in this case: log
+        # probability, log prior and mean of parameters)
         return lp + ll, lp, np.mean(params)
 
     coords = np.random.randn(32, 3)
     nwalkers, ndim = coords.shape
 
-    # Here are the important lines
+    # Here are the important lines for defining the blobs_dtype
     dtype = [("log_prior", float), ("mean", float)]
     sampler = emcee.EnsembleSampler(nwalkers, ndim, log_prob,
                                     blobs_dtype=dtype)
@@ -88,14 +120,14 @@
     blobs = sampler.get_blobs()
     log_prior_samps = blobs["log_prior"]
     mean_samps = blobs["mean"]
-    print(log_prior_samps.shape)
-    print(mean_samps.shape)
+    print(log_prior_samps.shape)  # (100, 32)
+    print(mean_samps.shape)  # (100, 32)
 
     flat_blobs = sampler.get_blobs(flat=True)
     flat_log_prior_samps = flat_blobs["log_prior"]
     flat_mean_samps = flat_blobs["mean"]
-    print(flat_log_prior_samps.shape)
-    print(flat_mean_samps.shape)
+    print(flat_log_prior_samps.shape)  # (3200,)
+    print(flat_mean_samps.shape)  # (3200,)
 
 This will print
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/readthedocs.yml 
new/emcee-3.1.6/readthedocs.yml
--- old/emcee-3.1.4/readthedocs.yml     2023-01-27 13:19:09.000000000 +0100
+++ new/emcee-3.1.6/readthedocs.yml     1970-01-01 01:00:00.000000000 +0100
@@ -1,13 +0,0 @@
-version: 2
-
-python:
-  version: 3.8
-  install:
-    - requirements: docs/requirements.txt
-    - method: pip
-      path: .
-
-sphinx:
-  configuration: docs/conf.py
-  fail_on_warning: true
-  builder: dirhtml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee/autocorr.py 
new/emcee-3.1.6/src/emcee/autocorr.py
--- old/emcee-3.1.4/src/emcee/autocorr.py       2023-01-27 13:19:09.000000000 
+0100
+++ new/emcee-3.1.6/src/emcee/autocorr.py       2024-04-19 11:49:57.000000000 
+0200
@@ -46,7 +46,7 @@
     return len(taus) - 1
 
 
-def integrated_time(x, c=5, tol=50, quiet=False):
+def integrated_time(x, c=5, tol=50, quiet=False, has_walkers=True):
     """Estimate the integrated autocorrelation time of a time series.
 
     This estimate uses the iterative procedure described on page 16 of
@@ -54,9 +54,11 @@
     determine a reasonable window size.
 
     Args:
-        x: The time series. If multidimensional, set the time axis using the
-            ``axis`` keyword argument and the function will be computed for
-            every other axis.
+        x (numpy.ndarray): The time series. If 2-dimensional, the array
+            dimesions are interpreted as ``(n_step, n_walker)`` unless
+            ``has_walkers==False``, in which case they are interpreted as
+            ``(n_step, n_param)``. If 3-dimensional, the dimensions are
+            interperted as ``(n_step, n_walker, n_param)``.
         c (Optional[float]): The step size for the window search. (default:
             ``5``)
         tol (Optional[float]): The minimum number of autocorrelation times
@@ -64,10 +66,13 @@
         quiet (Optional[bool]): This argument controls the behavior when the
             chain is too short. If ``True``, give a warning instead of raising
             an :class:`AutocorrError`. (default: ``False``)
+        has_walkers (Optional[bool]): Whether the last axis should be
+            interpreted as walkers or parameters if ``x`` has 2 dimensions.
+            (default: ``True``)
 
     Returns:
         float or array: An estimate of the integrated autocorrelation time of
-            the time series ``x`` computed along the axis ``axis``.
+            the time series ``x``.
 
     Raises
         AutocorrError: If the autocorrelation time can't be reliably estimated
@@ -79,7 +84,10 @@
     if len(x.shape) == 1:
         x = x[:, np.newaxis, np.newaxis]
     if len(x.shape) == 2:
-        x = x[:, :, np.newaxis]
+        if not has_walkers:
+            x = x[:, np.newaxis, :]
+        else:
+            x = x[:, :, np.newaxis]
     if len(x.shape) != 3:
         raise ValueError("invalid dimensions")
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee/emcee_version.py 
new/emcee-3.1.6/src/emcee/emcee_version.py
--- old/emcee-3.1.4/src/emcee/emcee_version.py  2023-01-27 13:19:19.000000000 
+0100
+++ new/emcee-3.1.6/src/emcee/emcee_version.py  2024-04-19 11:50:06.000000000 
+0200
@@ -1 +1 @@
-__version__ = "3.1.4"
+__version__ = "3.1.6"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee/ensemble.py 
new/emcee-3.1.6/src/emcee/ensemble.py
--- old/emcee-3.1.4/src/emcee/ensemble.py       2023-01-27 13:19:09.000000000 
+0100
+++ new/emcee-3.1.6/src/emcee/ensemble.py       2024-04-19 11:49:57.000000000 
+0200
@@ -21,6 +21,13 @@
     # for py2.7, will be an Exception in 3.8
     from collections import Iterable
 
+try:
+    # Try to import from numpy.exceptions (available in NumPy 1.25 and later)
+    from numpy.exceptions import VisibleDeprecationWarning
+except ImportError:
+    # Fallback to the top-level numpy import (for older versions)
+    from numpy import VisibleDeprecationWarning
+
 
 class EnsembleSampler(object):
     """An ensemble MCMC sampler
@@ -45,10 +52,10 @@
             (default: :class:`StretchMove`)
         args (Optional): A list of extra positional arguments for
             ``log_prob_fn``. ``log_prob_fn`` will be called with the sequence
-            ``log_pprob_fn(p, *args, **kwargs)``.
+            ``log_prob_fn(p, *args, **kwargs)``.
         kwargs (Optional): A dict of extra keyword arguments for
             ``log_prob_fn``. ``log_prob_fn`` will be called with the sequence
-            ``log_pprob_fn(p, *args, **kwargs)``.
+            ``log_prob_fn(p, *args, **kwargs)``.
         pool (Optional): An object with a ``map`` method that follows the same
             calling sequence as the built-in ``map`` function. This is
             generally used to compute the log-probabilities for the ensemble
@@ -179,7 +186,7 @@
                 if name not in dupes:
                     uniq.append(name)
                     dupes.add(name)
-            msg = f"duplicate paramters: {dupes}"
+            msg = f"duplicate parameters: {dupes}"
             assert len(uniq) == len(parameter_names), msg
 
             if isinstance(parameter_names, list):
@@ -489,10 +496,19 @@
             results = list(map_func(self.log_prob_fn, p))
 
         try:
-            log_prob = np.array([float(l[0]) for l in results])
-            blob = [l[1:] for l in results]
+            # perhaps log_prob_fn returns blobs?
+
+            # deal with the blobs first
+            # if l does not have a len attribute (i.e. not a sequence, no blob)
+            # then a TypeError is raised. However, no error will be raised if
+            # l is a length-1 array, np.array([1.234]). In that case blob
+            # will become an empty list.
+            blob = [l[1:] for l in results if len(l) > 1]
+            if not len(blob):
+                raise IndexError
+            log_prob = np.array([_scalar(l[0]) for l in results])
         except (IndexError, TypeError):
-            log_prob = np.array([float(l) for l in results])
+            log_prob = np.array([_scalar(l) for l in results])
             blob = None
         else:
             # Get the blobs dtype
@@ -502,7 +518,7 @@
                 try:
                     with warnings.catch_warnings(record=True):
                         warnings.simplefilter(
-                            "error", np.VisibleDeprecationWarning
+                            "error", VisibleDeprecationWarning
                         )
                         try:
                             dt = np.atleast_1d(blob[0]).dtype
@@ -682,3 +698,16 @@
       list of dictionaries of parameters
     """
     return [{key: xi[val] for key, val in key_map.items()} for xi in x]
+
+
+def _scalar(fx):
+    # Make sure a value is a true scalar
+    # 1.0, np.float64(1.0), np.array([1.0]), np.array(1.0)
+    if not np.isscalar(fx):
+        try:
+            fx = np.asarray(fx).item()
+        except (TypeError, ValueError) as e:
+            raise ValueError("log_prob_fn should return scalar") from e
+        return float(fx)
+    else:
+        return float(fx)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee/moves/de.py 
new/emcee-3.1.6/src/emcee/moves/de.py
--- old/emcee-3.1.4/src/emcee/moves/de.py       2023-01-27 13:19:09.000000000 
+0100
+++ new/emcee-3.1.6/src/emcee/moves/de.py       2024-04-19 11:49:57.000000000 
+0200
@@ -1,4 +1,5 @@
 # -*- coding: utf-8 -*-
+from functools import lru_cache
 
 import numpy as np
 
@@ -13,7 +14,7 @@
     This `Differential evolution proposal
     <http://www.stat.columbia.edu/~gelman/stuff_for_blog/cajo.pdf>`_ is
     implemented following `Nelson et al. (2013)
-    <https://arxiv.org/abs/1311.5229>`_.
+    <https://doi.org/10.1088/0067-0049/210/1/11>`_.
 
     Args:
         sigma (float): The standard deviation of the Gaussian used to stretch
@@ -27,8 +28,7 @@
     def __init__(self, sigma=1.0e-5, gamma0=None, **kwargs):
         self.sigma = sigma
         self.gamma0 = gamma0
-        kwargs["nsplits"] = 3
-        super(DEMove, self).__init__(**kwargs)
+        super().__init__(**kwargs)
 
     def setup(self, coords):
         self.g0 = self.gamma0
@@ -38,14 +38,40 @@
             self.g0 = 2.38 / np.sqrt(2 * ndim)
 
     def get_proposal(self, s, c, random):
-        Ns = len(s)
-        Nc = list(map(len, c))
-        ndim = s.shape[1]
-        q = np.empty((Ns, ndim), dtype=np.float64)
-        f = self.sigma * random.randn(Ns)
-        for i in range(Ns):
-            w = np.array([c[j][random.randint(Nc[j])] for j in range(2)])
-            random.shuffle(w)
-            g = np.diff(w, axis=0) * self.g0 + f[i]
-            q[i] = s[i] + g
-        return q, np.zeros(Ns, dtype=np.float64)
+        c = np.concatenate(c, axis=0)
+        ns, ndim = s.shape
+        nc = c.shape[0]
+
+        # Get the pair indices
+        pairs = _get_nondiagonal_pairs(nc)
+
+        # Sample from the pairs
+        indices = random.choice(pairs.shape[0], size=ns, replace=True)
+        pairs = pairs[indices]
+
+        # Compute diff vectors
+        diffs = np.diff(c[pairs], axis=1).squeeze(axis=1)  # (ns, ndim)
+
+        # Sample a gamma value for each walker following Nelson et al. (2013)
+        gamma = self.g0 * (1 + self.sigma * random.randn(ns, 1))  # (ns, 1)
+
+        # In this way, sigma is the standard deviation of the distribution of 
gamma,
+        # instead of the standard deviation of the distribution of the 
proposal as proposed by Ter Braak (2006).
+        # Otherwise, sigma should be tuned for each dimension, which confronts 
the idea of affine-invariance.
+
+        q = s + gamma * diffs
+
+        return q, np.zeros(ns, dtype=np.float64)
+
+
+@lru_cache(maxsize=1)
+def _get_nondiagonal_pairs(n: int) -> np.ndarray:
+    """Get the indices of a square matrix with size n, excluding the 
diagonal."""
+    rows, cols = np.tril_indices(n, -1)  # -1 to exclude diagonal
+
+    # Combine rows-cols and cols-rows pairs
+    pairs = np.column_stack(
+        [np.concatenate([rows, cols]), np.concatenate([cols, rows])]
+    )
+
+    return pairs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee/moves/de_snooker.py 
new/emcee-3.1.6/src/emcee/moves/de_snooker.py
--- old/emcee-3.1.4/src/emcee/moves/de_snooker.py       2023-01-27 
13:19:09.000000000 +0100
+++ new/emcee-3.1.6/src/emcee/moves/de_snooker.py       2024-04-19 
11:49:57.000000000 +0200
@@ -32,7 +32,7 @@
         Ns = len(s)
         Nc = list(map(len, c))
         ndim = s.shape[1]
-        q = np.empty((Ns, ndim), dtype=np.float64)
+        q = np.empty_like(s)
         metropolis = np.empty(Ns, dtype=np.float64)
         for i in range(Ns):
             w = np.array([c[j][random.randint(Nc[j])] for j in range(3)])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee/moves/gaussian.py 
new/emcee-3.1.6/src/emcee/moves/gaussian.py
--- old/emcee-3.1.4/src/emcee/moves/gaussian.py 2023-01-27 13:19:09.000000000 
+0100
+++ new/emcee-3.1.6/src/emcee/moves/gaussian.py 2024-04-19 11:49:57.000000000 
+0200
@@ -60,7 +60,6 @@
 
 
 class _isotropic_proposal(object):
-
     allowed_modes = ["vector", "random", "sequential"]
 
     def __init__(self, scale, factor, mode):
@@ -111,7 +110,6 @@
 
 
 class _proposal(_isotropic_proposal):
-
     allowed_modes = ["vector"]
 
     def get_updated_vector(self, rng, x0):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee/moves/walk.py 
new/emcee-3.1.6/src/emcee/moves/walk.py
--- old/emcee-3.1.4/src/emcee/moves/walk.py     2023-01-27 13:19:09.000000000 
+0100
+++ new/emcee-3.1.6/src/emcee/moves/walk.py     2024-04-19 11:49:57.000000000 
+0200
@@ -28,7 +28,7 @@
         c = np.concatenate(c, axis=0)
         Ns, Nc = len(s), len(c)
         ndim = s.shape[1]
-        q = np.empty((Ns, ndim), dtype=np.float64)
+        q = np.empty_like(s)
         s0 = Nc if self.s is None else self.s
         for i in range(Ns):
             inds = random.choice(Nc, s0, replace=False)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee/tests/unit/test_autocorr.py 
new/emcee-3.1.6/src/emcee/tests/unit/test_autocorr.py
--- old/emcee-3.1.4/src/emcee/tests/unit/test_autocorr.py       2023-01-27 
13:19:09.000000000 +0100
+++ new/emcee-3.1.6/src/emcee/tests/unit/test_autocorr.py       2024-04-19 
11:49:57.000000000 +0200
@@ -28,6 +28,13 @@
     assert np.all(np.abs(tau - 19.0) / 19.0 < 0.2)
 
 
+def test_nd_without_walkers(seed=1234, ndim=3, N=10000):
+    x = get_chain(seed=seed, ndim=ndim, N=N)
+    tau1 = integrated_time(x[:, np.newaxis])
+    tau2 = integrated_time(x, has_walkers=False)
+    assert np.allclose(tau1, tau2)
+
+
 def test_too_short(seed=1234, ndim=3, N=100):
     x = get_chain(seed=seed, ndim=ndim, N=N)
     with pytest.raises(AutocorrError):
@@ -39,10 +46,9 @@
     np.random.seed(42)
     xs = np.random.randn(16384, 2)
 
-    # This throws exception unconditionally in buggy impl's
-    acls_multi = integrated_time(xs)
+    acls_multi = integrated_time(xs[:, np.newaxis])
     acls_single = np.array(
         [integrated_time(xs[:, i]) for i in range(xs.shape[1])]
-    )
+    ).squeeze()
 
-    assert np.all(np.abs(acls_multi - acls_single) < 2)
+    assert np.allclose(acls_multi, acls_single)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee/tests/unit/test_ensemble.py 
new/emcee-3.1.6/src/emcee/tests/unit/test_ensemble.py
--- old/emcee-3.1.4/src/emcee/tests/unit/test_ensemble.py       2023-01-27 
13:19:09.000000000 +0100
+++ new/emcee-3.1.6/src/emcee/tests/unit/test_ensemble.py       2024-04-19 
11:49:57.000000000 +0200
@@ -1,6 +1,7 @@
 """
 Unit tests of some functionality in ensemble.py when the parameters are named
 """
+
 import string
 from unittest import TestCase
 
@@ -182,3 +183,37 @@
         assert results.coords.shape == (n_walkers, len(self.names))
         chain = sampler.chain
         assert chain.shape == (n_walkers, n_steps, len(self.names))
+
+
+class TestLnProbFn(TestCase):
+    # checks that the log_prob_fn can deal with a variety of 'scalar-likes'
+    def lnpdf(self, x):
+        v = np.log(np.sqrt(np.pi) * np.exp(-((x / 2.0) ** 2)))
+        v = float(v[0])
+        assert np.isscalar(v)
+        return v
+
+    def lnpdf_arr1(self, x):
+        v = self.lnpdf(x)
+        return np.array([v])
+
+    def lnpdf_float64(self, x):
+        v = self.lnpdf(x)
+        return np.float64(v)
+
+    def lnpdf_arr0D(self, x):
+        v = self.lnpdf(x)
+        return np.array(v)
+
+    def test_deal_with_scalar_likes(self):
+        rng = np.random.default_rng()
+        fns = [
+            self.lnpdf,
+            self.lnpdf_arr1,
+            self.lnpdf_float64,
+            self.lnpdf_arr0D,
+        ]
+        for fn in fns:
+            init = rng.random((50, 1))
+            sampler = EnsembleSampler(50, 1, fn)
+            _ = sampler.run_mcmc(initial_state=init, nsteps=20)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee.egg-info/PKG-INFO 
new/emcee-3.1.6/src/emcee.egg-info/PKG-INFO
--- old/emcee-3.1.4/src/emcee.egg-info/PKG-INFO 2023-01-27 13:19:19.000000000 
+0100
+++ new/emcee-3.1.6/src/emcee.egg-info/PKG-INFO 2024-04-19 11:50:06.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: emcee
-Version: 3.1.4
+Version: 3.1.6
 Summary: The Python ensemble sampling toolkit for MCMC
 Home-page: https://emcee.readthedocs.io
 Author: Daniel Foreman-Mackey
@@ -16,10 +16,16 @@
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
 Description-Content-Type: text/x-rst
-Provides-Extra: extras
-Provides-Extra: tests
 License-File: LICENSE
 License-File: AUTHORS.rst
+Requires-Dist: numpy
+Provides-Extra: extras
+Requires-Dist: h5py; extra == "extras"
+Requires-Dist: scipy; extra == "extras"
+Provides-Extra: tests
+Requires-Dist: pytest; extra == "tests"
+Requires-Dist: pytest-cov; extra == "tests"
+Requires-Dist: coverage[toml]; extra == "tests"
 
 emcee
 =====
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/src/emcee.egg-info/SOURCES.txt 
new/emcee-3.1.6/src/emcee.egg-info/SOURCES.txt
--- old/emcee-3.1.4/src/emcee.egg-info/SOURCES.txt      2023-01-27 
13:19:19.000000000 +0100
+++ new/emcee-3.1.6/src/emcee.egg-info/SOURCES.txt      2024-04-19 
11:50:06.000000000 +0200
@@ -1,6 +1,7 @@
 .gitattributes
 .gitignore
 .pre-commit-config.yaml
+.readthedocs.yaml
 AUTHORS.rst
 CODE_OF_CONDUCT.md
 CONTRIBUTING.md
@@ -10,7 +11,6 @@
 README.rst
 VISION.md
 pyproject.toml
-readthedocs.yml
 setup.py
 tox.ini
 .github/ISSUE_TEMPLATE.md
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/emcee-3.1.4/tox.ini new/emcee-3.1.6/tox.ini
--- old/emcee-3.1.4/tox.ini     2023-01-27 13:19:09.000000000 +0100
+++ new/emcee-3.1.6/tox.ini     2024-04-19 11:49:57.000000000 +0200
@@ -1,12 +1,12 @@
 [tox]
-envlist = py{37,38,39,310}{,-extras},lint
+envlist = py{39,310,311,312}{,-extras},lint
 
 [gh-actions]
 python =
-    3.7: py37
-    3.8: py38
-    3.9: py39-extras
+    3.9: py39
     3.10: py310
+    3.11: py311-extras
+    3.12: py312
 
 [testenv]
 deps = coverage[toml]

Reply via email to