diff --git a/design.md b/design.md
index fb0211d..f1b5a40 100644
--- a/design.md
+++ b/design.md
@@ -150,9 +150,10 @@ with code styling again. Here are the steps to follow:
- Install `black` and `pre-commit`:
```bash
$ pip install --user black pre-commit reorder_python_imports
+$ pre-commit install
```
-`pre-commit` will be tasked with automatically running `black` formatting
-whenever you commit some code.
+`pre-commit` will be tasked with automatically running `black` and `reorder_python_imports` formatting
+whenever you commit some code. The import guidelines are documented [here](https://github.com/asottile/reorder_python_imports#what-does-it-do).
- Manually running black formatting:
```bash
@@ -160,7 +161,7 @@ $ black .
```
from the root directory.
-- Automatically running black at each commit: You actually have nothing
+- Automatically running `black` and `reorder_python_imports` at each commit: You actually have nothing
else to do. If pre-commit is installed it will happen automatically for
you.
diff --git a/docs/notebooks/jax-cosmo-intro.ipynb b/docs/notebooks/jax-cosmo-intro.ipynb
index fdaf43c..cdc9a08 100644
--- a/docs/notebooks/jax-cosmo-intro.ipynb
+++ b/docs/notebooks/jax-cosmo-intro.ipynb
@@ -1,1198 +1,1202 @@
{
- "nbformat": 4,
- "nbformat_minor": 0,
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.8.2"
- },
- "colab": {
- "name": "jax-cosmo-intro.ipynb",
- "provenance": [],
- "toc_visible": true,
- "include_colab_link": true
- },
- "accelerator": "GPU"
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "view-in-github"
+ },
+ "source": [
+ "
"
+ ]
},
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "view-in-github",
- "colab_type": "text"
- },
- "source": [
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "lpIJcb3tcFkC",
- "colab_type": "text"
- },
- "source": [
- "# Introduction to jax-cosmo\n",
- "\n",
- "Authors:\n",
- " - [@EiffL](https://github.com/EiffL) (Francois Lanusse)\n",
- "\n",
- "### Overview\n",
- "\n",
- "`jax-cosmo` brings the power of automatic differentiation and XLA execution\n",
- "to cosmological computations, all the while preserving the readability and human\n",
- "friendliness of Python / NumPy.\n",
- "\n",
- "This is made possible by the [JAX](https://jax.readthedocs.io/en/latest/index.html) framework, which can be summarised as JAX = NumPy + autograd + GPU/TPU. We\n",
- "encourage the interested reader to follow this [introduction to JAX](https://jax.readthedocs.io/en/latest/notebooks/quickstart.html) but it will not be necessary to follow this notebook.\n",
- "\n",
- "\n",
- "### Learning objectives\n",
- "\n",
- "In this short introduction we will cover:\n",
- " - How to define computations of **2pt functions**\n",
- " - How to execute these computations on **GPU** (spoiler alert, you actually don't need to do anything, it happens automatically)\n",
- " - How to **take derivatives** of any quantities by automatic differentation\n",
- " - And finally, how to piece all of this together for efficient and reliable **Fisher matrices**.\n",
- "\n",
- "\n",
- "\n"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "Dlb7kXPYEf6Z",
- "colab_type": "text"
- },
- "source": [
- "## Installing and importing jax-cosmo\n",
- "\n",
- "One of the important aspects of `jax-cosmo` is that it is entirely Python-based\n",
- "so it can trivially be installed without compiling or downloading any third-party tools.\n",
- "\n",
- "Here is how to install the current release on your system:"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "yZWz-yxPcG6q",
- "colab_type": "code",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 51
- },
- "outputId": "b315e257-1cb3-4654-c8ff-2b319ab27b13"
- },
- "source": [
- "# Installing jax-cosmo\n",
- "!pip install --quiet jax-cosmo"
- ],
- "execution_count": 1,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "\u001b[?25l\r\u001b[K |█▌ | 10kB 28.3MB/s eta 0:00:01\r\u001b[K |███ | 20kB 3.0MB/s eta 0:00:01\r\u001b[K |████▍ | 30kB 4.0MB/s eta 0:00:01\r\u001b[K |█████▉ | 40kB 4.3MB/s eta 0:00:01\r\u001b[K |███████▎ | 51kB 3.5MB/s eta 0:00:01\r\u001b[K |████████▊ | 61kB 3.9MB/s eta 0:00:01\r\u001b[K |██████████▏ | 71kB 4.3MB/s eta 0:00:01\r\u001b[K |███████████▋ | 81kB 4.5MB/s eta 0:00:01\r\u001b[K |█████████████ | 92kB 4.9MB/s eta 0:00:01\r\u001b[K |██████████████▌ | 102kB 4.8MB/s eta 0:00:01\r\u001b[K |████████████████ | 112kB 4.8MB/s eta 0:00:01\r\u001b[K |█████████████████▌ | 122kB 4.8MB/s eta 0:00:01\r\u001b[K |███████████████████ | 133kB 4.8MB/s eta 0:00:01\r\u001b[K |████████████████████▍ | 143kB 4.8MB/s eta 0:00:01\r\u001b[K |█████████████████████▉ | 153kB 4.8MB/s eta 0:00:01\r\u001b[K |███████████████████████▎ | 163kB 4.8MB/s eta 0:00:01\r\u001b[K |████████████████████████▊ | 174kB 4.8MB/s eta 0:00:01\r\u001b[K |██████████████████████████▏ | 184kB 4.8MB/s eta 0:00:01\r\u001b[K |███████████████████████████▋ | 194kB 4.8MB/s eta 0:00:01\r\u001b[K |█████████████████████████████ | 204kB 4.8MB/s eta 0:00:01\r\u001b[K |██████████████████████████████▌ | 215kB 4.8MB/s eta 0:00:01\r\u001b[K |████████████████████████████████| 225kB 4.8MB/s \n",
- "\u001b[?25h Building wheel for jax-cosmo (setup.py) ... \u001b[?25l\u001b[?25hdone\n"
- ],
- "name": "stdout"
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "xvIGKcbXFEFO",
- "colab_type": "text"
- },
- "source": [
- "For efficient computation on GPU (if you have one), you might want to make sure that JAX itself is installed with the proper GPU-enabled backend. See [here](https://github.com/google/jax#installation) for more instructions.\n",
- "\n",
- "Now that `jax-cosmo` is installed, let's import it along with JAX tools:"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "AZkSj6XNcFkE",
- "colab_type": "code",
- "outputId": "6a325574-7540-4d62-bbfc-fcfaf00f009d",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "%pylab inline\n",
- "import jax\n",
- "import jax_cosmo as jc\n",
- "import jax.numpy as np"
- ],
- "execution_count": 2,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "Populating the interactive namespace from numpy and matplotlib\n"
- ],
- "name": "stdout"
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "bKuyf8bzFmSR",
- "colab_type": "text"
- },
- "source": [
- "**Note that we import the JAX version of NumPy here**. That's all that you have to do, any numpy functions you will use afterwards will be JAX-accelerated and differentiable.\n",
- "\n",
- "And for the purpose of this tutorial we also define a few plotting functions in the cell bellow, please run it."
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "8yvBIf1mm_h-",
- "colab_type": "code",
- "cellView": "form",
- "colab": {}
- },
- "source": [
- "#@title Defining some plotting functions [run me]\n",
- "\n",
- "import matplotlib.pyplot as plt\n",
- "from matplotlib.patches import Ellipse\n",
- "\n",
- "def plot_contours(fisher, pos, nstd=1., ax=None, **kwargs):\n",
- " \"\"\"\n",
- " Plot 2D parameter contours given a Hessian matrix of the likelihood\n",
- " \"\"\"\n",
- " \n",
- " def eigsorted(cov):\n",
- " vals, vecs = linalg.eigh(cov)\n",
- " order = vals.argsort()[::-1]\n",
- " return vals[order], vecs[:, order]\n",
- "\n",
- " mat = fisher\n",
- " cov = np.linalg.inv(mat)\n",
- " sigma_marg = lambda i: np.sqrt(cov[i, i])\n",
- "\n",
- " if ax is None:\n",
- " ax = plt.gca()\n",
- "\n",
- " vals, vecs = eigsorted(cov)\n",
- " theta = degrees(np.arctan2(*vecs[:, 0][::-1]))\n",
- "\n",
- " # Width and height are \"full\" widths, not radius\n",
- " width, height = 2 * nstd * sqrt(vals)\n",
- " ellip = Ellipse(xy=pos, width=width,\n",
- " height=height, angle=theta, **kwargs)\n",
- "\n",
- " ax.add_artist(ellip)\n",
- " sz = max(width, height)\n",
- " s1 = 1.5*nstd*sigma_marg(0)\n",
- " s2 = 1.5*nstd*sigma_marg(1)\n",
- " ax.set_xlim(pos[0] - s1, pos[0] + s1)\n",
- " ax.set_ylim(pos[1] - s2, pos[1] + s2)\n",
- " plt.draw()\n",
- " return ellip"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "nXjimh6KGFWm",
- "colab_type": "text"
- },
- "source": [
- "## Defining a Cosmology and computing background quantities\n",
- "\n",
- "We'll beginning with the basics, let's define a cosmology:\n"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "R0wxmnuBG9EC",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# Create a cosmology with default parameters\n",
- "cosmo = jc.Planck15()"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "by_0gcYKG9Ag",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# Alternatively we can override some of the defaults\n",
- "cosmo_modified = jc.Planck15(h=0.7)"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "d-VI1BFuI3w1",
- "colab_type": "code",
- "outputId": "8ed049c5-20bc-4874-87a2-db3e4ed49a4e",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "# Parameters can be easily accessed from the cosmology object\n",
- "cosmo.h"
- ],
- "execution_count": 6,
- "outputs": [
- {
- "output_type": "execute_result",
- "data": {
- "text/plain": [
- "0.6774"
- ]
- },
- "metadata": {
- "tags": []
- },
- "execution_count": 6
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "8RhqkfHjHgTT",
- "colab_type": "text"
- },
- "source": [
- "All background quantities can be computed from the `jax_cosmo.background` module, they typically take the cosmology as first argument, and a scale factor\n",
- "argument if they are not constant."
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "bdcm_oReG89o",
- "colab_type": "code",
- "outputId": "07e4ff00-3bfb-4bfd-bc61-70350a062435",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 403
- }
- },
- "source": [
- "# Let's define a range of scale factors\n",
- "a = np.linspace(0.01, 1.)\n",
- "\n",
- "# And compute the comoving distance for these scale factors \n",
- "chi = jc.background.radial_comoving_distance(cosmo, a)\n",
- "\n",
- "# We can now plot the results:\n",
- "plot(a, chi)\n",
- "xlabel(r'scale factor $a$')\n",
- "ylabel(r'radial comoving distance $\\chi$');"
- ],
- "execution_count": 7,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype float64 requested in asarray is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype float64 requested in array is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype requested in astype is not available, and will be truncated to dtype int32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n"
- ],
- "name": "stderr"
- },
- {
- "output_type": "display_data",
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "tags": [],
- "needs_background": "light"
- }
- }
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "z30Karo4Jdnw",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# Not sure what are the units of the comoving distance? just ask:\n",
- "jc.background.radial_comoving_distance?"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "yihFIALbJ24Q",
- "colab_type": "text"
- },
- "source": [
- "## Defining redshift distributions\n",
- "\n",
- "On our path to computing Fisher matrices, we need to be able to express redshift distrbutions. In `jax-cosmo` n(z) are parametrized functions which can\n",
- "be found in the `jax_cosmo.redshift` module. \n",
- "\n",
- "For the purpose of this tutorial, let's see how to define a Smail type distribution:\n",
- "$$ n(z) = z^a \\exp(- (z/z_0)^b) $$\n",
- "which depends on 3 parameters:"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "2D7ouxvVIR7M",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# You can inspect the documentation to see the \n",
- "# meaning of these positional arguments\n",
- "nz1 = jc.redshift.smail_nz(1., 2., 1.)\n",
- "nz2 = jc.redshift.smail_nz(1., 2., 0.5)"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "Ef2oNlQ7Lmdi",
- "colab_type": "code",
- "outputId": "799bb7a6-1e67-45d8-dfd3-ff3b27ce6f81",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 281
- }
- },
- "source": [
- "# And let's plot it\n",
- "z = np.linspace(0,5,256)\n",
- "\n",
- "# Redshift distributions are callable, and they return the normalized distribution\n",
- "plot(z, nz1(z), label='z0=1.')\n",
- "plot(z, nz2(z), label='z0=0.5')\n",
- "legend();\n",
- "xlabel('Redshift $z$');"
- ],
- "execution_count": 10,
- "outputs": [
- {
- "output_type": "display_data",
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "tags": [],
- "needs_background": "light"
- }
- }
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "0eG0GXjCLmhz",
- "colab_type": "code",
- "outputId": "283348ed-0a18-45b4-a584-a58db0a72c39",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "# We can check that the nz is properly normalized\n",
- "jc.scipy.integrate.romb(nz1, 0., 5.)"
- ],
- "execution_count": 11,
- "outputs": [
- {
- "output_type": "execute_result",
- "data": {
- "text/plain": [
- "DeviceArray(1.0000004, dtype=float32)"
- ]
- },
- "metadata": {
- "tags": []
- },
- "execution_count": 11
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "ZUYVlhKkMLpl",
- "colab_type": "text"
- },
- "source": [
- "Nice :-D "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "PGCY4irsNI9B",
- "colab_type": "text"
- },
- "source": [
- "## Defining probes and computing angular $C_\\ell$\n",
- "\n",
- "Let's now move on to define lensing and clustering probes using these two n(z).\n",
- "In `jax-cosmo` a probe/tracer of a given type, i.e. lensing, contains a series of parameters, like redshift distributions, or galaxy bias. Probes are hosted in\n",
- "the `jax_cosmo.probes` module.\n",
- "\n",
- "$C_\\ell$ computations will then take as argument a list of probes and will compute all auto- and cross- correlations between all redshift bins of all probes. "
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "-YUfaBhzNINW",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# First we define a list of redshift bins\n",
- "nzs = [nz1, nz2]"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "R3qUxP9wO6fH",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# And now we define 2 probes \n",
- "probes = [ jc.probes.WeakLensing(nzs, sigma_e=0.26), \n",
- " jc.probes.NumberCounts(nzs, jc.bias.constant_linear_bias(1.)) ]"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "t40aS024QFHx",
- "colab_type": "text"
- },
- "source": [
- "Given these probes, we can now compute tomographic angular power spectra for these probes using the `angular_cl` tools hosted in the `jax_cosmo.angular_cl` module. For now, all computations are done under the Limber approximation."
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "QWedY8i6cFkw",
- "colab_type": "code",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 139
- },
- "outputId": "d8b34187-8daf-4218-84a1-e6093a5868f2"
- },
- "source": [
- "# Let's define a range of \\ell\n",
- "ell = np.logspace(1,3)\n",
- "\n",
- "# And compute the data vector\n",
- "cls = jc.angular_cl.angular_cl(cosmo, ell, probes)"
- ],
- "execution_count": 14,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype float64 requested in asarray is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype float64 requested in array is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype requested in astype is not available, and will be truncated to dtype int32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n"
- ],
- "name": "stderr"
- }
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "VSKlZxxARxYO",
- "colab_type": "code",
- "outputId": "3d39a4d7-165e-428d-d2a8-d482353d2064",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "# Let's check the shape of these Cls\n",
- "cls.shape"
- ],
- "execution_count": 15,
- "outputs": [
- {
- "output_type": "execute_result",
- "data": {
- "text/plain": [
- "(10, 50)"
- ]
- },
- "metadata": {
- "tags": []
- },
- "execution_count": 15
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "X-Vnim-cSQSh",
- "colab_type": "text"
- },
- "source": [
- "We see that we have obtained 10 spectra, each of them of size 50, which is the length of the $\\ell$ vector. They are ordered first by probe, then by redshift bin. So the first cl is the lensing auto-spectrum of the first bin"
- ]
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "-Xc458aidYL8",
- "colab_type": "code",
- "outputId": "960b3f8d-8bb4-4018-f45d-869de305ca19",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 303
- }
- },
- "source": [
- "# This is for instance the first bin auto-spectrum \n",
- "loglog(ell, cls[0])\n",
- "ylabel(r'$C_\\ell$')\n",
- "xlabel(r'$\\ell$');\n",
- "title(r'Angular $C_\\ell$');"
- ],
- "execution_count": 16,
- "outputs": [
- {
- "output_type": "display_data",
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "tags": [],
- "needs_background": "light"
- }
- }
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {
- "id": "Ri-QjcD8UckV",
- "colab_type": "text"
- },
- "source": [
- "In addition to the data vector, we can also compute the covariance matrix using the tools from that module. Here is an example:"
- ]
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "lpIJcb3tcFkC"
+ },
+ "source": [
+ "# Introduction to jax-cosmo\n",
+ "\n",
+ "Authors:\n",
+ " - [@EiffL](https://github.com/EiffL) (Francois Lanusse)\n",
+ "\n",
+ "### Overview\n",
+ "\n",
+ "`jax-cosmo` brings the power of automatic differentiation and XLA execution\n",
+ "to cosmological computations, all the while preserving the readability and human\n",
+ "friendliness of Python / NumPy.\n",
+ "\n",
+ "This is made possible by the [JAX](https://jax.readthedocs.io/en/latest/index.html) framework, which can be summarised as JAX = NumPy + autograd + GPU/TPU. We\n",
+ "encourage the interested reader to follow this [introduction to JAX](https://jax.readthedocs.io/en/latest/notebooks/quickstart.html) but it will not be necessary to follow this notebook.\n",
+ "\n",
+ "\n",
+ "### Learning objectives\n",
+ "\n",
+ "In this short introduction we will cover:\n",
+ " - How to define computations of **2pt functions**\n",
+ " - How to execute these computations on **GPU** (spoiler alert, you actually don't need to do anything, it happens automatically)\n",
+ " - How to **take derivatives** of any quantities by automatic differentation\n",
+ " - And finally, how to piece all of this together for efficient and reliable **Fisher matrices**.\n",
+ "\n",
+ "\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "Dlb7kXPYEf6Z"
+ },
+ "source": [
+ "## Installing and importing jax-cosmo\n",
+ "\n",
+ "One of the important aspects of `jax-cosmo` is that it is entirely Python-based\n",
+ "so it can trivially be installed without compiling or downloading any third-party tools.\n",
+ "\n",
+ "Here is how to install the current release on your system:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 51
},
+ "colab_type": "code",
+ "id": "yZWz-yxPcG6q",
+ "outputId": "b315e257-1cb3-4654-c8ff-2b319ab27b13"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "zIdQSRgkUYC7",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "mu, cov = jc.angular_cl.gaussian_cl_covariance_and_mean(cosmo, ell, probes);"
- ],
- "execution_count": 0,
- "outputs": []
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\u001b[?25l\r",
+ "\u001b[K |█▌ | 10kB 28.3MB/s eta 0:00:01\r",
+ "\u001b[K |███ | 20kB 3.0MB/s eta 0:00:01\r",
+ "\u001b[K |████▍ | 30kB 4.0MB/s eta 0:00:01\r",
+ "\u001b[K |█████▉ | 40kB 4.3MB/s eta 0:00:01\r",
+ "\u001b[K |███████▎ | 51kB 3.5MB/s eta 0:00:01\r",
+ "\u001b[K |████████▊ | 61kB 3.9MB/s eta 0:00:01\r",
+ "\u001b[K |██████████▏ | 71kB 4.3MB/s eta 0:00:01\r",
+ "\u001b[K |███████████▋ | 81kB 4.5MB/s eta 0:00:01\r",
+ "\u001b[K |█████████████ | 92kB 4.9MB/s eta 0:00:01\r",
+ "\u001b[K |██████████████▌ | 102kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |████████████████ | 112kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |█████████████████▌ | 122kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |███████████████████ | 133kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |████████████████████▍ | 143kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |█████████████████████▉ | 153kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |███████████████████████▎ | 163kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |████████████████████████▊ | 174kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |██████████████████████████▏ | 184kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |███████████████████████████▋ | 194kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |█████████████████████████████ | 204kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |██████████████████████████████▌ | 215kB 4.8MB/s eta 0:00:01\r",
+ "\u001b[K |████████████████████████████████| 225kB 4.8MB/s \n",
+ "\u001b[?25h Building wheel for jax-cosmo (setup.py) ... \u001b[?25l\u001b[?25hdone\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Installing jax-cosmo\n",
+ "!pip install --quiet jax-cosmo"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "xvIGKcbXFEFO"
+ },
+ "source": [
+ "For efficient computation on GPU (if you have one), you might want to make sure that JAX itself is installed with the proper GPU-enabled backend. See [here](https://github.com/google/jax#installation) for more instructions.\n",
+ "\n",
+ "Now that `jax-cosmo` is installed, let's import it along with JAX tools:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 34
},
+ "colab_type": "code",
+ "id": "AZkSj6XNcFkE",
+ "outputId": "6a325574-7540-4d62-bbfc-fcfaf00f009d"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "yGd3NelNVZpj",
- "colab_type": "text"
- },
- "source": [
- "The data vector from this function is in a flattened shape so that it can be multiplied by the covariance matrix easily."
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Populating the interactive namespace from numpy and matplotlib\n"
+ ]
+ }
+ ],
+ "source": [
+ "%pylab inline\n",
+ "import jax\n",
+ "import jax_cosmo as jc\n",
+ "import jax.numpy as np"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "bKuyf8bzFmSR"
+ },
+ "source": [
+ "**Note that we import the JAX version of NumPy here**. That's all that you have to do, any numpy functions you will use afterwards will be JAX-accelerated and differentiable.\n",
+ "\n",
+ "And for the purpose of this tutorial we also define a few plotting functions in the cell bellow, please run it."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "cellView": "form",
+ "colab": {},
+ "colab_type": "code",
+ "id": "8yvBIf1mm_h-"
+ },
+ "outputs": [],
+ "source": [
+ "#@title Defining some plotting functions [run me]\n",
+ "\n",
+ "import matplotlib.pyplot as plt\n",
+ "from matplotlib.patches import Ellipse\n",
+ "\n",
+ "def plot_contours(fisher, pos, nstd=1., ax=None, **kwargs):\n",
+ " \"\"\"\n",
+ " Plot 2D parameter contours given a Hessian matrix of the likelihood\n",
+ " \"\"\"\n",
+ " \n",
+ " def eigsorted(cov):\n",
+ " vals, vecs = linalg.eigh(cov)\n",
+ " order = vals.argsort()[::-1]\n",
+ " return vals[order], vecs[:, order]\n",
+ "\n",
+ " mat = fisher\n",
+ " cov = np.linalg.inv(mat)\n",
+ " sigma_marg = lambda i: np.sqrt(cov[i, i])\n",
+ "\n",
+ " if ax is None:\n",
+ " ax = plt.gca()\n",
+ "\n",
+ " vals, vecs = eigsorted(cov)\n",
+ " theta = degrees(np.arctan2(*vecs[:, 0][::-1]))\n",
+ "\n",
+ " # Width and height are \"full\" widths, not radius\n",
+ " width, height = 2 * nstd * sqrt(vals)\n",
+ " ellip = Ellipse(xy=pos, width=width,\n",
+ " height=height, angle=theta, **kwargs)\n",
+ "\n",
+ " ax.add_artist(ellip)\n",
+ " sz = max(width, height)\n",
+ " s1 = 1.5*nstd*sigma_marg(0)\n",
+ " s2 = 1.5*nstd*sigma_marg(1)\n",
+ " ax.set_xlim(pos[0] - s1, pos[0] + s1)\n",
+ " ax.set_ylim(pos[1] - s2, pos[1] + s2)\n",
+ " plt.draw()\n",
+ " return ellip"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "nXjimh6KGFWm"
+ },
+ "source": [
+ "## Defining a Cosmology and computing background quantities\n",
+ "\n",
+ "We'll beginning with the basics, let's define a cosmology:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "R0wxmnuBG9EC"
+ },
+ "outputs": [],
+ "source": [
+ "# Create a cosmology with default parameters\n",
+ "cosmo = jc.Planck15()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "by_0gcYKG9Ag"
+ },
+ "outputs": [],
+ "source": [
+ "# Alternatively we can override some of the defaults\n",
+ "cosmo_modified = jc.Planck15(h=0.7)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 34
},
+ "colab_type": "code",
+ "id": "d-VI1BFuI3w1",
+ "outputId": "8ed049c5-20bc-4874-87a2-db3e4ed49a4e"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "WX5lmHsRVXIh",
- "colab_type": "code",
- "outputId": "64a404cf-9269-4e8b-ff67-3de6eb3ba183",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 265
- }
- },
- "source": [
- "semilogy(mu);"
- ],
- "execution_count": 18,
- "outputs": [
- {
- "output_type": "display_data",
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "tags": [],
- "needs_background": "light"
- }
- }
+ "data": {
+ "text/plain": [
+ "0.6774"
]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Parameters can be easily accessed from the cosmology object\n",
+ "cosmo.h"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "8RhqkfHjHgTT"
+ },
+ "source": [
+ "All background quantities can be computed from the `jax_cosmo.background` module, they typically take the cosmology as first argument, and a scale factor\n",
+ "argument if they are not constant."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 403
},
+ "colab_type": "code",
+ "id": "bdcm_oReG89o",
+ "outputId": "07e4ff00-3bfb-4bfd-bc61-70350a062435"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "KLdw1eSvVXE3",
- "colab_type": "code",
- "outputId": "cc8fc33a-ccb2-47a8-8e3b-cf4fdc4d9eb1",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 595
- }
- },
- "source": [
- "figure(figsize=(10,10))\n",
- "imshow(np.log10(cov+1e-11),cmap='gist_stern');"
- ],
- "execution_count": 19,
- "outputs": [
- {
- "output_type": "display_data",
- "data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkcAAAJCCAYAAADKjmNEAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+j8jraAAAgAElEQVR4nO3df5Ddd33f+9dnd7WWZQH2yhhjC8dxJMo4NBDXVzaE4RIorVW4MZ2huYBU3AypJ7mNnSbpBNLJvUDm/mhyZ0Jq5zYdJnDjxGoJQ5tCaFSGC3ScSYkUQRJ+mAZtKD9ssIW9/iVkeb06n/vHnnU/dR0sy2f3u+fjx2PmOzrnu0fW++vv2d3nfr/fc7bUWgMAwKqZoQcAANhMxBEAQEMcAQA0xBEAQEMcAQA0xBEAQGNd4qiUck0p5S9KKYullHesx78BALAeyqTf56iUMpvky0lem+SOJH+S5M211tsn+g8BAKyD9ThytCfJYq31K7XW5SQfSHLtOvw7AAATN7cO/82Lk3yjuX9Hkqu+218opXibbgDYpGaTnBp6iPVxT631uY9fOdgF2aWU60spR0opR4aaAQB4cqeSLJQuX8P1tSdauR5Hju5M8oLm/s7xuv9GrfW9Sd6bOHIEAJvdUh0NPcKGWY8M/JMku0sp31tKmU/ypiQfWYd/BwBg4iZ+5KjWulJK+akkH8vqacr311q/OOl/BwBgPUz8pfxnNITTagDAxvtMrfXKx6/s8uoqAIAzJY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABriCACgIY4AABri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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "tags": [],
- "needs_background": "light"
- }
- }
- ]
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype float64 requested in asarray is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype float64 requested in array is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype requested in astype is not available, and will be truncated to dtype int32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n"
+ ]
},
{
- "cell_type": "markdown",
- "metadata": {
- "id": "hN5jA8ogp7Bb",
- "colab_type": "text"
- },
- "source": [
- "## Where the wild things are: Automatic Differentiation\n",
- "\n",
- "Now that we know how to compute various quantities, we can move on to the amazing part, computing gradients automatically by autodiff. As an example, we\n",
- "will demonstrate how to analytically **compute Fisher matrices, without finite differences.** But gradients are usefull for a wide range of other applications.\n",
- "\n",
- "\n",
- "We begin by defining a Gaussian likelihood function for the data vector we have \n",
- "obtained at the previous step. And we make this likelihood function depend on an array of parameters, `Omega_c`, `sigma_8`.\n",
- " \n",
- "\n"
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY8AAAEICAYAAACnL3iHAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy86wFpkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAs5UlEQVR4nO3dd3xV9f3H8dcng7ADIWEGCMhGQCBMwYUD966jVrS21FX1p7W1vy5tbdWfVltbrbXurbUOxFVEUZEhe0/ZEGbYECDJ5/fHPWhqg+SYe3Nzc9/Px+M+7j3nnvE5BvPJd5u7IyIiEkZKvAMQEZHEo+QhIiKhKXmIiEhoSh4iIhKakoeIiISWFu8AqkJ2drbn5eXFOwwRkYQybdq0ze6eU953SZE88vLymDp1arzDEBFJKGa28lDfqdpKRERCU/IQEZHQlDxERCQ0JQ8REQlNyUNEREJT8hARkdCUPEREJDQlj2+wbtte7npnARt3FsU7FBGRakXJ4xvs3lfM3z9Zxrtz1sc7FBGRakXJ4xt0bNaALs0b8NasdfEORUSkWlHyOIwze7Vk6sqtrN22N96hiIhUG0oeh3FGzxYAvD1bpQ8RkYOUPA6jbZN69MrN5K1ZBfEORUSk2lDyqIAze7VkztrtLN+8O96hiIhUC0oeFXB6UHU1Wg3nIiKAkkeFtMisQ/+8LN5Su4eICKDkUWFn9mrB4g27WLR+Z7xDERGJOyWPCjq1RwtSDI35EBFByaPCsutncHSHbN6avQ53j3c4IiJxpeQRwpk9W7Jyyx7mrN0e71BEROJKySOEU7o3Jz3VVHUlIklPySOEzLrpHNsph9GzCygtVdWViCSvKk0eZvY/ZjbPzOaa2YtmVtvM2pnZZDNbamYvm1mt4NiMYHtp8H1emev8PNi/yMxOqcpnOLNXSwq2FzFt1daqvK2ISLVSZcnDzFoBNwD57n4kkApcDNwDPODuHYCtwFXBKVcBW4P9DwTHYWbdgvO6A8OBh80staqe48SuzaidnqKqKxFJalVdbZUG1DGzNKAuUACcALwafP80cE7w+exgm+D7YWZmwf6X3H2fuy8HlgL9qyZ8qJeRxrAuzXhnTgHFJaVVdVsRkWqlypKHu68F7gNWEUka24FpwDZ3Lw4OWwO0Cj63AlYH5xYHxzcpu7+cc75kZiPNbKqZTd20aVNUn+XMXi3YvGs/k5YVRvW6IiKJoiqrrRoTKTW0A1oC9YhUO8WEuz/q7vnunp+TkxPVax/XuSkNa6fx9MQVUb2uiEiiqMpqqxOB5e6+yd0PAK8BRwONgmosgFxgbfB5LdAaIPg+E9hSdn8551SJ2umpXDWkPWPmb2CuxnyISBKqyuSxChhoZnWDtothwHzgI+CC4JgRwJvB51HBNsH3H3pkaPco4OKgN1Y7oCPweRU9w5euODqPhrXT+PPYJVV9axGRuKvKNo/JRBq+pwNzgns/CvwMuNnMlhJp03g8OOVxoEmw/2bgtuA684BXiCSe94Dr3L2kqp7joMw66Sp9iEjSsmSYpyk/P9+nTp0a9etu33uAofd8yID2TfjH5flRv76ISDyZ2TR3L/eXm0aYV4JKHyKSrJQ8KkltHyKSjJQ8KkmlDxFJRkoeUaDSh4gkGyWPKFDpQ0SSjZJHlKj0ISLJRMkjSlT6EJFkouQRRQdLH/f9e5HWOReRGk3JI4oy66Rzw7COjFu0iffnbYh3OCIiMaPkEWVXDM6jS/MG3PHWPHbtKz78CSIiCajCyePg8rDyzdJSU/j9uT0o2F7En8Ysjnc4IiIxEabkMcnMesQskhqkb9vGXNK/NU9OWMH8dTviHY6ISNSFSR4/Ap43s598/Qszey96IdUMPxvehcw66fzijTmUlqrxXERqlgonD3efAgwA+pjZWDO71sz+bmYHp1eXMhrVrcUvTuvKjFXbeGnK6sOfICKSQMK0edwJzAV6AhuAXxEsJevuJ8cmvMR2Xp9WDGiXxT3vLWTzrn3xDkdEJGrClBiuAPq5+5HufimRJNIAuM/MGsYiuERnZvz+3CPZs7+YP7yzIN7hiIhETZjk0cndCw9uBGuRnw2MAyZFO7CaokPTBvxwaHtem76WiV9siXc4IiJREabNY88h9v8dOCtqEdVAPz6hI7mN6/CLN+awd3+Vr5grIhJ1UWnodvel0bhOTVWnVip3ndeDZZt2q/pKRGoE9ZKqIkM75nDVkHY8O2klYxdo6hIRSWxKHlXop8M706V5A259dTYbdxbFOxwRkW8tTFddM7PLzOzXwXYbM+sfu9Bqnoy0VP5ySW927yvmJ/+crcGDIpKwwpQ8HgYGAZcE2zuBh6IeUQ3XsVkDfnl6Vz5ZvImnJ66IdzgiIt9KmOQxwN2vA4oA3H0roMkSv4XLBrZlWJem3PXuQhau19xXIpJ4wiSPA2aWCjiAmeUApTGJqoYzM+65oCcNa6dz44szKTqg7rsikljCJI8HgdeBpmb2e2A8cFdMokoC2fUzuO/CnizasJO7310Y73BEREJJq+iB7v68mU0DhgEGnOPuGrRQCcd1bsoVg/N4asIKBrbPYviRLeIdkohIhYTpbfU0sN7dH3L3vwLrzeyJ2IWWHH5+WheOat2IW16ZxZINO+MdjohIhYSpturp7tsObgQN5r2jHlGSyUhL5ZHL+lKnVhojn53G9r0H4h2SiMhhhUkeKWbW+OCGmWURotpLDq15Zm0e/m4fVhfu4X9enqnxHyJS7YVJHn8EJprZ78zsd8AE4P9iE1by6d8ui1+f2Y0PF27kT2OXxDscEZFvFKbB/BkzmwqcEOw6z93nxyas5PS9gW2ZvWY7D45dwpEtG3Jy9+bxDklEpFyhqp2CZKGEESNmxp3nHMniDTu5+ZVZvHFdfTo0rR/vsERE/kuY3lYZZnapmf2vmf364CuWwSWj2umRBvSMtBRGPjuVHUVqQBeR6idMm8ebwNlAMbC7zEuirGWjOjz03T6s2rKHa5+bzoESDeQXkeolTLVVrrsPj1kk8h8Gtm/CH87rwU9fnc3PX5vDvRf0xMziHZaICBCu5DHBzHpU5mZm1sjMXjWzhWa2wMwGmVmWmY0xsyXBe+PgWDOzB81sqZnNNrM+Za4zIjh+iZmNqExM1dl38ltz47COvDptDQ+O1WKNIlJ9hEkeQ4BpZrYo+GU+x8xmh7zfn4H33L0L0AtYANwGjHX3jsDYYBvgVKBj8BoJ/A2+HF/yG2AA0B/4TdnxJzXNTSd25Pw+uTzwwWJenbYm3uGIiADhqq1OrcyNzCwTOAa4AsDd9wP7zexs4LjgsKeBccDPiLSvPOPuDkwKSi0tgmPHuHthcN0xwHDgxcrEV12ZGXed14MNO4q47V+zad6wNkM6Zsc7LBFJchUuebj7SmAH0AxoW+ZVUe2ATcCTZjbDzB4zs3pAM3cvCI5ZH1wfoBWwusz5a4J9h9r/H8xspJlNNbOpmzZtChFm9VMrLYWHL+tDh6b1ufq5aSwo0BogIhJfYbrq/gD4BHgfuCN4vz3EvdKAPsDf3L03kZ5at5U9IChlRGVuDnd/1N3z3T0/JycnGpeMq4a103nyyn7Uz0jjyienULB9b7xDEpEkFqbN40agH7DS3Y8nMinithDnrwHWuPvkYPtVIslkQ1AdRfC+Mfh+LdC6zPm5wb5D7a/xWmTW4ckr+7FrXzGXP/45hbv3xzskEUlSYZJHkbsXQWTAoLsvBDpX9GR3Xw+sNrOD5wwjMlp9FHCwx9QIIuNJCPZfHvS6GghsD6q33gdONrPGQUP5ycG+pNC1RUMeG5HPqsI9XP7EZA0iFJG4CJM81phZI+ANYIyZvQmsDHm/HwPPB720jgL+ANwNnGRmS4ATg22Ad4BlwFLgH8C1AEFD+e+AKcHrtwcbz5PFwPZNeOR7fVm0fifff3IKe/YXxzskEUkyFmlmCHmS2bFAJvCuu1f7P33z8/N96tSp8Q4j6t6ZU8D1L0zn6A7ZPDYin4y01HiHJCI1iJlNc/f88r4L02B+z8HP7v6xu48C7oxCfPItndajBfec35NPl2zmhhdnUKxpTESkioSptjqpnH2VGvshlXdhfmtuP7Mb78/bwK2vztZCUiJSJQ47SNDMriHS3nBEmRHlBjQAPothbFJBVxzdjt37S7j3/UXUqZXKnWcfSUqK5sESkdipyAjzF4B3gbv4z3EZO5Otobo6u+74DuzZX8xDH32BO/z+HCUQEYmdwyYPd98ObDez14BCd99pZr8E+pjZ79x9RsyjlAr5ycmdMYy/frSU0lLnrvN6KIGISEyEmdvqV+7+TzMbQqRL7b3AI0QmKJRqwMy45eROpKQYD45dQok795zfk1QlEBGJsjDJoyR4Px141N3fNjP1tqpmzIybT+pEqhkPfLCY0lLn3gt7KYGISFSFSR5rzezvRHpd3WNmGYTrrSVV6MYTO5KaAvf9ezEl7vzxwl6kperHJSLRESZ5fIfI1Of3ufu2YB6qW2MTlkTD9Sd0JCXF+L/3FlFc6vzpoqNIVwIRkSiocPJw9z3Aa2W2C4CCQ58h1cG1x3UgLcX4wzsL2bOvmIe/25c6tTQSXUQq57B/hprZ+OB9p5nt+Pp77EOUyhp5zBH84dwejFu8icufmMz2vdV+RhkRqeYOmzzcfUjw3sDdG379PfYhSjRcOqANf7mkNzNXb+OSRyexaee+eIckIgmsIiPMb/6m7939/uiFI7F0Rs+WNKidztXPTuPCRybw7FUDaJ1VN95hiUgCqkjraYPglQ9cw1dLwV5NZDEnSSDHdsrhuR8MoHD3fi58ZCJLNuyMd0gikoAqUm11h7vfQWTFvj7ufou73wL0BdrEOkCJvr5tG/PK1YMocefCv09k2sqt8Q5JRBJMmH6bzYCy657uD/ZJAurSvCH/unowjeqkc+k/JvHe3PXxDklEEkiY5PEM8LmZ3W5mtwOTgadiEZRUjTZN6vKvawbTrWVDrnl+Gk9+tjzeIYlIgqhw8nD33wNXAluD15XuflesApOq0aR+Bi/8YCAndW3GHW/N587R87UmiIgcVpgR5rj7dGB6jGKROKlTK5W/XdaX342ez2Pjl1OwvYg/fqcXtdM1mFBEyhcqeUjNlZpi/ObMbuQ2rsOdby9gw44i/nF5Po3r1Yp3aCJSDWmiI/mSmfGDoe156NI+zF67nXMe/oylG9WVV0T+m5KH/JfTe7bgxR8OZPe+Ys59aAIfL94U75BEpJox94o1jh5ipPl2YJq7z4xmUNGWn5/vU6dOjXcYCWfN1j384OmpLN6wk1+f0Y0Rg/Mw07ogIsnCzKa5e35534UpeeQTGVV+cIT5j4hM0f4PM/tppaOUaie3caQr7wldmnH7W/P55RtzOVBSGu+wRKQaCJM8yhth3hQ4BrgiBrFJNVAvI41Hv9eXq489gucnr2LEE5+zbc/+w58oIjVamOTRFCg7FesBoJm77/3afqlhUlKM207twn0X9mLqiq2c9dfPWLhes/GLJLMwyeN5YLKZ/SYYYT4BeMHM6gHzYxGcVC8X9M3lxZEDKTpQwrkPTWD07HXxDklE4qTCDeYAZpYPHA04MMHdE6IVWg3m0bVxRxHXPD+daSu38qNj2nPrKZ21PrpIDRSVBnMzywA6AfWARsBpZvbrqEQoCaVpw9q8+MOBXDawDX//ZBlXPDmFrbvVDiKSTML8ufgmcDZQDOwu85IkVCsthTvP6cE95/fg8+WFnPnX8cxduz3eYYlIFQkzPUmuuw+PWSSSkC7q14bOzRty9bPTOP9vE/jt2d35Tn5rjQcRqeHClDwmmFmPmEUiCeuo1o0YfcMQ+uVl8bN/zeEn/5zN3v0l8Q5LRGIoTPIYAkwzs0VmNtvM5pjZ7FgFJoklu34GT3+/PzcM68hrM9ZwzkOf8cWmXfEOS0RiJMz0JG3L2+/uK6MaUQyot1XV+mTxJm56eSb7DpRw9/k9ObNXy3iHJCLfQlR6W7n7yvJe0QtTaopjOuXw9g1D6NKiIT9+cQa/fnMuRQdUjSVSkxw2eZjZ+OB9p5ntKPPaaWYaZizlapFZh5dGDuQHQ9rxzMSVnPfwBFVjidQgh00e7j4keG/g7g3LvBq4e8OwNzSzVDObYWajg+12ZjbZzJaa2ctmVivYnxFsLw2+zytzjZ8H+xeZ2SlhY5CqkZ6awi/P6MbjI/Ip2L6XMx4czytTVxNmYKqIVE9hBgnebGbRqLy+EVhQZvse4AF370BkbfSrgv1XAVuD/Q8Ex2Fm3YCLge5EZvV92My0Xmo1NqxrM9698Rh6tc7kp6/O5saXZrKz6EC8wxKRSgjT26oBMMbMPjWz682sWdibmVkucDrwWLBtwAnAq8EhTwPnBJ/PDrYJvh8WHH828JK773P35cBSoH/YWKRqNc+szfM/GMgtJ3Vi9Ox1nP7geGau3hbvsETkWwrTYH6Hu3cHrgNaAB+b2Qch7/cn4KfAwUUhmgDb3L042F5DZK0QgvfVwb2LiSw81aTs/nLO+ZKZjTSzqWY2ddMmrYRXHaSmGD8e1pFXfjSIklLngr9N4KGPllJSqmoskUTzbWaz2wisB7YQmaa9QszsDGCju0/7FvcMzd0fdfd8d8/PycmpiltKBeXnZfHODUM5uXsz7n1/ERc/OpHVhXviHZaIhBCmzeNaMxsHjCVSAvihu/cMca+jgbPMbAXwEpHqqj8Djczs4DQpucDa4PNaoHVw7zQgk0jC+nJ/OedIgsism85Dl/bhjxf2YkHBTk7986e8Nn2NGtNFEkSYkkdr4CZ37+7ut7t7qDU83P3n7p7r7nlEGrw/dPfvAh8BFwSHjSAyASPAqGCb4PsPPfKbZRRwcdAbqx3QEfg8TCxSPZgZ5/fN5d0bh9K1RQNufmUW1784QysViiSAMG0ePwc8aCy/3sx6RSmGnwE3m9lSIiWax4P9jwNNgv03A7cFccwDXiGyANV7wHXurhFoCax1Vl1eGjmInw7vzPtz1zP8T5/y6RK1U4lUZ2GmJ7kBGAm8Fuw6F3jU3f8So9iiRtOTJI45a7Zz08sz+GLTbi4d0Ib/Pa0r9TPCTP4sItHyTdOThEkes4FB7r472K4HTAzZ7hEXSh6JpehACX/89yIeG7+cVo3qcO8FvRh0RJN4hyWSdKIytxVgQNnqoZJgn0hU1U5P5Rend+OVHw0iNcW45B+TuH3UPE3zLlKNhEkeTwKTzex2M7sDmAw8EZuwRKBfXhbv3jiUEYPa8tSEFZz24KdMXVEY77BEhBDVVgBm1odIl1uAT919ZiyCijZVWyW+CV9s5tZ/zmbd9r2MGJTHrad0pp7aQkRiKlptHvnAL4A8vlq+1tXmIVVl175i7n1vIc9MWknLzDrcdV4PjumkAaAisRKt5LEIuBWYw1fTi2gxKKlyU1YU8rN/zWbZpt1c0DeXX53ejcy66fEOS6TGiVaD+SZ3H+Xuy7UYlMRTv2B6k2uPO4LXZ6zlxAc+5r25BfEOSySphCl5DAMuITI9yb6D+939tUOeVE2o5FFzzV27nZ++Opv5BTs4qVsz7jirOy0b1Yl3WCI1QrSqrZ4DugDz+Krayt39+1GJMoaUPGq2AyWlPDF+OQ98sJhUM245uTMjBueRmqKe5CKVEbU2D3fvHNXIqoiSR3JYXbiHX74xl48Xb6JnbiZ/OLcHR7bKjHdYIgkrWm0eE4JV/ESqpdZZdXnqyn785ZLerNtWxFl/Hc+do+eze1/x4U8WkVDCdJQfCMw0s+VE2jyMBOmqK8nDzDizV0uO6ZjD3e8t5LHxyxk9u4BfndGN03o0J7IYpYhUVphqq7bl7U+EHleqtkpe01dt5VdvzGXeuh0M7ZjNHWd1p31O/XiHJZIQotLmkciUPJJbSanz3KSV3PfvRew7UMrIY9pz3fEdqFMrNd6hiVRr0WrzwMx6xWA9D5GYSk0xRgzO48NbjuOMni3460dLOfH+j3lv7nqtXCjyLYVZhvZG4Hki65Y3BZ4zsx/HKjCRaMtpkMH9Fx3FyyMHUj8jjaufm8Zlj09m8Yad8Q5NJOFoPQ9JSsUlpTw/eRX3j1nMrn3FXD6oLTed2InMOprmROQgrech8jVpqSmMGJzHRz85jov7teapCSs4/r5xvDB5FSWlqsoSOZxvu57H7cAktJ6HJLiserX4/bk9GP3jIXTIqc//vj6HM/8ynglfbI53aCLV2rdZz2NIsPmpu8+ISVRRpmorqQh3563ZBdzz7kLWbtvLiV2b8YvTu9Iuu168QxOJi2hNT/I0cKO7bwu2GwN/1NxWUtMUHSjh8fHLefijpewrLuXyQXncOKyjpn2XpBOtNo+eBxMHgLtvBXpXMjaRaqd2eirXHd+Bcbcez4X5uTw1YTnH3vcRT4xfzv7i0sNfQCQJhEkeKUFpAwAzyyLc9CYiCSWnQQZ3ndeTt28YSveWDfnt6PmceP/HjJ69TuNDJOmFSR5/BCaa2e/M7HfABOD/YhOWSPXRtUVDnrtqAE9d2Y+6tVK5/oUZnPPQZ0xatiXeoYnETdgG827ACcHmh+4+PyZRRZnaPCRaSkqd16av4f4xiynYXsSwLk352ald6NSsQbxDE4k6zW2l5CFRVnSghCc/W8HDHy1l9/5izundiv85sROts+rGOzSRqFHyUPKQGCncvZ+/jVvK0xNX4u5c2r8N15/QkZwGGfEOTaTSlDyUPCTGCrbv5cGxS3hl6hpqpabw/SF5jDzmCE13IglNyUPJQ6rIsk27eOCDJbw1ax2ZddIZeUx7rhicR70MdUyUxFOp5GFmO4HyDjq4kmDDyocYW0oeUtXmrdvO/f9ezNiFG8mqV4urj23P9wbmaQ0RSSgqeSh5SJzMWLWV+8cs5tMlm8lpkMG1xx3BJf3bUDtdSUSqv6glj2CQYEeg9sF97v5JpSOMMSUPibfPlxdy/5hFTFpWSPOGtbn2+CP4Tn5rJRGp1qI1t9UPgBuBXGAmMJDIeh4nfNN51YGSh1QXE5Zu5v4xi5m6citNG2Rw9bFHcOkAlUSkeorW3FY3Av2Ale5+PJF5rbZVPjyR5DG4Qzb/vHoQL/xwAO2y6/Hb0fMZcs9HPPbpMvbsL453eCIVFqYLSJG7F5kZZpbh7gvNrHPMIhOpocyMwUdkM/iIbCYt28JfPlzCnW8v4G/jvuCqoe343sC2NKitLr5SvYVJHmvMrBHwBjDGzLYCK2MRlEiyGNi+CQPbN2HqikIe/HAp//feIh4Z9wUjBudx5dHtyKpXK94hipTrW/W2MrNjgUzgPXffX8FzWgPPAM2IdP191N3/HMzO+zKQB6wAvuPuW83MgD8DpwF7gCvcfXpwrRHAL4NL3+nuT3/TvdXmIYli9pptPPzRF7w3bz110lO5dEAbfji0Pc0zax/+ZJEoqxZddc2sBdDC3aebWQNgGnAOcAVQ6O53m9ltQGN3/5mZnQb8mEjyGAD82d0HBMlmKpBPJAlNA/oG64uUS8lDEs2SDTv527gveHPWOlLNOL9vK344tD3tc+rHOzRJIpVqMDez8cH7TjPb8fX3igbh7gUHSw7uvhNYALQCzgYOlhyeJpJQCPY/4xGTgEZBAjoFGOPuhUHCGAMMr2gcIomgY7MG3H/RUYz7yXFcmJ/Lv6avZdj9H/OjZ6cyfdUh/04SqTKHbfNw9yHBe9TmnDazPCK9tSYDzdy9IPhqPZFqLYgkltVlTlsT7DvUfpEap3VWXX5/bg9uOrETz0xcwTMTV/L+vA30z8viR8e25/jOTUlJsXiHKUnosMnDzG7+pu/d/f4wNzSz+sC/gJvcfUekaePLa7mZRaUezcxGAiMB2rRpE41LisRNToMMbjm5M1cfewQvT1nN4+OXc9XTU+nYtD5XDWnHOb1baayIVKmKjPNoELzygWv46q//q4E+YW5mZulEEsfz7v5asHtDUB11sF1kY7B/LdC6zOm5wb5D7f8P7v6ou+e7e35OTk6YMEWqrXoZaXx/SDvG3XocD1zUi/TUFG57bQ5H3/0hf/pgMZt37Yt3iJIkwoww/wQ4PWivIGj0ftvdj6ng+UakTaPQ3W8qs/9eYEuZBvMsd/+pmZ0OXM9XDeYPunv/oMF8Gl8lrulEGswLD3VvNZhLTeXuTFy2hcc/Xc7YhRuplZbCeb1bcdWQdnTU6oZSSd/UYB5mnEczoGy33P181T5REUcD3wPmmNnMYN//AncDr5jZVUTGjXwn+O4dIoljKZGuulcCuHthsIb6lOC4335T4hCpycoOOFy6cRdPfLacf01bw0tTVjO0YzZXHp3HcZ3ULiLRF6bk8Qsiv9hfD3adA7zi7n+ITWjRo5KHJJPC3ft5YfJKnp20kg079tEuux4jBrXlgvzW1Ne6IhJCNGfV7QMMDTY/cfcZUYgv5pQ8JBkdKCnlnTkFPDVhBTNWbaN+RhoX5ucyYlAeedn14h2eJABNya7kIUlu5uptPPXZct6eU8CBEueYTjlcPrAtx3dpSqqqtOQQNCW7kocIABt3FPHi56t54fNIlVarRnX47sA2XJTfmib1M+IdnlQz0Uoec4hMyT7J3Y8ysy7AH9z9vOiFGhtKHiL/6UBJKR/M38AzE1cycdkWaqWlcHqPFlw6oA35bRtTdvyVJK9o9bbSlOwiNUR6agqn9mjBqT1asGTDTp6dtJLXp6/l9Rlr6dSsPpf2b8O5fXLJrKOp4aV8YUoerxPpLnsTcAKwFUh399NiFl2UqOQhcnh79hfz1qx1vDB5FbPWbKd2egpn9GzJpQPa0Lt1I5VGklClq62CAX657r462A49JXs8KXmIhDN37XZe+HwVb85Yy+79JXRqVp+L+rXh3N6ttMZIEolam4e794hqZFVEyUPk29m1r5jRs9bx0pTVzFy9jVqpKZzcvRkX92vD4COaaPBhDRetNo/pZtbP3acc/lARqQnqZ6Rxcf82XNy/DQvX7+Clz1fz+oy1jJ5dQG7jOpzfJ5cL+ubSOqtuvEOVKham5LEQ6EBkCpHdgBGZCLdn7MKLDpU8RKKn6EAJ/56/gVemrOazLzbjDoPaN+GCvrmc2qM5dWtpFHtNEa1qq7bl7Xf3ar+OuZKHSGys3baX16at4dXpa1i5ZQ/1M9I4vUcLzu+bS37bxqrWSnDVYhnaeFLyEIktd+fz5YW8Om0Nb88pYM/+EnIb1+G83q04t08u7TQdSkJS8lDyEKkye/YX8/689bw2fS2fLd1MqUPvNo04r08uZ/RoQWP11koYSh5KHiJxsX57EW/OXMtr09eyaMNO0lKMYzvlcHbvVpzYtanaR6o5JQ8lD5G4cnfmF+xg1Mx1jJq1joLtRdStlcop3Ztz1lEtGdIhm/TUiixsKlVJyUPJQ6TaKC11Pl9RyJsz1/L27AJ2FBXTuG46p/ZowZk9W9K/XZZm+q0mlDyUPESqpX3FJXy8aBNvzS7gg/kb2HughJwGGZzeowVn9mpB79bqsRVPSh5KHiLV3p79xXy4cCOjZxXw4aKN7C8upWVmbU7t0YLTerSgd+tGSiRVTMlDyUMkoewsOsCY+Rt4Z04BnyzezP6SUlpk1mb4kc05vUcL+rRRiaQqKHkoeYgkrB1FBxi7YANvz17PJ0s2sb+4lGYNMzile3OGd29O/3ZZpKmxPSaUPJQ8RGqEnUUH+HDhRt6ZU8DHizdRdKCUxnXTObFrM4Yf2ZyjO2RTOz013mHWGEoeSh4iNc7e/SV8vHgT789bzwcLNrCzqJh6tVI5tnMOJ3Vrxgmdm5FZV4tZVUa0ZtUVEak26tRKZfiRzRl+ZHP2F5cycdkW3psbSSTvzFlPaorRPy+Lk7s346RuzchtrJl/o0klDxGpUUpLnVlrtjFm/gbGzN/Ako27AOjSvAHDujZlWNdmHJWrnlsVoWorJQ+RpLV8827GzF/PBws2Mm3lVkpKnez6tTi+c1OGdW3K0I451MtQJUx5lDyUPEQE2LZnPx8v3sTYBRsZt2gjO4qKqZWaQv92WRzXOYfjuzSlfXY9rdceUPJQ8hCRrzlQUsrUFVsZt2gjHy3ayOINkeqtNll1Ob5zDsd1acrAdk2oUyt5e28peSh5iMhhrC7cw7jFmxi3cCOffbGZogOl1EpLYUC7LI7tlMNxnXM4Iqd+UpVKlDyUPEQkhKIDJUxeXsgnizfx8eJNLA0a3Vs1qsMxnbIZ2jGHo4/IrvFdgZU8lDxEpBLWbtsbSSSLNvHZ0s3s3FdMikHP3EYM7RhJJr3bNKpx08oreSh5iEiUFJeUMmvNNj5ZvJlPl2xi5uptlDrUq5XKgPZNOLpDNkd3aELnZg0SvopLyUPJQ0RiZPveA0z8YgufLtnEhC+2sHzzbgCy62cw+IgmDOmQzeAOTRJykKJGmIuIxEhmnfQvR7pDpIrrs6WbmbB0M+OXbmHUrHUA5Dauw6D2TRjcoQmD2mfTPLN2PMOuNJU8RERixN1ZsnEXE5ZuZuKyLUxeXsi2PQcAaJddj4HtsxjQrgkD2mfRIrNOnKP9b6q2UvIQkWqgtNRZsH4HE7/YwqQgmewsKgYi40sGtMtiQPsmDGiXRW7jOnFvM1HyUPIQkWqopNRZULCDycsLmbxsC5+v+Kpk0iKzNv3ysujXLov+eVl0bFq/yufjUvJQ8hCRBFBa6izeuJPJywr5fEUhU5YXsnHnPgAa1U0nv21j8vOyyG/bmB65mWSkxXb0e41sMDez4cCfgVTgMXe/O84hiYhUSkqK0aV5Q7o0b8iIwXm4O6sK9zBlxVamLC9kyopCPliwEYBaaSn0bJVJ37zG9GubRZ+2jcmqV6vKYk3IkoeZpQKLgZOANcAU4BJ3n1/e8Sp5iEhNsXnXPqat3Mq0lVuZsqKQuWu3c6Ak8nu8fXY9+rRtTN+2jenTpnGlq7pqYsmjP7DU3ZcBmNlLwNlAuclDRKSmyK4fWb/9lO6RrsFFB0qYvWb7lwnlo4UbeXXaGgAa1E7jovzW/PKMblGPI1GTRytgdZntNcCAsgeY2UhgJECbNm2qLjIRkSpUOz2V/u2y6N8uC4h0D165ZU8kmazaSstGsekCnKjJ47Dc/VHgUYhUW8U5HBGRKmFm5GXXIy+7Huf3zY3ZfRJ1Fq+1QOsy27nBPhERqQKJmjymAB3NrJ2Z1QIuBkbFOSYRkaSRkNVW7l5sZtcD7xPpqvuEu8+Lc1giIkkjIZMHgLu/A7wT7zhERJJRolZbiYhIHCl5iIhIaEoeIiISmpKHiIiElpBzW4VlZpuAlSFOyQY2xyic6iwZnzsZnxmS87mT8Zmhcs/d1t1zyvsiKZJHWGY29VCTgdVkyfjcyfjMkJzPnYzPDLF7blVbiYhIaEoeIiISmpJH+R6NdwBxkozPnYzPDMn53Mn4zBCj51abh4iIhKaSh4iIhKbkISIioSV18jCz4Wa2yMyWmtlt5XyfYWYvB99PNrO8OIQZdRV47pvNbL6ZzTazsWbWNh5xRtPhnrnMceebmZtZjejSWZHnNrPvBD/veWb2QlXHGG0V+Pfdxsw+MrMZwb/x0+IRZzSZ2RNmttHM5h7iezOzB4P/JrPNrE+lb+ruSfkiMpX7F0B7oBYwC+j2tWOuBR4JPl8MvBzvuKvouY8H6gafr0n0567IMwfHNQA+ASYB+fGOu4p+1h2BGUDjYLtpvOOugmd+FLgm+NwNWBHvuKPw3McAfYC5h/j+NOBdwICBwOTK3jOZSx79gaXuvszd9wMvAWd/7ZizgaeDz68Cw8zMqjDGWDjsc7v7R+6+J9icRGSlxkRWkZ81wO+Ae4Ciqgwuhiry3D8EHnL3rQDuvrGKY4y2ijyzAw2Dz5nAuiqMLybc/ROg8BsOORt4xiMmAY3MrEVl7pnMyaMVsLrM9ppgX7nHuHsxsB1oUiXRxU5Fnrusq4j8xZLIDvvMQTG+tbu/XZWBxVhFftadgE5m9pmZTTKz4VUWXWxU5JlvBy4zszVE1gT6cdWEFldh/78/rIRdDEpiz8wuA/KBY+MdSyyZWQpwP3BFnEOJhzQiVVfHESlhfmJmPdx9WzyDirFLgKfc/Y9mNgh41syOdPfSeAeWSJK55LEWaF1mOzfYV+4xZpZGpIi7pUqii52KPDdmdiLwC+Asd99XRbHFyuGeuQFwJDDOzFYQqRMeVQMazSvys14DjHL3A+6+HFhMJJkkqoo881XAKwDuPhGoTWTywJqsQv/fh5HMyWMK0NHM2plZLSIN4qO+dswoYETw+QLgQw9anxLYYZ/bzHoDfyeSOBK9DhwO88zuvt3ds909z93ziLTznOXuU+MTbtRU5N/4G0RKHZhZNpFqrGVVGGO0VeSZVwHDAMysK5HksalKo6x6o4DLg15XA4Ht7l5QmQsmbbWVuxeb2fXA+0R6aDzh7vPM7LfAVHcfBTxOpEi7lEhj1MXxizg6Kvjc9wL1gX8G/QNWuftZcQu6kir4zDVOBZ/7feBkM5sPlAC3unvClq4r+My3AP8ws/8h0nh+RaL/UWhmLxL5IyA7aMv5DZAO4O6PEGnbOQ1YCuwBrqz0PRP8v5mIiMRBMldbiYjIt6TkISIioSl5iIhIaEoeIiISmpKHiIiEpuQhIiKhKXmIiEhoSh4ilWBmu0Ief4OZLTCz57/FvRqZ2bVhzxOJBQ0SFKkEM9vl7vVDHL8QONHd13yLe+UBo939yBDnGJH/zzXpn0SVSh6StMysnpm9bWazzGyumV0U7L88WG1tlpk9G+x7w8ymBavtjTzE9S4zs8/NbKaZ/d3MUr/2/SNEFil6N5ga45DXLS8G4G7giOD69wbH3RzEPtfMbgr25QUr6T0DzOU/J8TDzC4Ipl+fZWbjzSyn0v8xJfnEewUsvfSK1ws4H/hHme1MoDuRmWWzg31ZX3uvQ+QXcpNge1fw3hV4C0gPth8GLi/nnisOXvtQ1/2GGPIos1Ic0BeYA9QjMhfZPKB3cFwpMPAQz92kzOffANfF+2ehV+K9VPKQZDYHOMnM7jGzoe6+HTgB+Ke7bwZw94Ors91gZrOIzLjbmv+etnwYkV/mU8xsZrDdvgIxlHfdQ8XwdUOA1919t7vvAl4DhgbfrfTIinHluSIoIc0istRyTVk5UapQ0s6qK+Lui4MVBE8D7jSzscDWrx9nZscBJwKD3H2PmY0jMo33fxwGPO3uP6/o/St43W9r9yHueTmRpVpPcPddZvYJkRKLSCgqeUjSMrOWwB53f47INPR9gA+BC82sSXBMFpHqrK3BL/guRBaL+rqxwAVm1vTgeWbW9jAhHOq65cUAsJPIwlUHfQqcY2Z1zawecG6w75v0ACYEieN8YDCREphIKCp5SDLrAdxrZqXAAeAaj6z98HvgYzMrAWYAPwKuNrMFwCIiVUz/wd3nm9kvgX9bZFnbA8B1wMpvuP975V33EDFc4e5bLLLW+FzgXXe/1cyeAj4PrveYu88IemUdylPAa2b2XeDfwDJ3L7eUIvJN1FVXRERCU7WViIiEpuQhIiKhKXmIiEhoSh4iIhKakoeIiISm5CEiIqEpeYiISGj/DwsR8lHoDLKvAAAAAElFTkSuQmCC\n",
+ "text/plain": [
+ ""
]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Let's define a range of scale factors\n",
+ "a = np.linspace(0.01, 1.)\n",
+ "\n",
+ "# And compute the comoving distance for these scale factors \n",
+ "chi = jc.background.radial_comoving_distance(cosmo, a)\n",
+ "\n",
+ "# We can now plot the results:\n",
+ "plot(a, chi)\n",
+ "xlabel(r'scale factor $a$')\n",
+ "ylabel(r'radial comoving distance $\\chi$');"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "z30Karo4Jdnw"
+ },
+ "outputs": [],
+ "source": [
+ "# Not sure what are the units of the comoving distance? just ask:\n",
+ "jc.background.radial_comoving_distance?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "yihFIALbJ24Q"
+ },
+ "source": [
+ "## Defining redshift distributions\n",
+ "\n",
+ "On our path to computing Fisher matrices, we need to be able to express redshift distrbutions. In `jax-cosmo` n(z) are parametrized functions which can\n",
+ "be found in the `jax_cosmo.redshift` module. \n",
+ "\n",
+ "For the purpose of this tutorial, let's see how to define a Smail type distribution:\n",
+ "$$ n(z) = z^a \\exp(- (z/z_0)^b) $$\n",
+ "which depends on 3 parameters:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "2D7ouxvVIR7M"
+ },
+ "outputs": [],
+ "source": [
+ "# You can inspect the documentation to see the \n",
+ "# meaning of these positional arguments\n",
+ "nz1 = jc.redshift.smail_nz(1., 2., 1.)\n",
+ "nz2 = jc.redshift.smail_nz(1., 2., 0.5)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 281
},
+ "colab_type": "code",
+ "id": "Ef2oNlQ7Lmdi",
+ "outputId": "799bb7a6-1e67-45d8-dfd3-ff3b27ce6f81"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "QUBA8ajicFk4",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# Let's define a parameter vector for Omega_cdm, sigma8, which we initialize \n",
- "# at the fiducial cosmology used to produce the data vector.\n",
- "data = mu;\n",
- "params = np.array([cosmo.Omega_c, cosmo.sigma8])\n",
- "\n",
- "# Note the `jit` decorator for just in time compilation, this makes your code\n",
- "# run fast on GPU :-)\n",
- "@jax.jit\n",
- "def likelihood(p):\n",
- " # Create a new cosmology at these parameters\n",
- " cosmo = jc.Planck15(Omega_c=p[0], sigma8=p[1])\n",
- "\n",
- " # Compute mean and covariance of angular Cls\n",
- " m, C = jc.angular_cl.gaussian_cl_covariance_and_mean(cosmo, ell, probes)\n",
- "\n",
- " # Return likelihood value assuming constant covariance, so we stop the gradient\n",
- " # at the level of the precision matrix, and we will not include the logdet term\n",
- " # in the likelihood\n",
- " P = jax.lax.stop_gradient(np.linalg.inv(C))\n",
- " r = data - m\n",
- " return -0.5 * (r.T @ P @ r)"
- ],
- "execution_count": 0,
- "outputs": []
- },
- {
- "cell_type": "code",
- "metadata": {
- "id": "4Us1pbt1dt-h",
- "colab_type": "code",
- "outputId": "42bfcaff-0ed7-457f-95ce-108d1d8462eb",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 51
- }
- },
- "source": [
- "# Computing the likelihood at our fiducial params, we should get 0 since we don't\n",
- "# have the normalization term\n",
- "print(likelihood(params))\n",
- "%timeit likelihood(params).block_until_ready()"
- ],
- "execution_count": 21,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "-2.5765703e-09\n",
- "10 loops, best of 3: 40.5 ms per loop\n"
- ],
- "name": "stdout"
- }
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# And let's plot it\n",
+ "z = np.linspace(0,5,256)\n",
+ "\n",
+ "# Redshift distributions are callable, and they return the normalized distribution\n",
+ "plot(z, nz1(z), label='z0=1.')\n",
+ "plot(z, nz2(z), label='z0=0.5')\n",
+ "legend();\n",
+ "xlabel('Redshift $z$');"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 34
},
+ "colab_type": "code",
+ "id": "0eG0GXjCLmhz",
+ "outputId": "283348ed-0a18-45b4-a584-a58db0a72c39"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "EmJfTrVSySAW",
- "colab_type": "text"
- },
- "source": [
- "This is an illustration of evaluating the full likelihood. Note that because we \n",
- "used the `@jax.jit` decorator on the likelihood, this code is being compiled to \n",
- "and XLA expression that runs automatically on the GPU if it's available. \n",
- "\n",
- "\n",
- "But now that we have a likelihood function of the parameters, we can manipulate\n",
- "it with JAX, and in particular take the second derivative of this likelihood \n",
- "with respect to the input cosmological parameters. This Hessian, is just minus \n",
- "the Fisher matrix when everything is nice and Gaussian around the fiducial comology.\n",
- "\n",
- "\n",
- "So this mean, by JAX automaticatic differentiation, we can analytically derive\n",
- "the Fisher matrix in just one line:\n"
+ "data": {
+ "text/plain": [
+ "DeviceArray(1.0000004, dtype=float32)"
]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# We can check that the nz is properly normalized\n",
+ "jc.scipy.integrate.romb(nz1, 0., 5.)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "ZUYVlhKkMLpl"
+ },
+ "source": [
+ "Nice :-D "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "PGCY4irsNI9B"
+ },
+ "source": [
+ "## Defining probes and computing angular $C_\\ell$\n",
+ "\n",
+ "Let's now move on to define lensing and clustering probes using these two n(z).\n",
+ "In `jax-cosmo` a probe/tracer of a given type, i.e. lensing, contains a series of parameters, like redshift distributions, or galaxy bias. Probes are hosted in\n",
+ "the `jax_cosmo.probes` module.\n",
+ "\n",
+ "$C_\\ell$ computations will then take as argument a list of probes and will compute all auto- and cross- correlations between all redshift bins of all probes. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "-YUfaBhzNINW"
+ },
+ "outputs": [],
+ "source": [
+ "# First we define a list of redshift bins\n",
+ "nzs = [nz1, nz2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "R3qUxP9wO6fH"
+ },
+ "outputs": [],
+ "source": [
+ "# And now we define 2 probes \n",
+ "probes = [ jc.probes.WeakLensing(nzs, sigma_e=0.26), \n",
+ " jc.probes.NumberCounts(nzs, jc.bias.constant_linear_bias(1.)) ]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "t40aS024QFHx"
+ },
+ "source": [
+ "Given these probes, we can now compute tomographic angular power spectra for these probes using the `angular_cl` tools hosted in the `jax_cosmo.angular_cl` module. For now, all computations are done under the Limber approximation."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 139
},
+ "colab_type": "code",
+ "id": "QWedY8i6cFkw",
+ "outputId": "d8b34187-8daf-4218-84a1-e6093a5868f2"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "V9vX2W1UyRhm",
- "colab_type": "code",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 139
- },
- "outputId": "e5985d95-374b-4150-8b28-e16218ab9d45"
- },
- "source": [
- "# Compile a function that computes the Hessian of the likelihood\n",
- "hessian_loglik = jax.jit(jax.hessian(likelihood))\n",
- "\n",
- "# Evalauate the Hessian at fiductial cosmology to retrieve Fisher matrix\n",
- "F = - hessian_loglik(params)"
- ],
- "execution_count": 22,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype float64 requested in asarray is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype float64 requested in array is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype requested in astype is not available, and will be truncated to dtype int32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n"
- ],
- "name": "stderr"
- }
- ]
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype float64 requested in asarray is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype float64 requested in array is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype requested in astype is not available, and will be truncated to dtype int32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Let's define a range of \\ell\n",
+ "ell = np.logspace(1,3)\n",
+ "\n",
+ "# And compute the data vector\n",
+ "cls = jc.angular_cl.angular_cl(cosmo, ell, probes)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 34
},
+ "colab_type": "code",
+ "id": "VSKlZxxARxYO",
+ "outputId": "3d39a4d7-165e-428d-d2a8-d482353d2064"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "_Vvm8-IpB4rf",
- "colab_type": "text"
- },
- "source": [
- "What we are doing on the line above is taking the Hessian of the likelihood function, and evaluating at the fiducial cosmology. We surround the whole thing \n",
- "with a `jit` instruction so that the function gets compiled and evaluated in one\n",
- "block in the GPU.\n",
- "\n",
- "Compiling the function is not instantaneous, but once compiled, it becomes fast but the evaluation is:"
+ "data": {
+ "text/plain": [
+ "(10, 50)"
]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Let's check the shape of these Cls\n",
+ "cls.shape"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "X-Vnim-cSQSh"
+ },
+ "source": [
+ "We see that we have obtained 10 spectra, each of them of size 50, which is the length of the $\\ell$ vector. They are ordered first by probe, then by redshift bin. So the first cl is the lensing auto-spectrum of the first bin"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 303
},
+ "colab_type": "code",
+ "id": "-Xc458aidYL8",
+ "outputId": "960b3f8d-8bb4-4018-f45d-869de305ca19"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "NgrRoxsSB3UZ",
- "colab_type": "code",
- "outputId": "ec070fd3-1f46-449c-e5c5-bca82ccae07d",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "%timeit hessian_loglik(params).block_until_ready()"
- ],
- "execution_count": 23,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "1 loop, best of 3: 270 ms per loop\n"
- ],
- "name": "stdout"
- }
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
]
- },
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# This is for instance the first bin auto-spectrum \n",
+ "loglog(ell, cls[0])\n",
+ "ylabel(r'$C_\\ell$')\n",
+ "xlabel(r'$\\ell$');\n",
+ "title(r'Angular $C_\\ell$');"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "Ri-QjcD8UckV"
+ },
+ "source": [
+ "In addition to the data vector, we can also compute the covariance matrix using the tools from that module. Here is an example:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "zIdQSRgkUYC7"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "ZqXezv82EnxE",
- "colab_type": "text"
- },
- "source": [
- "And best of all: **No derivatives were harmed by finite differences in the computation of this Fisher!**\n",
- "\n",
- "We can now try to plot it:"
- ]
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype requested in astype is not available, and will be truncated to dtype int32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype float64 requested in asarray is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype float64 requested in array is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n"
+ ]
+ }
+ ],
+ "source": [
+ "mu, cov = jc.angular_cl.gaussian_cl_covariance_and_mean(cosmo, ell, probes, sparse=True);"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "yGd3NelNVZpj"
+ },
+ "source": [
+ "The data vector from this function is in a flattened shape so that it can be multiplied by the covariance matrix easily."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 265
},
+ "colab_type": "code",
+ "id": "WX5lmHsRVXIh",
+ "outputId": "64a404cf-9269-4e8b-ff67-3de6eb3ba183"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "pmTdQeeXk8qB",
- "colab_type": "code",
- "outputId": "3ac0f9a9-3dc5-4dd4-b58b-fa6a6d8e1291",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 299
- }
- },
- "source": [
- "# We can now plot contours obtained with this \n",
- "plot_contours(F, params, fill=False);\n",
- "xlabel('Omega_m')\n",
- "ylabel('sigma8')"
- ],
- "execution_count": 25,
- "outputs": [
- {
- "output_type": "execute_result",
- "data": {
- "text/plain": [
- "Text(14.5, 0.5, 'sigma8')"
- ]
- },
- "metadata": {
- "tags": []
- },
- "execution_count": 25
- },
- {
- "output_type": "display_data",
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "tags": [],
- "needs_background": "light"
- }
- }
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "semilogy(mu);"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 595
},
+ "colab_type": "code",
+ "id": "KLdw1eSvVXE3",
+ "outputId": "cc8fc33a-ccb2-47a8-8e3b-cf4fdc4d9eb1"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "dEXC2lIlE5IN",
- "colab_type": "text"
- },
- "source": [
- "And just to reinforce this point and demonstrate further audodiff magic, let's try to derive the same matrix differently, using the usual formula for constant\n",
- "covariance:\n",
- "\n",
- "$$ F_{\\alpha, \\beta} = \\sum_{i,j} \\frac{d \\mu_i}{d \\theta_\\alpha} C^{-1}_{i,j} \\frac{d \\mu_j}{d \\theta_\\beta} $$\n",
- "\n",
- "What we need in this expression, is the covariance matrix, which we already have\n",
- "and the Jacobian of the mean with respect to parameters. Normally you would need to use finite differencing, but luckily we can get that easily with JAX:"
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkcAAAJCCAYAAADKjmNEAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy86wFpkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAiKklEQVR4nO3df4xld33f/9dnZna8XpZlGS+2g9fE0DFCVgTEsnZJmqoEiuSFNOYPlC+wlt0IhPRVsWmbqqWVKkPVqkpblcRJFYkmKaR2mqA0Cm66/lIKfJv+E29sEkL40eyA+GGD2drjtVmv1+vZ++kfc8b51HXYXfvOnLkfPx7S0d575q7nfXzuzDznnHPvllprAABYNzf2AAAA24k4AgBoiCMAgIY4AgBoiCMAgIY4AgBobEoclVKuL6X8z1LKSinlg5vxOQAANkOZ9vsclVLmk/x5krckuT/JHyV5V631y1P9RAAAm2AzjhwdSLJSa/16rfVMkt9KcsMmfB4AgKlb2IT/5hVJvt3cvz/JwR/0F0op3qYbALap+SRnxx5iczxUa33ZM1eOdkF2KeV9pZR7Syn3jjUDAHBuZ5MslS5fw/XNZ1u5GVv6QJIrm/v7h3X/h1rrR2ut19Var9uEGQCAKVqtk14D6f+yGVv5R0muLqW8spSymOSdSe7ahM8DAGyh1ToZe4QtMfVrjmqta6WU9yf5VNZPU/56rfVL0/48AACbYeov5X9OQ7ggGwDYevc92+U9L4yThwAA50kcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0zhlHpZRfL6UcL6X8WbNuqZTy6VLKseHPlw7rSynl9lLKSinlT0sp127m8AAA03Y+R44+luT6Z6z7YJLP1FqvTvKZ4X6SHEpy9bC8L8mvTGdMAICtcc44qrX+QZLVZ6y+IcnHh9sfT/L2Zv1v1HV/mGRvKeWHpjQrADCCpfLCugrnuW7tZbXW7w63H0xy2XD7iiTfbh53/7Du/1JKeV8p5d5Syr3PcQYAZlCvP2gPzC92uW2HFnbmQxftGXuMLfW892KttSapz+HvfbTWel2t9brnOwMAs2O1TrqMiKNnz2R5bqG7bbt77XRuP3Myt+/cO/YoW+a57sHvbZwuG/48Pqx/IMmVzeP2D+sA4Gk9B9JSmetu21Yma/nQk4/lthfIEaTnuvfuSnLzcPvmJJ9s1t80vGrtDUkebU6/AcDTeg2klclakv5OH67WST785GO5ZXH32KNsurJ+VuwHPKCU/5jkjUn2JflektuS/F6STyR5RZJvJvmZWutqKaUk+eWsv7rtVJKfrbWe85qiUsoFn5YDgO1uqcxltU7GHmPqDi3szN1rp8ceYxrue7bLe84ZR1tBHAHQq14D6cD8Yo6ePTP2GM/Xs8ZRX8f8AGCb6TGMkvXTh8tzC2OPsSnEEQBwwVbrpNvrxvrbIgBgS2wcFestkPo8HgYAbIkeTxv2lXoAAM+TOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjAICGOAIAaIgjaCwVXxKw2Q7ML449wqa44+KlLM8tjD3G1N3zokvz5Ut/ZOwxtpSfBNBYrROBBJvs6NkzXUbEh558LId37Opu2w4/sZrvP348D1zy6rFH2TJ+CsAzrNbJ2CNA91brpLuIWJms5c6nTuXg/GJX27YyWcvhJ1bzhSdWM9mzf+xxtkSptY49Q0op4w8BwJbaOErb2y8ky3MLWSpzWa2TrEzWxh5napbKXO64eClJ8tZTD408zdTcV2u97pkrHTkCYBS9RdGGlcna06foezpNv1onT0fRLYu7R55mc/Wz1wCYOb1e57cyWcvKZO3po0g9eeuph3JoYWe3F9Yn4giAkfUaSBun1Xrctreeeii3Lu7u6tqqVn97DICZ0+spto1A6jEibnxiNYd37Ooy/vrbIgDYZnoNpA8/+VgOLezsLpD62hoA2KZ6PcV251Onuru2qp8tAYBtrtfrq46ePdPVq/P62AoAmBG9BtLGezr1sG2zvwUAMGN6vgC9h/ib7ekBgG1n1uNPHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEDjnHFUSrmylPK5UsqXSylfKqV8YFi/VEr5dCnl2PDnS4f1pZRyeyllpZTyp6WUazd7IwAApuV8jhytJfm5Wus1Sd6Q5G+XUq5J8sEkn6m1Xp3kM8P9JDmU5OpheV+SX5n61AAAm+SccVRr/W6t9fPD7e8n+UqSK5LckOTjw8M+nuTtw+0bkvxGXfeHSfaWUn5o2oMDAGyGC7rmqJRyVZIfTXJPkstqrd8dPvRgksuG21ck+Xbz1+4f1j3zv/W+Usq9pZR7L3RoAIDNct5xVErZneQ/Jfk7tdbH2o/VWmuSeiGfuNb60VrrdbXW6y7k7wEAbKbziqNSyo6sh9GdtdbfHVZ/b+N02fDn8WH9A0mubP76/mEdAMC2dz6vVitJfi3JV2qt/6b50F1Jbh5u35zkk836m4ZXrb0hyaPN6TcAgG2trJ8R+wEPKOUnkvyPJF9MMhlW/+OsX3f0iSSvSPLNJD9Ta10dYuqXk1yf5FSSn621/sDrikopF3RKDgBgCu57tst7zhlHW0EcAQAjeNY48g7ZAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHADAFy3MLY4+wKZbnFnJ4x66xx9hS4ggApmBlspal0t+P1ZXJWu5eO/2CCqT+9iIAjGS1TroMpNU6yd1rp3NoYefYo2yJ/vYgAIxotU7GHmFTrNZJ7jl7JgfmF8ceZdOJIwDgvKzWSVYma91eX7VBHAEA5221Tro9fbih3y0DADZFr6cON4gjAOCC9Xz0qM+tAgA2Xa9HkMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANMQRAEBDHAEANM4ZR6WUnaWUo6WUL5RSvlRK+fCw/pWllHtKKSullN8upSwO6y8a7q8MH79qk7cBAGBqzufI0ZNJ3lRrfV2S1ye5vpTyhiQ/n+QjtdblJI8kec/w+PckeWRY/5HhcQAAM+GccVTXnRzu7hiWmuRNSX5nWP/xJG8fbt8w3M/w8TeXUsq0BgYA2Ezndc1RKWW+lPInSY4n+XSSryU5UWtdGx5yf5IrhttXJPl2kgwffzTJJVOcGYAZtlT6vNz10MLOsUfYFId37MqRXfvGHmNLndcztNZ6ttb6+iT7kxxI8prn+4lLKe8rpdxbSrn3+f63AJgtPQbSw3WSA/OL3W3bscn6cZDbd+4dd5AtdEF7sNZ6IsnnkvxYkr2llIXhQ/uTPDDcfiDJlUkyfPwlSR5+lv/WR2ut19Var3tuowMwi1brZOwRNsXRs2eyWifdxdHRs2dy6+kTWZ5byOEdu8YeZ0ucz6vVXlZK2TvcvjjJW5J8JeuR9I7hYTcn+eRw+67hfoaPf7bWWqc4MwAzrseISJKV4SjL8tzCOR45W1Yma7nxidUc3rErB+YXxx5n05VzdUsp5bVZv8B6Pusx9Yla6z8tpbwqyW8lWUryx0lurLU+WUrZmeQ/JPnRJKtJ3llr/fo5Pod4AqAbS2UuS2Xu6VjqyR0XL+XW0yd6OQJ437OdwTpnHG0FcQRAbzaOjHUSEf+H23fuza2nT4w9xjQ8axz1d0wTALaB1Trp9vThradP5JbF3WOPsWn622MAsI30Gki/dOZkt29f0N/eAoBtptdAunvtdJcXaPe3pwBgG+rx2qNk/aX+vb06TxwBAM/LymStqyNj/WwJADCano6MiSMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAgIY4AgBoiCMAttRS6fNHz4H5xbFH2BQH5hdzy+LuscfYUn0+Q9l0vrnB5loqc11+nS2VuRzbffnYY2yKf3H563PbRXvGHmPq/t2+1+TBa96R5bmFsUfZMqXWOvYMKaWMPwQXbKnMZbVOxh5j6pbnFrJaJ11uG7NlI456fC4+/OKX55Lvf2fsMabuy5f+SD7//e/kxidWxx5lqiZ79udvLl+f//L5Xx17lGm7r9Z63TNX9vdrCVtmtU66/M12ZbLW7W/tzJaNSO/xuXjJ97+Te1506dhjTN01x/8sb79oT47s2jf2KFM199j9ue5Ln8i7X3fT2KNsif6+4thSvX7jXpmsJen39CGzpccjR0ly8PHjuePipbHHmLrdJ76RS8pcd/H34Scfy8qf/Vb+yWvePvYom853fp63Xr9x9/xbO2wXNz6xmlsWd3f3dXbw8eM5sna6uyNIR8+eyaeOHcmdV71x7FE2VV/PRtgEAgk2151PncrB+cXuvs5+6czJ3PnUqe6Ojh09eyZHHjiaL1z22u722YY+twqmrNejY7AdrNZJ7jl7JstzC139sF2tk9y9djp3PnWqu1ex3fnUqfzuiW/kWy95RZevYvNqNQC2hY0XQvT4atFDCzuzVOZy51Onxh5lqm67aE8Ozi/m1tMnnr5Wc8Z4tRoA21d7nV9PR5CS5O6101mtk+7eS+3DTz6We86eyeEdu7o6gtTXsw+AmdbjUaMNd6+dziVlrquISNYDabVOurpurI+tAKAbPb9S9O6107m6s2urkvWLz5N0E0izvwUAdKnnQOrt6FGyfpH2w8MRpFnX37MOgG70GkhHh1fn9ebo2TM5NlnLoYWdY4/yvPT3jAOgK70G0sY/VdSblcla7jl7ZqYvPu9vrwDQnV4DqeftmuWjY/3tEQC61Our2HrdrmT9KNIsBpI4AgA2zSyePpytaQGAmTNrpw9nZ1IAYGbN0ulDcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAAANcQQA0BBHAACN846jUsp8KeWPSym/P9x/ZSnlnlLKSinlt0spi8P6i4b7K8PHr9qk2QEApu5Cjhx9IMlXmvs/n+QjtdblJI8kec+w/j1JHhnWf2R4HADATDivOCql7E/ytiS/OtwvSd6U5HeGh3w8yduH2zcM9zN8/M3D4wEAtr3zPXL0C0n+QZLJcP+SJCdqrWvD/fuTXDHcviLJt5Nk+Pijw+PpyIH5xbFH2BR3XLyU5bmFscfgAvS6vw4t7Ozy6+zA/GI+c8WBscfYFH/lx/9+Hn7xy8ceY+re/bqb8rf+1v8/9hhb6pxxVEr5qSTHa633TfMTl1LeV0q5t5Ry7zT/u2yNlclal9+4P/TkYzm8Y1e3P3B7tDJZy1Lp77Uld6+dTtJf/B09eyZ/8NBX8+VLf2TsUabu6Bd/M//wh/96Tu69auxRpuoDK/9fHv+Tj+Vd77pr7FG2Tq31By5J/kXWjwx9I8mDSU4luTPJQ0kWhsf8WJJPDbc/leTHhtsLw+PKOT5HtczeslTm6vLcwuhzTHtZnluoh3fs6nLbel6WytzoM2zGNi3PLXT5XLzj4qV6cu9Vo88x7eXk3qvqx676yfrIS181+izTXI7s2lff/bqb6vXX/8Los0x5uffZuuScv27VWv9RrXV/rfWqJO9M8tla6+Ekn0vyjuFhNyf55HD7ruF+ho9/tg4FRF9W6ySrddLdb+0rk7Xcc/ZMlspcd7+192y1Ts79oBmzWidZmaxfvdDb19mNT6zmD86czD0vunTsUaZq94lv5IZHv5kvXryUJ1/yirHHmZq3nnooV3/19zL5X1/OT1z3/449zqZ7Pl9t/zDJ3yulrGT9mqJfG9b/WpJLhvV/L8kHn9+IbGc9/kBK1gNpI/x6+6HE7Nk4ddjbc/Gtpx5Kktx20Z6utu2lj3w9Bx8/nq9dtKer+Pvwk4/lxJ98LKfmd+QXl68fe5xNVbbDQZ1SyvhD8LwslbkuQ2nj6NFGLMGYev06O7JrX+586lTuXjvd1fbd86JL8+IXXZr/9tj9ufX0ibHHmZqlMpdLD34g//lrn8rBh7466/vsvlrrdc9c2U+qM6oeT68lf3Fao8dtY/b0+nX21lMP5dDCzhzs7EUeBx8/nv/22P35G3v259DCzrHHmZrVOslX//AjufGVb8qx3Zd3+Zzsb4sYzYz/9vCX2ggk1x+xHfQaSDc+sZoD84tdRUSS3Hr6RH5udSW3v/RV3X0PuefoL+eWV/2N3HHxUnfPSafV4AJsnGKDsfV6iu3wjl1ZrZOn38qgF8tzC/nvL31Vrnj4z8ceZer+9fKh/LXv3peDjx8fe5Tn4llPq4kjuEC9/lCC7eLA/GIuKXPdBVKSnNx7VXaf+MbYY0zdZ644kFc8+q1cffLBsUe5UK45gmno9bQGbBdHz57Jsclad6fYkvWX+h/bffnYY0zdmx84mpcs7u5m23yHh+dAIMHm2ni/sR7fif/qkw/mjouXxh5j6i5dXclqnXTx9gW+u8Nz5NQabK7VOsnRs2e6u5A5Wb8A/ZbF3d39knXw8eO546lTObJr39ijPC+uOQJg2+vxWr9e30dtqczl4PxiDswv5sNPPjb2OOfimiMAZlOPp7Lb91Hrads2Xm1499rpHN6xa+xxnpP+jlUC0KWejq5s6HGbNhw9eybJ+qsPN27Pin5SFQBmUK//iHfyF4E0a9s2W9MCQKd6DqRZO3U4O5MCQOd6Pc02a/9G5exMCgDMrFkKpNmYEgCYebNy6nD7TwgAdGMWTh2KIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiIIwCAhjgCAGiII56TQws7xx5hUxzZtS/Lcwtjj8EF6HV/Hd6xKwfmF8ceY+oOzC/mC5e9duwxNsXNr70xR3btG3uMqfvYVT+Zt7zlX449xpbaFnE0P/YAXJClMpdDCzu7/KF01e7Lc+fFS11uW68Ozi9mqWyLb2VTdXjHrnzooj3dPRcPzi/mn/3QtZns2T/2KFNXrn1v/v2rf6q7QPrNV78t7373at527XvHHmXr1FpHX5LUpTJXk1hmaLl9594u99sDl7y6Htm1r8tt63U5vGNXl/vr9p17u3wuLs8t1Ldd+95620V7Rp9l2su73nVXfffrbupu29527XvrJz/5I/X3r/zx0WeZ8nLvs3bJ2GG0EUeJQJrFpbdvABvLZM/+emTXvtHnsJz/cmhhZ5ffQw7v2NXtc/Hdr7upHphfHH2OaS/XX/8L9W3Xvre7bfv9K3+8/tf/uliP7b589FmmuGz/OLLM5nLL4u7RZ9iM5ciufd3+UOp1OTC/2GUgHZhfrHdcvDT6HJux/JPXvL27iEhSDx54f7324K3dPR+P7b68HjlyWU/7TBxZNm85tLBz9Bk2Y7llcbdAmrFleW6hux9IyfqR9dt37h19js1Y7rzqjfXwjl2jzzHt5ReXr6+vecPfHX2OaS8H5hfrb/7m4bo8tzD6LFNYxJFlcxe/tVu2y7JU5rp8Lib9Hqn9wmWv7fI0/bGXXVMPHnj/6HNMe1meW6j/6l99vod9Jo4sm7/0+lv78txCD98EXnBLj8/FpM8jtUtlrp7ce1V3X2dLZa4+/OKX13e/7qbRZ5n2cttFe+r73//VOtmzf/RZnscijixbs/T6W/tSmevy0L9lNpeOrvl4elmeW6hHdu3rMpCO7NpX//XyodFnmfYy2bO//vRP/2p94JJXjz7Lc1yeNY7KECejKqWMPwRTtVTmslonY48xdUtlLstzCzl69szYo0CW5xayMlkbe4ypWp5byOEdu7JaJ/mlMyfHHmdqlspc7t61Lyf3XpU3P3B07HGm6oFLXp3/55Vvzr//5n/P1f/ry2OPc6Huq7Ve98yV4ggu0FKZy1KZ6+6HErOpx19ElucWcnB4d/A7nzo18jTTdWz35XnJ4u5curoy9ihTdexl1+STL/nhvOuRr+WKh/987HEuhDiCadl4R+befijBdrFU5nJwfjEP10l3R2qP7b48q3WSg48fH3uUqXrgklfnixcv5Se//51c9Oi3xh7nfD1rHPX3nvuwBUQRbK7VOsk9Z8/kkuFUdk+uPvlgkuSWxd1d/dM3Vzz85/nJ738nX925N/e86NKxx3le+tkrsMVW66Srb2yw3azWSe5eO52r5xa6+1o7+PjxHFrY+fTpw15c9Oi3cvrkg1natS+3LO4ee5znrK9nG2wxR5Bg8929drq7o0dJ8tZTD+XA/GIOdBZIBx8/ntsf/VY++OKXz+y2ueYIgJnQ46vzkuTwjl05Nlnr7tqqA/OL+dSe/fkrJ76xnX+RdEE2ALOt10DaOMLSWyAtlbk89OKXZ+6x+8ce5S/jgmwAZtvKZK2764+S9Shamax1d/pwtU4y99j9ObJr39ijXJD+nmEAdK3XF0Os1klW66S7QErWr6+67aI9Y49x3pxWA4Btpsc390ySQws7c/fa6bHHaDmtBgCzoNejY7PyysP+/s8DQAd6PHKUzMZ1Y9t7OgCgO9v9yNj2nQwA6NZ2PjImjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGuIIAKAhjgAAGgtjDzB4KMnjw5/Mhn2xv2aNfTZ77LPZYn/Nnh9+tpWl1rrVgzyrUsq9tdbrxp6D82N/zR77bPbYZ7PF/uqH02oAAA1xBADQ2E5x9NGxB+CC2F+zxz6bPfbZbLG/OrFtrjkCANgOttORIwCA0Y0eR6WU60sp/7OUslJK+eDY87CulPLrpZTjpZQ/a9YtlVI+XUo5Nvz50mF9KaXcPuzDPy2lXDve5C9MpZQrSymfK6V8uZTypVLKB4b19tk2VUrZWUo5Wkr5wrDPPjysf2Up5Z5h3/x2KWVxWH/RcH9l+PhVo27AC1gpZb6U8sellN8f7ttnnRk1jkop80n+bZJDSa5J8q5SyjVjzsTTPpbk+mes+2CSz9Rar07ymeF+sr7/rh6W9yX5lS2akb+wluTnaq3XJHlDkr89fC3ZZ9vXk0neVGt9XZLXJ7m+lPKGJD+f5CO11uUkjyR5z/D49yR5ZFj/keFxjOMDSb7S3LfPOjP2kaMDSVZqrV+vtZ5J8ltJbhh5JpLUWv8gyeozVt+Q5OPD7Y8neXuz/jfquj9MsreU8kNbMihJklrrd2utnx9ufz/r37iviH22bQ3/708Od3cMS03ypiS/M6x/5j7b2Je/k+TNpZSyNdOyoZSyP8nbkvzqcL/EPuvO2HF0RZJvN/fvH9axPV1Wa/3ucPvBJJcNt+3HbWQ4dP+jSe6JfbatDadn/iTJ8SSfTvK1JCdqrWvDQ9r98vQ+Gz7+aJJLtnRgkuQXkvyDJJPh/iWxz7ozdhwxo+r6yxy91HGbKaXsTvKfkvydWutj7cfss+2n1nq21vr6JPuzfiT9NeNOxA9SSvmpJMdrrfeNPQuba+w4eiDJlc39/cM6tqfvbZx6Gf48Pqy3H7eBUsqOrIfRnbXW3x1W22czoNZ6IsnnkvxY1k9xbvy7l+1+eXqfDR9/SZKHt3bSF7y/muSnSynfyPplIG9K8ouxz7ozdhz9UZKrhyv9F5O8M8ldI8/EX+6uJDcPt29O8slm/U3DK6DekOTR5lQOW2C4juHXknyl1vpvmg/ZZ9tUKeVlpZS9w+2Lk7wl69eKfS7JO4aHPXOfbezLdyT5bPVGdVuq1vqPaq37a61XZf3n1WdrrYdjn3Vn9DeBLKW8NevncOeT/Hqt9Z+POhBJklLKf0zyxqz/K9PfS3Jbkt9L8okkr0jyzSQ/U2tdHX4w/3LWX912KsnP1lrvHWHsF6xSyk8k+R9Jvpi/uBbiH2f9uiP7bBsqpbw26xfrzmf9F9VP1Fr/aSnlVVk/KrGU5I+T3FhrfbKUsjPJf8j69WSrSd5Za/36ONNTSnljkr9fa/0p+6w/o8cRAMB2MvZpNQCAbUUcAQA0xBEAQEMcAQA0xBEAQEMcAQA0xBEAQEMcAQA0/jd61R9bo6yzOQAAAABJRU5ErkJggg==\n",
+ "text/plain": [
+ ""
]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "figure(figsize=(10,10))\n",
+ "imshow(np.log10(jc.sparse.to_dense(cov)+1e-11),cmap='gist_stern');"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "hN5jA8ogp7Bb"
+ },
+ "source": [
+ "## Where the wild things are: Automatic Differentiation\n",
+ "\n",
+ "Now that we know how to compute various quantities, we can move on to the amazing part, computing gradients automatically by autodiff. As an example, we\n",
+ "will demonstrate how to analytically **compute Fisher matrices, without finite differences.** But gradients are usefull for a wide range of other applications.\n",
+ "\n",
+ "\n",
+ "We begin by defining a Gaussian likelihood function for the data vector we have \n",
+ "obtained at the previous step. And we make this likelihood function depend on an array of parameters, `Omega_c`, `sigma_8`.\n",
+ " \n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "QUBA8ajicFk4"
+ },
+ "outputs": [],
+ "source": [
+ "# Let's define a parameter vector for Omega_cdm, sigma8, which we initialize \n",
+ "# at the fiducial cosmology used to produce the data vector.\n",
+ "data = mu;\n",
+ "params = np.array([cosmo.Omega_c, cosmo.sigma8])\n",
+ "\n",
+ "# Note the `jit` decorator for just in time compilation, this makes your code\n",
+ "# run fast on GPU :-)\n",
+ "@jax.jit\n",
+ "def likelihood(p):\n",
+ " # Create a new cosmology at these parameters\n",
+ " cosmo = jc.Planck15(Omega_c=p[0], sigma8=p[1])\n",
+ "\n",
+ " # Compute mean and covariance of angular Cls\n",
+ " m, C = jc.angular_cl.gaussian_cl_covariance_and_mean(cosmo, ell, probes, sparse=True)\n",
+ "\n",
+ " # Return likelihood value assuming constant covariance, so we stop the gradient\n",
+ " # at the level of the precision matrix, and we will not include the logdet term\n",
+ " # in the likelihood\n",
+ " P = jc.sparse.inv(jax.lax.stop_gradient(C))\n",
+ " r = data - m\n",
+ " return -0.5 * r.T @ jc.sparse.sparse_dot_vec(P, r)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 51
},
+ "colab_type": "code",
+ "id": "4Us1pbt1dt-h",
+ "outputId": "42bfcaff-0ed7-457f-95ce-108d1d8462eb"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "WKn4COsdlKfs",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# We define a parameter dependent function that computes the mean\n",
- "def mean_fn(p):\n",
- " cosmo = jc.Planck15(Omega_c=p[0], sigma8=p[1])\n",
- " # Compute signal vector\n",
- " m = jc.angular_cl.angular_cl(cosmo, ell, probes)\n",
- " return m.flatten() # We want it in 1d to operate against the covariance matrix"
- ],
- "execution_count": 0,
- "outputs": []
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype float64 requested in asarray is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype float64 requested in array is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
+ "/home/francois/.local/lib/python3.8/site-packages/jax/lax/lax.py:5591: UserWarning: Explicitly requested dtype requested in astype is not available, and will be truncated to dtype int32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
+ " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n"
+ ]
},
{
- "cell_type": "code",
- "metadata": {
- "id": "Be381gp6Gjqx",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# We compute it's jacobian with JAX, and we JIT it for efficiency\n",
- "jac_mean = jax.jit(jax.jacfwd(mean_fn))"
- ],
- "execution_count": 0,
- "outputs": []
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "-3.5111292e-09\n",
+ "29.1 ms ± 676 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Computing the likelihood at our fiducial params, we should get 0 since we don't\n",
+ "# have the normalization term\n",
+ "print(likelihood(params))\n",
+ "%timeit likelihood(params).block_until_ready()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "EmJfTrVSySAW"
+ },
+ "source": [
+ "This is an illustration of evaluating the full likelihood. Note that because we \n",
+ "used the `@jax.jit` decorator on the likelihood, this code is being compiled to \n",
+ "and XLA expression that runs automatically on the GPU if it's available. \n",
+ "\n",
+ "\n",
+ "But now that we have a likelihood function of the parameters, we can manipulate\n",
+ "it with JAX, and in particular take the second derivative of this likelihood \n",
+ "with respect to the input cosmological parameters. This Hessian, is just minus \n",
+ "the Fisher matrix when everything is nice and Gaussian around the fiducial comology.\n",
+ "\n",
+ "\n",
+ "So this mean, by JAX automaticatic differentiation, we can analytically derive\n",
+ "the Fisher matrix in just one line:\n"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 139
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "t3kVMfEaGyuJ",
- "colab_type": "code",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 139
- },
- "outputId": "339ec1c1-4f47-43e9-f692-9c9070f5f0a2"
- },
- "source": [
- "# We can now evaluate the jacobian at the fiducial cosmology\n",
- "dmu = jac_mean(params)"
- ],
- "execution_count": 28,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype float64 requested in asarray is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype float64 requested in array is not available, and will be truncated to dtype float32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n",
- "/usr/local/lib/python3.6/dist-packages/jax/lax/lax.py:5222: UserWarning: Explicitly requested dtype requested in astype is not available, and will be truncated to dtype int32. To enable more dtypes, set the jax_enable_x64 configuration option or the JAX_ENABLE_X64 shell environment variable. See https://github.com/google/jax#current-gotchas for more.\n",
- " warnings.warn(msg.format(dtype, fun_name , truncated_dtype))\n"
- ],
- "name": "stderr"
- }
- ]
+ "colab_type": "code",
+ "id": "V9vX2W1UyRhm",
+ "outputId": "e5985d95-374b-4150-8b28-e16218ab9d45"
+ },
+ "outputs": [],
+ "source": [
+ "# Compile a function that computes the Hessian of the likelihood\n",
+ "hessian_loglik = jax.jit(jax.hessian(likelihood))\n",
+ "\n",
+ "# Evalauate the Hessian at fiductial cosmology to retrieve Fisher matrix\n",
+ "F = - hessian_loglik(params)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "_Vvm8-IpB4rf"
+ },
+ "source": [
+ "What we are doing on the line above is taking the Hessian of the likelihood function, and evaluating at the fiducial cosmology. We surround the whole thing \n",
+ "with a `jit` instruction so that the function gets compiled and evaluated in one\n",
+ "block in the GPU.\n",
+ "\n",
+ "Compiling the function is not instantaneous, but once compiled, it becomes fast but the evaluation is:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 34
},
+ "colab_type": "code",
+ "id": "NgrRoxsSB3UZ",
+ "outputId": "ec070fd3-1f46-449c-e5c5-bca82ccae07d"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "H6uzzV-jHnNe",
- "colab_type": "code",
- "outputId": "ed61a0df-5f6f-485b-ebbc-33ddaaa15c20",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "dmu.shape"
- ],
- "execution_count": 29,
- "outputs": [
- {
- "output_type": "execute_result",
- "data": {
- "text/plain": [
- "(500, 2)"
- ]
- },
- "metadata": {
- "tags": []
- },
- "execution_count": 29
- }
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "479 ms ± 9.09 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
+ ]
+ }
+ ],
+ "source": [
+ "%timeit hessian_loglik(params).block_until_ready()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "ZqXezv82EnxE"
+ },
+ "source": [
+ "And best of all: **No derivatives were harmed by finite differences in the computation of this Fisher!**\n",
+ "\n",
+ "We can now try to plot it:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 299
},
+ "colab_type": "code",
+ "id": "pmTdQeeXk8qB",
+ "outputId": "3ac0f9a9-3dc5-4dd4-b58b-fa6a6d8e1291"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "X9ZDB3RtHFnG",
- "colab_type": "code",
- "outputId": "07f53328-fb3a-4ead-bdaf-d6528136a8aa",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 34
- }
- },
- "source": [
- "# For fun, we can alsi time it\n",
- "%timeit jac_mean(params).block_until_ready()"
- ],
- "execution_count": 30,
- "outputs": [
- {
- "output_type": "stream",
- "text": [
- "10 loops, best of 3: 31.6 ms per loop\n"
- ],
- "name": "stdout"
- }
+ "data": {
+ "text/plain": [
+ "Text(8.125, 0.5, 'sigma8')"
]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
},
{
- "cell_type": "markdown",
- "metadata": {
- "id": "ej3RdeaeHWy6",
- "colab_type": "text"
- },
- "source": [
- "Getting these gradients is the same order of time than evaluating the forward function!"
+ "data": {
+ "image/png": "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Y/zijTfeoHTp0vTu3dvtUvIdCxXjUzVq1OCnn35iy5YtXH/99TbOYoJOSkoKL730Eu+++y5nX3rQgIWK8YOIiAjmzp1Lp06daNKkCZ988onbJRnjE6rKAw88wMMPP0z16tXdLidfslAxfhESEsIjjzzCvHnzeO655+jduzdHjx51uyxjLsmECRPYsWMHjz32mNul5FsWKsavYmNjWblyJWFhYcTGxrJ8+XK3SzLmovzwww8MHz6c6dOnExYW5nY5+ZaFivG74sWLM378eF5++WXatm3Lyy+/TEZGhttlGZNnv/76K126dOHjjz8mJibG7XLyNQsVc9l06tSJpKQkvvrqK2655RZ27tzpdknGnNfBgwf529/+xgsvvMDNN9/sdjn5noWKuawqV67MwoULufnmm7nuuut49dVXOX36tNtlGZOjtLQ0OnbsyB133MHAgQPdLicgWKiYyy40NJQnn3ySZcuWkZCQwHXXXUdiYqLbZRlzFlXl3nvvJSIigldeecXtcgKGhYpxTbVq1fj666/55z//SdeuXenXrx8HDhxwuyxjsr4xv379eqZMmWJXIL4AFirGVSJC586d2bBhA6VLl6ZOnTq8//77ZGZmul2aKaBOnDjBXXfdxW+//caCBQsoXry42yUFFAsVky+UKlWKUaNGMW/ePMaPH098fDxr1651uyxTwBw8eJBbb72VkiVLMmfOHEqUKOF2SQHHQsXkKw0aNODHH3+kd+/etGrVigEDBthZYuaySE1NJT4+niZNmvDhhx/ad1EukoWKyXdCQkIYNGgQycnJXHnllcTGxvKPf/yDvXv3ul2aCVIbN26kefPm9O3bl9dee81ukX0J7F/O5FsRERG8+OKLbNiwARGhdu3aPPnkkxw6dMjt0kyQUFU++ugjrr/+el544QUeffRRt0sKeBYqJt+rWLEio0eP5ueff2b//v3UqFGDl156iWPHjrldmglghw8f5u9//zsvvfQS3377Lb169XK7pKBgoWICRuXKlRk/fjxLlixh7dq1VKtWjTFjxnDy5Em3SzMB5ocffqB+/fqULVuWpKQkYmNj3S4paFiomIBTo0YNPvnkE+bNm0dCQgLXXHMNzz77rI25mPNKS0vjiSeeoFu3brz99tuMHTuWYsWKuV1WULFQMQGrfv36fPHFF3z//ffs3buXWrVq0bdvX9asWeN2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\n",
+ "text/plain": [
+ ""
]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# We can now plot contours obtained with this \n",
+ "plot_contours(F, params, fill=False);\n",
+ "xlabel('Omega_m')\n",
+ "ylabel('sigma8')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "dEXC2lIlE5IN"
+ },
+ "source": [
+ "And just to reinforce this point and demonstrate further audodiff magic, let's try to derive the same matrix differently, using the usual formula for constant\n",
+ "covariance:\n",
+ "\n",
+ "$$ F_{\\alpha, \\beta} = \\sum_{i,j} \\frac{d \\mu_i}{d \\theta_\\alpha} C^{-1}_{i,j} \\frac{d \\mu_j}{d \\theta_\\beta} $$\n",
+ "\n",
+ "What we need in this expression, is the covariance matrix, which we already have\n",
+ "and the Jacobian of the mean with respect to parameters. Normally you would need to use finite differencing, but luckily we can get that easily with JAX:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "WKn4COsdlKfs"
+ },
+ "outputs": [],
+ "source": [
+ "# We define a parameter dependent function that computes the mean\n",
+ "def mean_fn(p):\n",
+ " cosmo = jc.Planck15(Omega_c=p[0], sigma8=p[1])\n",
+ " # Compute signal vector\n",
+ " m = jc.angular_cl.angular_cl(cosmo, ell, probes)\n",
+ " return m.flatten() # We want it in 1d to operate against the covariance matrix"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 27,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "Be381gp6Gjqx"
+ },
+ "outputs": [],
+ "source": [
+ "# We compute it's jacobian with JAX, and we JIT it for efficiency\n",
+ "jac_mean = jax.jit(jax.jacfwd(mean_fn))"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 28,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 139
},
- {
- "cell_type": "code",
- "metadata": {
- "id": "F3UMqqdLHQX7",
- "colab_type": "code",
- "colab": {}
- },
- "source": [
- "# Now we can compose the Fisher matrix:\n",
- "F_2 = np.einsum('ia, ij, jb', dmu, np.linalg.inv(cov), dmu)"
- ],
- "execution_count": 0,
- "outputs": []
+ "colab_type": "code",
+ "id": "t3kVMfEaGyuJ",
+ "outputId": "339ec1c1-4f47-43e9-f692-9c9070f5f0a2"
+ },
+ "outputs": [],
+ "source": [
+ "# We can now evaluate the jacobian at the fiducial cosmology\n",
+ "dmu = jac_mean(params)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 29,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 34
},
+ "colab_type": "code",
+ "id": "H6uzzV-jHnNe",
+ "outputId": "ed61a0df-5f6f-485b-ebbc-33ddaaa15c20"
+ },
+ "outputs": [
{
- "cell_type": "code",
- "metadata": {
- "id": "zUv4GmcVH1z8",
- "colab_type": "code",
- "outputId": "4b7fb3e2-3271-4492-f781-45c205c2e57c",
- "colab": {
- "base_uri": "https://localhost:8080/",
- "height": 282
- }
- },
- "source": [
- "# We can now plot contours obtained with this \n",
- "plot_contours(F, params, fill=False,color='black',lw=4);\n",
- "plot_contours(F_2, params, fill=False, color='red', lw=4, linestyle='dashed');\n",
- "xlabel('Omega_m')\n",
- "ylabel('sigma8');"
- ],
- "execution_count": 32,
- "outputs": [
- {
- "output_type": "display_data",
- "data": {
- "image/png": "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\n",
- "text/plain": [
- ""
- ]
- },
- "metadata": {
- "tags": [],
- "needs_background": "light"
- }
- }
+ "data": {
+ "text/plain": [
+ "(500, 2)"
]
+ },
+ "execution_count": 29,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "dmu.shape"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 30,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 34
},
+ "colab_type": "code",
+ "id": "X9ZDB3RtHFnG",
+ "outputId": "07f53328-fb3a-4ead-bdaf-d6528136a8aa"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "51gfhl9cIzMC",
- "colab_type": "text"
- },
- "source": [
- "The red dashed is our second derivation of the Fisher matrix using the jacobian, the black contour underneath is our first derivation simply taking the Hessian of the likelihood.\n",
- "\n",
- "They agree perfectly, and they should, because they are both analytically computed."
- ]
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "56.5 ms ± 601 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# For fun, we can alsi time it\n",
+ "%timeit jac_mean(params).block_until_ready()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "ej3RdeaeHWy6"
+ },
+ "source": [
+ "Getting these gradients is the same order of time than evaluating the forward function!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 35,
+ "metadata": {
+ "colab": {},
+ "colab_type": "code",
+ "id": "F3UMqqdLHQX7"
+ },
+ "outputs": [],
+ "source": [
+ "# Now we can compose the Fisher matrix:\n",
+ "F_2 = jc.sparse.dot(dmu.T, jc.sparse.inv(cov), dmu)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 36,
+ "metadata": {
+ "colab": {
+ "base_uri": "https://localhost:8080/",
+ "height": 282
},
+ "colab_type": "code",
+ "id": "zUv4GmcVH1z8",
+ "outputId": "4b7fb3e2-3271-4492-f781-45c205c2e57c"
+ },
+ "outputs": [
{
- "cell_type": "markdown",
- "metadata": {
- "id": "JrpDmbNfJUJ4",
- "colab_type": "text"
- },
- "source": [
- "## Conclusions and going further\n",
- "\n",
- "We have covered some of the most important points of `jax-cosmo`, feel free to \n",
- "go through the [design document](https://github.com/DifferentiableUniverseInitiative/jax_cosmo/blob/master/design.md) for background and further explanations of how things work. You can also follow this [JAX document](https://jax.readthedocs.io/en/latest/notebooks/Common_Gotchas_in_JAX.html) to go deeper into JAX.\n",
- "\n",
- "\n",
- "`jax-cosmo` is still very young and lacks many features, but hopefuly this notebook demonstrates the power of automatic differentiation, and given that the entire code is in simple Python, feel free to contribute missing features that would be necessary for your work ;-) "
+ "data": {
+ "image/png": "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\n",
+ "text/plain": [
+ ""
]
+ },
+ "metadata": {
+ "needs_background": "light"
+ },
+ "output_type": "display_data"
}
- ]
-}
\ No newline at end of file
+ ],
+ "source": [
+ "# We can now plot contours obtained with this \n",
+ "plot_contours(F, params, fill=False,color='black',lw=4);\n",
+ "plot_contours(F_2, params, fill=False, color='red', lw=4, linestyle='dashed');\n",
+ "xlabel('Omega_m')\n",
+ "ylabel('sigma8');"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "51gfhl9cIzMC"
+ },
+ "source": [
+ "The red dashed is our second derivation of the Fisher matrix using the jacobian, the black contour underneath is our first derivation simply taking the Hessian of the likelihood.\n",
+ "\n",
+ "They agree perfectly, and they should, because they are both analytically computed."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {
+ "colab_type": "text",
+ "id": "JrpDmbNfJUJ4"
+ },
+ "source": [
+ "## Conclusions and going further\n",
+ "\n",
+ "We have covered some of the most important points of `jax-cosmo`, feel free to \n",
+ "go through the [design document](https://github.com/DifferentiableUniverseInitiative/jax_cosmo/blob/master/design.md) for background and further explanations of how things work. You can also follow this [JAX document](https://jax.readthedocs.io/en/latest/notebooks/Common_Gotchas_in_JAX.html) to go deeper into JAX.\n",
+ "\n",
+ "\n",
+ "`jax-cosmo` is still very young and lacks many features, but hopefuly this notebook demonstrates the power of automatic differentiation, and given that the entire code is in simple Python, feel free to contribute missing features that would be necessary for your work ;-) "
+ ]
+ }
+ ],
+ "metadata": {
+ "accelerator": "GPU",
+ "colab": {
+ "include_colab_link": true,
+ "name": "jax-cosmo-intro.ipynb",
+ "provenance": [],
+ "toc_visible": true
+ },
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.8.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 1
+}
diff --git a/jax_cosmo/__init__.py b/jax_cosmo/__init__.py
index ea39c8b..b12f3c7 100644
--- a/jax_cosmo/__init__.py
+++ b/jax_cosmo/__init__.py
@@ -22,3 +22,4 @@
import jax_cosmo.transfer as transfer
from jax_cosmo.core import *
from jax_cosmo.parameters import *
+import jax_cosmo.sparse as sparse
diff --git a/jax_cosmo/angular_cl.py b/jax_cosmo/angular_cl.py
index 63db4dd..6918189 100644
--- a/jax_cosmo/angular_cl.py
+++ b/jax_cosmo/angular_cl.py
@@ -122,14 +122,19 @@ def get_noise_cl(inds):
return lax.map(get_noise_cl, cl_index)
-def gaussian_cl_covariance(ell, probes, cl_signal, cl_noise, f_sky=0.25):
+def gaussian_cl_covariance(ell, probes, cl_signal, cl_noise, f_sky=0.25, sparse=True):
"""
Computes a Gaussian covariance for the angular cls of the provided probes
+ Set sparse True to return a sparse matrix representation that uses a factor
+ of n_ell less memory and is compatible with the linear algebra operations
+ in :mod:`jax_cosmo.sparse`.
+
return_cls: (returns covariance)
"""
ell = np.atleast_1d(ell)
n_ell = len(ell)
+ one = 1.0 if sparse else np.eye(n_ell)
# Adding noise to auto-spectra
cl_obs = cl_signal + cl_noise
@@ -144,15 +149,22 @@ def gaussian_cl_covariance(ell, probes, cl_signal, cl_noise, f_sky=0.25):
def get_cov_block(inds):
a, b, c, d = inds
cov = (cl_obs[a] * cl_obs[b] + cl_obs[c] * cl_obs[d]) / norm
- return cov * np.eye(n_ell)
+ return cov * one
+ # Return a sparse representation of the matrix containing only the diagonals
+ # for each of the n_cls x n_cls blocks of size n_ell x n_ell.
+ # We could compress this further using the symmetry of the blocks, but
+ # it is easier to invert this matrix with this redundancy included.
cov_mat = lax.map(get_cov_block, cov_blocks)
# Reshape covariance matrix into proper matrix
- cov_mat = cov_mat.reshape((n_cls, n_cls, n_ell, n_ell))
- cov_mat = cov_mat.transpose(axes=(0, 2, 1, 3)).reshape(
- (n_ell * n_cls, n_ell * n_cls)
- )
+ if sparse:
+ cov_mat = cov_mat.reshape((n_cls, n_cls, n_ell))
+ else:
+ cov_mat = cov_mat.reshape((n_cls, n_cls, n_ell, n_ell))
+ cov_mat = cov_mat.transpose(axes=(0, 2, 1, 3)).reshape(
+ (n_ell * n_cls, n_ell * n_cls)
+ )
return cov_mat
@@ -163,10 +175,15 @@ def gaussian_cl_covariance_and_mean(
transfer_fn=tklib.Eisenstein_Hu,
nonlinear_fn=power.halofit,
f_sky=0.25,
+ sparse=False,
):
"""
Computes a Gaussian covariance for the angular cls of the provided probes
+ Set sparse True to return a sparse matrix representation that uses a factor
+ of n_ell less memory and is compatible with the linear algebra operations
+ in :mod:`jax_cosmo.sparse`.
+
return_cls: (returns signal + noise cl, covariance)
"""
ell = np.atleast_1d(ell)
@@ -179,6 +196,6 @@ def gaussian_cl_covariance_and_mean(
cl_noise = noise_cl(ell, probes)
# retrieve the covariance
- cov_mat = gaussian_cl_covariance(ell, probes, cl_signal, cl_noise, f_sky)
+ cov_mat = gaussian_cl_covariance(ell, probes, cl_signal, cl_noise, f_sky, sparse)
return cl_signal.flatten(), cov_mat
diff --git a/jax_cosmo/likelihood.py b/jax_cosmo/likelihood.py
index 5ad295a..27ebc4c 100644
--- a/jax_cosmo/likelihood.py
+++ b/jax_cosmo/likelihood.py
@@ -6,27 +6,60 @@
import jax.numpy as np
import jax.scipy as sp
+import jax_cosmo.sparse as sparse
from jax_cosmo.angular_cl import gaussian_cl_covariance
def gaussian_log_likelihood(data, mu, C, constant_cov=True, inverse_method="inverse"):
"""
- Computes the likelihood for some cl
+ Computes the log likelihood for a given data vector under a multivariate
+ Gaussian distribution.
+
+ If the covariance C is sparse (according to :meth:`jax_cosmo.sparse.is_sparse`)
+ use sparse inverse and determinant algorithms (and ignore ``inverse_method``).
+
+ Parameters
+ ----------
+ data: array_like
+ Data vector, with shape [N].
+
+ mu: array_like, 1d
+ Mean of the Gaussian likelihood, with shape [N].
+
+ C: array_like or sparse matrix
+ Covariance of Gaussian likelihood with shape [N,N]
+
+ constant_cov: boolean
+ Whether to include the log determinant of the covariance matrix in the
+ likelihood. If `constant_cov` is true, the log determinant is ignored
+ (default: True)
+
+ inverse_method: string
+ Methods for computing the precision matrix. Either "inverse", "cholesky".
+ Note that this option is ignored when the covariance is sparse. (default: "inverse")
"""
# Computes residuals
r = mu - data
- # TODO: check what is the fastest and works the best between cholesky+solve
- # and just inversion
- if inverse_method == "inverse":
- y = np.dot(np.linalg.inv(C), r)
- elif inverse_method == "cholesky":
- y = sp.linalg.cho_solve(sp.linalg.cho_factor(C, lower=True), r)
+ if sparse.is_sparse(C):
+ r = r.reshape(-1, 1)
+ rT_Cinv_r = sparse.dot(r.T, sparse.inv(C), r)[0, 0]
else:
- raise NotImplementedError
+ # TODO: check what is the fastest and works the best between cholesky+solve
+ # and just inversion
+ if inverse_method == "inverse":
+ y = np.dot(np.linalg.inv(C), r)
+ elif inverse_method == "cholesky":
+ y = sp.linalg.cho_solve(sp.linalg.cho_factor(C, lower=True), r)
+ else:
+ raise NotImplementedError
+ rT_Cinv_r = r.dot(y)
if constant_cov:
- return -0.5 * r.dot(y)
+ return -0.5 * rT_Cinv_r
else:
- _, logdet = np.linalg.slogdet(C)
- return -0.5 * r.dot(y) - 0.5 * logdet
+ if sparse.is_sparse(C):
+ _, logdet = sparse.slogdet(C)
+ else:
+ _, logdet = np.linalg.slogdet(C)
+ return -0.5 * (rT_Cinv_r - logdet)
diff --git a/jax_cosmo/sparse.py b/jax_cosmo/sparse.py
new file mode 100644
index 0000000..e69df7d
--- /dev/null
+++ b/jax_cosmo/sparse.py
@@ -0,0 +1,388 @@
+"""Support for sparse matrices composed of square blocks that are individually diagonal.
+
+The motivating example is a Gaussian covariance matrix computed in angular_cl.
+The sparse matrix is represented as a 3D array of shape (ny, nx, ndiag) composed
+of ny x nx square blocks of size ndiag x ndiag. The vector at [ny, nx] is the
+diagonal of the corresponding block. The memory savings is a factor of ndiag
+and most algorithms are sped up by a comparable factor.
+
+We do not assume that the corresponding dense matrix is square or symmetric, even
+though a covariance has these properties, since this streamlines the implementation
+for a relatively small (factor of 2) increase in memory.
+
+This sparse format is not one of those currently supported by scipy.sparse.
+The scipy.sparse dia format has a similar memory efficiency but does not take
+advantage of the block structure we exploit here for efficient operations.
+
+For dot products involving a sparse matrix, use :func:`dot` to automatically
+select the correct jit-compiled algorithm, with some input validation. All
+pairs of vector, dense matrix and at least one sparse matrix are
+supported. The special bilinear form (dense, sparse, dense) is also supported.
+
+You can also use the lower-level algorithms (with no input validation) directly:
+ - :fun:`sparse_dot_vec`
+ - :fun:`sparse_dot_dense`
+ - :fun:`vec_dot_sparse`
+ - :fun:`dense_dot_sparse`
+ - :fun:`sparse_dot_sparse`
+ - :fun:`dense_dot_sparse_dot_dense`
+"""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import functools
+
+import jax.numpy as np
+from jax import jit
+from jax import vmap
+
+
+def is_sparse(sparse):
+ """Test if the input is interpretable as a sparse matrix.
+ """
+ return np.asarray(sparse).ndim == 3
+
+
+def check_sparse(sparse, square=False):
+ """Check for a valid sparse matrix.
+ """
+ sparse = np.asarray(sparse)
+ if sparse.ndim != 3:
+ raise ValueError("Expected 3D array of sparse diagonals.")
+ if square and (sparse.shape[0] != sparse.shape[1]):
+ raise ValueError("Expected a square matrix.")
+ return sparse
+
+
+@jit
+def to_dense(sparse):
+ """Convert a sparse matrix to its dense equivalent.
+
+ Parameters
+ ----------
+ sparse : array
+ 3D array of shape (a, b, ndiag) of block diagonal elements.
+
+ Returns
+ -------
+ array
+ 2D array of shape (a * ndiag, b * ndiag) with the same dtype
+ as the input array.
+ """
+ sparse = check_sparse(sparse)
+ return np.vstack(vmap(lambda row: np.hstack(vmap(np.diag)(row)))(sparse))
+
+
+@jit
+def dot(*args):
+ """Calculate A @ B where at least one of A or B is sparse.
+
+ All combinations of vector, dense matrix and at least one
+ sparse matrix are supported. The bilinear form A @ B @ C is
+ also supported where A and C are dense and B is sparse.
+
+ Checks the inputs and calls the appropriate *_dot_* specialized
+ jit-compiled method defined below. Input types are identified
+ by their array dimension: 1 = vector, 2 = dense matrix,
+ 3 = sparse matrix.
+
+ Returns a dense 1D or 2D array except where A and B are both
+ sparse matrices, when the result is also a sparse matrix.
+
+ Parameters
+ ----------
+ args
+ 2 or 3 arrays to multiply.
+
+ Returns
+ -------
+ array
+ Result of A @ B or A @ B @ C.
+ """
+ if len(args) == 2:
+ A, B = args
+ A = np.asarray(A)
+ B = np.asarray(B)
+ if is_sparse(A):
+ Acols = A.shape[1] * A.shape[2]
+ else:
+ if A.ndim < 1 or A.ndim > 2:
+ raise ValueError(f"A has invalid dimension {A.ndim} (expected 1 or 2).")
+ Acols = A.shape[-1]
+ if is_sparse(B):
+ Brows = B.shape[0] * B.shape[2]
+ else:
+ if B.ndim < 1 or B.ndim > 2:
+ raise ValueError(f"B has invalid dimension {B.ndim} (expected 1 or 2).")
+ Brows = B.shape[0]
+ if Acols != Brows:
+ raise ValueError(
+ f"Shapes of A {A.shape} and B {B.shape} not compatible for dot product."
+ )
+ if is_sparse(A):
+ if is_sparse(B):
+ return sparse_dot_sparse(A, B)
+ else:
+ return sparse_dot_vec(A, B) if B.ndim == 1 else sparse_dot_dense(A, B)
+ else:
+ return vec_dot_sparse(A, B) if A.ndim == 1 else dense_dot_sparse(A, B)
+ elif len(args) == 3:
+ A, B, C = args
+ if A.ndim != 2 or B.ndim != 3 or C.ndim != 2:
+ raise ValueError("Can only handle dense @ sparse @ dense bilinear form.")
+ if (
+ A.shape[1] != B.shape[0] * B.shape[2]
+ or B.shape[1] * B.shape[2] != C.shape[0]
+ ):
+ raise ValueError(
+ "Shapes of A {A.shape}, B {B.shape}, C {C.shape} not compatible for dot product."
+ )
+ return dense_dot_sparse_dot_dense(A, B, C)
+ else:
+ raise ValueError(f"Expected 2 or 3 input arrays but got {len(args)}.")
+
+
+@jit
+def sparse_dot_vec(sparse, vec):
+ """Calculate M @ v where M is a sparse matrix.
+
+ Inputs must be jax numpy arrays. No error checking is performed.
+ Use :func:`dot` for a more convenient front-end with error checking.
+
+ Parameters
+ ----------
+ sparse : array
+ 3D array of shape (a, b, ndiag) of block diagonal elements.
+ vec : array
+ 1D array of shape (b * ndiag).
+
+ Returns
+ -------
+ array
+ 1D array of shape (a * ndiag).
+ """
+ return vmap(
+ lambda row, vec: np.sum(vmap(np.multiply)(row, vec.reshape(row.shape)), axis=0),
+ in_axes=(0, None),
+ )(sparse, vec).reshape(-1)
+
+
+@jit
+def sparse_dot_dense(sparse, dense):
+ """Calculate A @ B where A is sparse and B is dense and return dense.
+
+ Inputs must be jax numpy arrays. No error checking is performed.
+ Use :func:`dot` for a more convenient front-end with error checking.
+
+ Parameters
+ ----------
+ sparse : array
+ 3D array of shape (a, b, ndiag) of block diagonal elements.
+ dense : array
+ 2D array of shape (b * ndiag, c).
+
+ Returns
+ -------
+ array
+ 2D array of shape (a * ndiag, c).
+ """
+ return vmap(sparse_dot_vec, (None, 1), 1)(sparse, dense)
+
+
+@jit
+def vec_dot_sparse(vec, sparse):
+ """Calculate vec @ M where M is a sparse matrix.
+
+ Inputs must be jax numpy arrays. No error checking is performed.
+ Use :func:`dot` for a more convenient front-end with error checking.
+
+ Parameters
+ ----------
+ vec : array
+ 1D array of shape (a * ndiag).
+ sparse : array
+ 3D array of shape (a, b, ndiag) of block diagonal elements.
+
+ Returns
+ -------
+ array
+ 1D array of shape (b * ndiag).
+ """
+ return vmap(
+ lambda vec, col: np.sum(vmap(np.multiply)(vec.reshape(col.shape), col), axis=0),
+ in_axes=(None, 1),
+ )(vec, sparse).reshape(-1)
+
+
+@jit
+def dense_dot_sparse(dense, sparse):
+ """Calculate A @ B where A is dense and B is sparse and return dense.
+
+ Inputs must be jax numpy arrays. No error checking is performed.
+ Use :func:`dot` for a more convenient front-end with error checking.
+
+ Parameters
+ ----------
+ dense : array
+ 2D array of shape (a * ndiag, b * ndiag).
+ sparse : array
+ 3D array of shape (b, c, ndiag) of block diagonal elements.
+
+ Returns
+ -------
+ array
+ 2D array of shape (a * ndiag, c * ndiag).
+ """
+ return vmap(vec_dot_sparse, (0, None), 0)(dense, sparse)
+
+
+@jit
+def sparse_dot_sparse(sparse1, sparse2):
+ """Calculate A @ B where A and B are both sparse and return sparse.
+
+ Inputs must be jax numpy arrays. No error checking is performed.
+ Use :func:`dot` for a more convenient front-end with error checking.
+
+ Parameters
+ ----------
+ sparse1 : array
+ 3D array of shape (a, b, ndiag) of block diagonal elements.
+ sparse2 : array
+ 3D array of shape (b, c, ndiag) of block diagonal elements.
+
+ Returns
+ -------
+ array
+ 3D array of shape (a, c, ndiag) of block diagonal elements.
+ """
+ return vmap(
+ # Sparse multiply row @ col
+ vmap(
+ # Sparse multiply blocks B1 and B2
+ lambda B1, B2: np.sum(np.multiply(B1, B2), axis=0),
+ (0, None),
+ 0,
+ ),
+ (None, 1),
+ 1,
+ )(sparse1, sparse2)
+
+
+@jit
+def dense_dot_sparse_dot_dense(X, Y, Z):
+ """Calculate the bilinear form X @ Y @ Z where B is sparse.
+
+ Inputs must be jax numpy arrays. No error checking is performed.
+
+ Parameters
+ ----------
+ X : array
+ 2D array of shape (a, b * ndiag) with dense matrix elements.
+ Y : array
+ 3D array of shape (b, c, ndiag) with sparse matrix elements.
+ Z : array
+ 2D array of shape (c * ndiag, d) with dense matrix elements.
+
+ Returns
+ -------
+ array
+ 2D array of shape (a, d) with dense matrix elements.
+ """
+ return vmap(
+ vmap(
+ lambda row, sparse, col: np.dot(row, sparse_dot_vec(sparse, col)),
+ (None, None, 1),
+ ),
+ (0, None, None),
+ )(X, Y, Z)
+
+
+@jit
+def inv(sparse):
+ """Calculate the inverse of a square matrix in sparse format.
+
+ We currently assume that the matrix is invertible and you should not
+ trust the answer unless you know this is true (because jax.numpy.linalg.inv
+ has this behavior).
+
+ Parameters
+ ----------
+ sparse : array
+ 3D array of shape (n, n, ndiag) of block diagonal elements.
+
+ Returns
+ -------
+ array
+ 3D array of shape (n, n, ndiag) of block diagonal elements
+ representing the inverse matrix.
+ """
+ sparse = check_sparse(sparse, square=True)
+ return np.transpose(np.linalg.inv(np.transpose(sparse, (2, 0, 1))), (1, 2, 0))
+
+
+# We split the determinant calculation for a matrix with N x N blocks
+# into n pieces that can be evaluated in parallel, following eqn (2.2)
+# of https://arxiv.org/abs/1112.4379. First build a helper function
+# to calculate one piece indexed by 0 <= k < N:
+@functools.partial(jit, static_argnums=(1, 2, 3))
+def _block_det(sparse, k, N, P):
+ u = sparse[k : k + 1, k + 1 : N, 0:P]
+ S = sparse[k + 1 : N, k + 1 : N, 0:P]
+ v = sparse[k + 1 : N, k : k + 1, 0:P]
+ Sinv_v = sparse_dot_sparse(inv(S), v)
+ M = sparse[k, k] - sparse_dot_sparse(u, Sinv_v)
+ sign = np.product(np.sign(M))
+ logdet = np.sum(np.log(np.abs(M)))
+ return sign, logdet
+
+
+@jit
+def slogdet(sparse):
+ """Calculate the log(determinant) of a sparse matrix.
+
+ Based on equation (2.2) of https://arxiv.org/abs/1112.4379
+
+ Parameters
+ ----------
+ sparse : array
+ 3D array of shape (ny, nx, ndiag) of block diagonal elements.
+
+ Returns
+ -------
+ tuple
+ Tuple (sign, logdet) such that sign * exp(logdet) is the
+ determinant. If the determinant is zero, logdet = -inf.
+ """
+ sparse = check_sparse(sparse, square=True)
+ N, _, P = sparse.shape
+ sign = np.product(np.sign(sparse[-1, -1]))
+ logdet = np.sum(np.log(np.abs(sparse[-1, -1])))
+ # The individual blocks can be calculated in any order so there
+ # should be a better way to express this using lax.map but I
+ # can't get it to work without "concretization" errors.
+ for i in range(N - 1):
+ s, ld = _block_det(sparse, i, N, P)
+ sign *= s
+ logdet += ld
+ return sign, logdet
+
+
+@jit
+def det(sparse):
+ """Calculate the determinant of a sparse matrix.
+
+ Uses :func:`slogdet`.
+
+ Parameters
+ ----------
+ sparse : array
+ 3D array of shape (ny, nx, ndiag) of block diagonal elements.
+
+ Returns
+ -------
+ float
+ Determinant result.
+ """
+ sign, logdet = slogdet(sparse)
+ return sign * np.exp(logdet)
diff --git a/tests/test_angular_cl.py b/tests/test_angular_cl.py
index 96a2704..7390407 100644
--- a/tests/test_angular_cl.py
+++ b/tests/test_angular_cl.py
@@ -2,14 +2,17 @@
import numpy as np
import pyccl as ccl
from numpy.testing import assert_allclose
+from numpy.testing import assert_array_equal
import jax_cosmo.background as bkgrd
from jax_cosmo import Cosmology
from jax_cosmo import probes
from jax_cosmo.angular_cl import angular_cl
+from jax_cosmo.angular_cl import gaussian_cl_covariance
from jax_cosmo.bias import constant_linear_bias
from jax_cosmo.bias import inverse_growth_linear_bias
from jax_cosmo.redshift import smail_nz
+from jax_cosmo.sparse import to_dense
def test_lensing_cl():
@@ -143,3 +146,18 @@ def test_clustering_cl():
cl_jax = angular_cl(cosmo_jax, ell, [tracer_jax])
assert_allclose(cl_ccl, cl_jax[0], rtol=1e-2)
+
+
+def test_sparse_cov():
+ n_ell = 25
+ ell = jnp.logspace(1, 3, n_ell)
+ nz1 = smail_nz(1.0, 2.0, 1.0)
+ nz2 = smail_nz(1.0, 2.0, 0.5)
+ n_cls = 3
+ P = [probes.NumberCounts([nz1, nz2], constant_linear_bias(1.0))]
+ cl_signal = jnp.ones((n_cls, n_ell))
+ cl_noise = jnp.ones_like(cl_signal)
+ cov_dense = gaussian_cl_covariance(ell, P, cl_signal, cl_noise, sparse=False)
+ cov_sparse = gaussian_cl_covariance(ell, P, cl_signal, cl_noise, sparse=True)
+ assert cov_sparse.shape == (n_cls, n_cls, n_ell)
+ assert_array_equal(to_dense(cov_sparse), cov_dense)
diff --git a/tests/test_likelihood.py b/tests/test_likelihood.py
new file mode 100644
index 0000000..9a950f8
--- /dev/null
+++ b/tests/test_likelihood.py
@@ -0,0 +1,33 @@
+import jax.numpy as jnp
+from numpy.testing import assert_allclose
+from numpy.testing import assert_array_equal
+
+from jax_cosmo import Planck15
+from jax_cosmo import probes
+from jax_cosmo.angular_cl import gaussian_cl_covariance_and_mean
+from jax_cosmo.bias import constant_linear_bias
+from jax_cosmo.likelihood import gaussian_log_likelihood
+from jax_cosmo.redshift import smail_nz
+from jax_cosmo.sparse import to_dense
+
+
+def test_gaussian_log_likelihood():
+ n_ell = 5
+ ell = jnp.logspace(1, 3, n_ell)
+ nz1 = smail_nz(1.0, 2.0, 1.0)
+ nz2 = smail_nz(1.0, 2.0, 0.5)
+ n_cls = 3
+ P = [probes.NumberCounts([nz1, nz2], constant_linear_bias(1.0))]
+ cosmo = Planck15()
+ mu, cov_sparse = gaussian_cl_covariance_and_mean(cosmo, ell, P, sparse=True)
+ cov_dense = to_dense(cov_sparse)
+ data = 1.1 * mu
+ for constant_cov in (True, False):
+ loglike_sparse = gaussian_log_likelihood(
+ data, mu, cov_sparse, constant_cov=constant_cov
+ )
+ for method in "inverse", "cholesky":
+ loglike_dense = gaussian_log_likelihood(
+ data, mu, cov_dense, constant_cov=constant_cov, inverse_method=method
+ )
+ assert_allclose(loglike_sparse, loglike_dense, rtol=1e-6)
diff --git a/tests/test_sparse.py b/tests/test_sparse.py
new file mode 100644
index 0000000..3fe213d
--- /dev/null
+++ b/tests/test_sparse.py
@@ -0,0 +1,85 @@
+import jax.numpy as jnp
+import numpy as numpy
+from numpy.testing import assert_allclose
+from numpy.testing import assert_array_equal
+from numpy.testing import assert_raises
+
+from jax_cosmo.sparse import *
+
+
+def test_to_dense():
+ X_sparse = jnp.array(
+ [[[1, 2, 3], [4, 5, 6], [-1, -2, -3]], [[1, 2, 3], [-4, -5, -6], [7, 8, 9]]]
+ )
+ X_dense = to_dense(X_sparse)
+ X_answer = jnp.array(
+ [
+ [1, 0, 0, 4, 0, 0, -1, 0, 0],
+ [0, 2, 0, 0, 5, 0, 0, -2, 0],
+ [0, 0, 3, 0, 0, 6, 0, 0, -3],
+ [1, 0, 0, -4, 0, 0, 7, 0, 0],
+ [0, 2, 0, 0, -5, 0, 0, 8, 0],
+ [0, 0, 3, 0, 0, -6, 0, 0, 9],
+ ]
+ )
+ assert_array_equal(X_dense, X_answer)
+
+ with assert_raises(ValueError):
+ to_dense([1, 2, 3])
+
+ with assert_raises(ValueError):
+ to_dense(jnp.ones((2, 3, 4, 5)))
+
+
+def test_dot():
+ X1 = [[[1.0, 2], [3, 4], [5, 6]], [[4, 5], [6, 7], [8, 9]]]
+ X2 = [[[1.0, -2], [3, -4]], [[5, 4], [6, -7]], [[5, 6], [9, 8]]]
+ X1d = to_dense(X1)
+ X2d = to_dense(X2)
+ v1 = np.arange(6)
+ v2 = np.arange(4)
+
+ assert_allclose(X2d @ v2, dot(X2, v2))
+ assert_allclose(X1d @ v1, dot(X1, v1))
+ assert_allclose(v2 @ X1d, dot(v2, X1))
+ assert_allclose(v1 @ X2d, dot(v1, X2))
+ assert_allclose(X1d @ X2d, dot(X1, X2d))
+ assert_allclose(X1d @ X2d, dot(X1d, X2))
+ assert_allclose(X1d @ X2d, to_dense(dot(X1, X2)))
+ assert_allclose(X2d @ X1d, to_dense(dot(X2, X1)))
+
+
+def test_bilinear():
+ X1 = [[[1.0, 2], [3, 4], [5, 6]], [[4, 5], [6, 7], [8, 9]]]
+ X2 = [[[1.0, -2], [3, -4]], [[5, 4], [6, -7]], [[5, 6], [9, 8]]]
+ X1d = to_dense(X1)
+ X2d = to_dense(X2)
+ X12 = dot(X2, X1)
+ X21 = dot(X1, X2)
+ X12d = X2d @ X1d
+ X21d = X1d @ X2d
+ assert_allclose(X1d @ X12d @ X2d, dot(X1d, X12, X2d))
+ assert_allclose(X2d @ X21d @ X1d, dot(X2d, X21, X1d))
+
+
+def test_inv():
+ X_sparse = jnp.array([[[1.0, 1.0], [1.0, 1.0]], [[1.0, 1.0], [2.0, 2.0]]])
+ X_inv_sparse = inv(X_sparse)
+ X_answer = jnp.array([[[2.0, 2.0], [-1.0, -1.0]], [[-1.0, -1.0], [1.0, 1.0]]])
+ assert_allclose(X_inv_sparse, X_answer)
+
+ with assert_raises(ValueError):
+ inv(jnp.ones((2, 3, 4)))
+
+
+def test_det():
+ X = np.array(
+ [
+ [[1, 2, 3], [4, 5, 6], [-1, 7, -2]],
+ [[1, 2, 3], [-4, -5, -6], [2, -3, 9]],
+ [[7, 8, 9], [5, -4, 6], [-3, -2, -1]],
+ ]
+ )
+ assert_array_equal(-det(-X), det(X))
+ assert_array_equal(det(0.0 * X), 0.0)
+ assert_allclose(det(X), np.linalg.det(to_dense(X)), rtol=1e-6)