numpyro_schechter


Namenumpyro_schechter JSON
Version 1.1.0 PyPI version JSON
download
home_pageNone
SummarySchechter galaxy luminosity distribution for NumPyro.
upload_time2025-08-21 05:12:41
maintainerNone
docs_urlNone
authorAlice Serene
requires_python<3.14,>=3.10
licenseMIT
keywords numpyro schechter astronomy bayesian distribution
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # numpyro_schechter

**Schechter galaxy luminosity distribution for NumPyro**

<p align="center">
  <img src="https://raw.githubusercontent.com/alserene/numpyro_schechter/main/docs/assets/logo.png" alt="Schechter distribution logo for numpyro_schechter" width="300"/>
</p>

<p align="center">
  <a href="https://pypi.org/project/numpyro-schechter/">
    <img src="https://img.shields.io/pypi/pyversions/numpyro-schechter.svg" alt="Python Versions">
  </a>
  <a href="https://numpyro-schechter.readthedocs.io/en/latest/?badge=latest">
    <img src="https://readthedocs.org/projects/numpyro-schechter/badge/?version=latest" alt="Docs Status">
  </a>
  <a href="https://pypi.org/project/numpyro-schechter/">
    <img src="https://img.shields.io/pypi/v/numpyro-schechter.svg" alt="PyPI">
  </a>
  <a href="https://opensource.org/licenses/MIT">
    <img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="MIT License">
  </a>
  <a href="https://github.com/alserene/numpyro_schechter/actions/workflows/tests.yml">
    <img src="https://github.com/alserene/numpyro_schechter/actions/workflows/tests.yml/badge.svg" alt="Tests">
  </a>
</p>

---

## Overview

`numpyro_schechter` provides NumPyro-compatible probability distributions for Bayesian inference with Schechter and double Schechter luminosity functions in absolute magnitude space.

Built for astronomers and statisticians, it includes a JAX-compatible, differentiable implementation of the upper incomplete gamma function, enabling stable and efficient modelling in probabilistic programming frameworks.

---

## Parameter Constraints

Due to the custom normalisation logic, some constraints apply:

- `alpha` must be real and non-integer.
- The valid range of `alpha + 1` depends on `alpha_domain_depth`. By default, `alpha_domain_depth=3`, which supports the domain `-3 < alpha + 1 < 3`.
- To model more extreme values of `alpha`, increase the `alpha_domain_depth` parameter (see below).
- The list of valid depths is fixed and can be queried programmatically:
  ```python
  from numpyro_schechter import SchechterMag
  SchechterMag.supported_depths()
  # -> [3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30]
  ```
- If you set `include_poisson_term=True`, the log-likelihood will also include a Poisson term for the total number counts, with expectation `N_exp = norm * volume`. The volume argument defaults to `1.0` but can be set to your survey volume.

---

## Installation

From PyPI:

```bash
pip install numpyro_schechter
```

From GitHub (latest development version):

```bash
pip install git+https://github.com/alserene/numpyro_schechter.git
```

---

## Usage

### Single Schechter Example

Here is a minimal example showing how to use the `SchechterMag` distribution:

```python
import jax.numpy as jnp
import numpyro
import numpyro.distributions as dist
from numpyro_schechter.distribution import SchechterMag

# Simulated observed magnitudes
mag_obs = jnp.linspace(-24, -18, 100)

def model(mag_obs):
    # Priors
    alpha = numpyro.sample("alpha", dist.Uniform(-3.0, 1.0))
    M_star = numpyro.sample("M_star", dist.Uniform(-24.0, -20.0))
    logphi = numpyro.sample("logphi", dist.Normal(-3.0, 1.0))

    # Custom likelihood using the SchechterMag distribution, fitting only
    # the shape. Adding include_poisson_term=True would include total counts.
    # See Double Schechter Example for fitting both shape and total count.
    schechter_dist = SchechterMag(alpha=alpha, M_star=M_star, logphi=logphi,
                                  mag_obs=mag_obs)
    
    # Manually inject log-likelihood of observed magnitudes.
    # Required because SchechterMag/DoubleSchechterMag are custom distributions.
    log_likelihood = jnp.sum(schechter_dist.log_prob(mag_obs))
    numpyro.factor("likelihood", log_likelihood)

# You can now run inference with NumPyro's MCMC
# e.g., numpyro.infer.MCMC(...).run(rng_key, model, mag_obs=...)

# Note: Sampling is not implemented for SchechterMag or DoubleSchechterMag;
# it is intended for use as a likelihood in inference.
```

### Double Schechter Example

The double Schechter function is the sum of two Schechter components, each with their own parameters 
$(\alpha, M^\*, \phi^\*)$, normalised together over the observed magnitude range:

$$
\phi_{\text{double}}(M) = 
\frac{\phi_1(M) + \phi_2(M)}{\phi_1^\* \Gamma_1 + \phi_2^\* \Gamma_2}
$$

where $\Gamma_i$ is the upper incomplete gamma function for component $i$.

```python
import jax.numpy as jnp
import numpyro
import numpyro.distributions as dist
from numpyro_schechter import DoubleSchechterMag

def double_schechter_model(mag_obs, volume):
    # Slopes
    alpha1 = numpyro.sample("alpha1", dist.TruncatedNormal(-0.3, 0.1, low=-1.5, high=0.5))
    alpha2 = numpyro.sample("alpha2", dist.TruncatedNormal(-1.3, 0.1, low=-2.5, high=-0.5))

    # Normalisations (log10 φ*)
    logphi1 = numpyro.sample("logphi1", dist.Normal(-2.5, 0.3))
    logphi2 = numpyro.sample("logphi2", dist.Normal(-3.0, 0.3))

    # Break magnitudes
    M_star1 = numpyro.sample("M_star1", dist.TruncatedNormal(-21.0, 0.5, low=-23.0, high=-19.0))
    M_star2 = numpyro.sample("M_star2", dist.TruncatedNormal(-21.5, 0.5, low=-23.5, high=-19.5))

    # Likelihood: includes both point term and Poisson count term to fit
    # both shape and total count. If include_poisson_term=True, then volume
    # is used to scale expected counts and defaults to 1.0.
    dbl_schechter_dist = DoubleSchechterMag(alpha1, M_star1, logphi1,
                                    alpha2, M_star2, logphi2,
                                    mag_obs=mag_obs,
                                    include_poisson_term=True,
                                    volume=volume)

    # Manually inject log-likelihood of observed magnitudes.
    # Required because SchechterMag/DoubleSchechterMag are custom distributions.
    log_likelihood = jnp.sum(dbl_schechter_dist.log_prob(mag_obs))
    numpyro.factor("likelihood", log_likelihood)

# --- Example MCMC runner (same approach can be used for SchechterMag)
# from numpyro.infer import MCMC, NUTS
# mcmc = MCMC(NUTS(double_schechter_model), num_warmup=1000, num_samples=2000)
# mcmc.run(rng_key, mag_obs=your_magnitude_array, volume=your_survey_volume)
# samples = mcmc.get_samples()

```

For detailed usage and API documentation, please visit the [Documentation](https://numpyro-schechter.readthedocs.io/).

---

## Development

If you want to contribute or develop locally:

```bash
git clone https://github.com/alserene/numpyro_schechter.git
cd numpyro_schechter
poetry install
poetry run pytest
```

---

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file.

---

## Contact

Created by
 - Alice — [aserene@swin.edu.au](mailto:aserene@swin.edu.au)
 - Aryan - [aryanbansal@swin.edu.au](mailto:aryanbansal@swin.edu.au)
 - Edward - [entaylor@swin.edu.au](mailto:entaylor@swin.edu.au)

---

*Happy modelling!*

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "numpyro_schechter",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<3.14,>=3.10",
    "maintainer_email": null,
    "keywords": "numpyro, schechter, astronomy, bayesian, distribution",
    "author": "Alice Serene",
    "author_email": "aserene@swin.edu.au",
    "download_url": "https://files.pythonhosted.org/packages/4b/86/7dcba7608255be56fee5a7c825bf68e7e280ebf1ba3bfb13f0163acc3185/numpyro_schechter-1.1.0.tar.gz",
    "platform": null,
    "description": "# numpyro_schechter\n\n**Schechter galaxy luminosity distribution for NumPyro**\n\n<p align=\"center\">\n  <img src=\"https://raw.githubusercontent.com/alserene/numpyro_schechter/main/docs/assets/logo.png\" alt=\"Schechter distribution logo for numpyro_schechter\" width=\"300\"/>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://pypi.org/project/numpyro-schechter/\">\n    <img src=\"https://img.shields.io/pypi/pyversions/numpyro-schechter.svg\" alt=\"Python Versions\">\n  </a>\n  <a href=\"https://numpyro-schechter.readthedocs.io/en/latest/?badge=latest\">\n    <img src=\"https://readthedocs.org/projects/numpyro-schechter/badge/?version=latest\" alt=\"Docs Status\">\n  </a>\n  <a href=\"https://pypi.org/project/numpyro-schechter/\">\n    <img src=\"https://img.shields.io/pypi/v/numpyro-schechter.svg\" alt=\"PyPI\">\n  </a>\n  <a href=\"https://opensource.org/licenses/MIT\">\n    <img src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"MIT License\">\n  </a>\n  <a href=\"https://github.com/alserene/numpyro_schechter/actions/workflows/tests.yml\">\n    <img src=\"https://github.com/alserene/numpyro_schechter/actions/workflows/tests.yml/badge.svg\" alt=\"Tests\">\n  </a>\n</p>\n\n---\n\n## Overview\n\n`numpyro_schechter` provides NumPyro-compatible probability distributions for Bayesian inference with Schechter and double Schechter luminosity functions in absolute magnitude space.\n\nBuilt for astronomers and statisticians, it includes a JAX-compatible, differentiable implementation of the upper incomplete gamma function, enabling stable and efficient modelling in probabilistic programming frameworks.\n\n---\n\n## Parameter Constraints\n\nDue to the custom normalisation logic, some constraints apply:\n\n- `alpha` must be real and non-integer.\n- The valid range of `alpha + 1` depends on `alpha_domain_depth`. By default, `alpha_domain_depth=3`, which supports the domain `-3 < alpha + 1 < 3`.\n- To model more extreme values of `alpha`, increase the `alpha_domain_depth` parameter (see below).\n- The list of valid depths is fixed and can be queried programmatically:\n  ```python\n  from numpyro_schechter import SchechterMag\n  SchechterMag.supported_depths()\n  # -> [3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30]\n  ```\n- If you set `include_poisson_term=True`, the log-likelihood will also include a Poisson term for the total number counts, with expectation `N_exp = norm * volume`. The volume argument defaults to `1.0` but can be set to your survey volume.\n\n---\n\n## Installation\n\nFrom PyPI:\n\n```bash\npip install numpyro_schechter\n```\n\nFrom GitHub (latest development version):\n\n```bash\npip install git+https://github.com/alserene/numpyro_schechter.git\n```\n\n---\n\n## Usage\n\n### Single Schechter Example\n\nHere is a minimal example showing how to use the `SchechterMag` distribution:\n\n```python\nimport jax.numpy as jnp\nimport numpyro\nimport numpyro.distributions as dist\nfrom numpyro_schechter.distribution import SchechterMag\n\n# Simulated observed magnitudes\nmag_obs = jnp.linspace(-24, -18, 100)\n\ndef model(mag_obs):\n    # Priors\n    alpha = numpyro.sample(\"alpha\", dist.Uniform(-3.0, 1.0))\n    M_star = numpyro.sample(\"M_star\", dist.Uniform(-24.0, -20.0))\n    logphi = numpyro.sample(\"logphi\", dist.Normal(-3.0, 1.0))\n\n    # Custom likelihood using the SchechterMag distribution, fitting only\n    # the shape. Adding include_poisson_term=True would include total counts.\n    # See Double Schechter Example for fitting both shape and total count.\n    schechter_dist = SchechterMag(alpha=alpha, M_star=M_star, logphi=logphi,\n                                  mag_obs=mag_obs)\n    \n    # Manually inject log-likelihood of observed magnitudes.\n    # Required because SchechterMag/DoubleSchechterMag are custom distributions.\n    log_likelihood = jnp.sum(schechter_dist.log_prob(mag_obs))\n    numpyro.factor(\"likelihood\", log_likelihood)\n\n# You can now run inference with NumPyro's MCMC\n# e.g., numpyro.infer.MCMC(...).run(rng_key, model, mag_obs=...)\n\n# Note: Sampling is not implemented for SchechterMag or DoubleSchechterMag;\n# it is intended for use as a likelihood in inference.\n```\n\n### Double Schechter Example\n\nThe double Schechter function is the sum of two Schechter components, each with their own parameters \n$(\\alpha, M^\\*, \\phi^\\*)$, normalised together over the observed magnitude range:\n\n$$\n\\phi_{\\text{double}}(M) = \n\\frac{\\phi_1(M) + \\phi_2(M)}{\\phi_1^\\* \\Gamma_1 + \\phi_2^\\* \\Gamma_2}\n$$\n\nwhere $\\Gamma_i$ is the upper incomplete gamma function for component $i$.\n\n```python\nimport jax.numpy as jnp\nimport numpyro\nimport numpyro.distributions as dist\nfrom numpyro_schechter import DoubleSchechterMag\n\ndef double_schechter_model(mag_obs, volume):\n    # Slopes\n    alpha1 = numpyro.sample(\"alpha1\", dist.TruncatedNormal(-0.3, 0.1, low=-1.5, high=0.5))\n    alpha2 = numpyro.sample(\"alpha2\", dist.TruncatedNormal(-1.3, 0.1, low=-2.5, high=-0.5))\n\n    # Normalisations (log10 \u03c6*)\n    logphi1 = numpyro.sample(\"logphi1\", dist.Normal(-2.5, 0.3))\n    logphi2 = numpyro.sample(\"logphi2\", dist.Normal(-3.0, 0.3))\n\n    # Break magnitudes\n    M_star1 = numpyro.sample(\"M_star1\", dist.TruncatedNormal(-21.0, 0.5, low=-23.0, high=-19.0))\n    M_star2 = numpyro.sample(\"M_star2\", dist.TruncatedNormal(-21.5, 0.5, low=-23.5, high=-19.5))\n\n    # Likelihood: includes both point term and Poisson count term to fit\n    # both shape and total count. If include_poisson_term=True, then volume\n    # is used to scale expected counts and defaults to 1.0.\n    dbl_schechter_dist = DoubleSchechterMag(alpha1, M_star1, logphi1,\n                                    alpha2, M_star2, logphi2,\n                                    mag_obs=mag_obs,\n                                    include_poisson_term=True,\n                                    volume=volume)\n\n    # Manually inject log-likelihood of observed magnitudes.\n    # Required because SchechterMag/DoubleSchechterMag are custom distributions.\n    log_likelihood = jnp.sum(dbl_schechter_dist.log_prob(mag_obs))\n    numpyro.factor(\"likelihood\", log_likelihood)\n\n# --- Example MCMC runner (same approach can be used for SchechterMag)\n# from numpyro.infer import MCMC, NUTS\n# mcmc = MCMC(NUTS(double_schechter_model), num_warmup=1000, num_samples=2000)\n# mcmc.run(rng_key, mag_obs=your_magnitude_array, volume=your_survey_volume)\n# samples = mcmc.get_samples()\n\n```\n\nFor detailed usage and API documentation, please visit the [Documentation](https://numpyro-schechter.readthedocs.io/).\n\n---\n\n## Development\n\nIf you want to contribute or develop locally:\n\n```bash\ngit clone https://github.com/alserene/numpyro_schechter.git\ncd numpyro_schechter\npoetry install\npoetry run pytest\n```\n\n---\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file.\n\n---\n\n## Contact\n\nCreated by\n - Alice \u2014 [aserene@swin.edu.au](mailto:aserene@swin.edu.au)\n - Aryan - [aryanbansal@swin.edu.au](mailto:aryanbansal@swin.edu.au)\n - Edward - [entaylor@swin.edu.au](mailto:entaylor@swin.edu.au)\n\n---\n\n*Happy modelling!*\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Schechter galaxy luminosity distribution for NumPyro.",
    "version": "1.1.0",
    "project_urls": {
        "Homepage": "https://github.com/alserene/numpyro_schechter",
        "Issues": "https://github.com/alserene/numpyro_schechter/issues"
    },
    "split_keywords": [
        "numpyro",
        " schechter",
        " astronomy",
        " bayesian",
        " distribution"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2946b3007670792664023e5515dd1661bb7adda6b17be1125232ee135671b5bd",
                "md5": "df10096d0328af09eddbbb281275f65d",
                "sha256": "5b45601c96254e04db5006622f0b424822796d57e94385669d1a8b6bfa377af5"
            },
            "downloads": -1,
            "filename": "numpyro_schechter-1.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "df10096d0328af09eddbbb281275f65d",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<3.14,>=3.10",
            "size": 8847,
            "upload_time": "2025-08-21T05:12:40",
            "upload_time_iso_8601": "2025-08-21T05:12:40.695465Z",
            "url": "https://files.pythonhosted.org/packages/29/46/b3007670792664023e5515dd1661bb7adda6b17be1125232ee135671b5bd/numpyro_schechter-1.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4b867dcba7608255be56fee5a7c825bf68e7e280ebf1ba3bfb13f0163acc3185",
                "md5": "d08ccd08d817c12e4e67fd937b4b26bd",
                "sha256": "32435cc0e999640b40140b8fa177be7900715095b61bea6581ae740f2cb9cbb2"
            },
            "downloads": -1,
            "filename": "numpyro_schechter-1.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "d08ccd08d817c12e4e67fd937b4b26bd",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<3.14,>=3.10",
            "size": 7581,
            "upload_time": "2025-08-21T05:12:41",
            "upload_time_iso_8601": "2025-08-21T05:12:41.976322Z",
            "url": "https://files.pythonhosted.org/packages/4b/86/7dcba7608255be56fee5a7c825bf68e7e280ebf1ba3bfb13f0163acc3185/numpyro_schechter-1.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-21 05:12:41",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "alserene",
    "github_project": "numpyro_schechter",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "numpyro_schechter"
}
        
Elapsed time: 1.12856s