### Setup Gaussian Model Class Instance Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Initializes an instance of the `GaussianLikelihood` class with specified dimensions and parameter bounds. This sets up the model for which the sampler will be used. ```python ndim = 20 pmin, pmax = 0.0, 10.0 glo = GaussianLikelihood(ndim=ndim, pmin=pmin, pmax=pmax) ``` -------------------------------- ### Install Open MPI on macOS and Debian Source: https://github.com/nanograv/ptmcmcsampler/blob/master/README.md Commands to install the Open MPI library, an alternative prerequisite for MPI support in PTMCMCSampler, on macOS using Homebrew and Debian-based Linux distributions using apt. ```bash # mac brew install open-mpi # debian sudo apt install libopenmpi-dev ``` -------------------------------- ### Setup PTMCMCSampler Instance Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Initializes the `PTMCSampler.PTSampler` with the number of dimensions, likelihood function, prior function, initial covariance matrix, and an output directory for chains. This prepares the sampler for running. ```python sampler = PTMCMCSampler.PTSampler(ndim, glo.lnlikefn, glo.lnpriorfn, np.copy(cov), outDir='./chains') ``` -------------------------------- ### Install PTMCMCSampler via pip Source: https://github.com/nanograv/ptmcmcsampler/blob/master/README.md Standard installation of the PTMCMCSampler package using pip. Includes an option to install with MPI support. ```bash pip install ptmcmcsampler # for MPI support use pip install ptmcmcsampler[mpi] ``` -------------------------------- ### Install MPICH on macOS and Debian Source: https://github.com/nanograv/ptmcmcsampler/blob/master/README.md Commands to install the MPICH library, a prerequisite for MPI support in PTMCMCSampler, on macOS using Homebrew and Debian-based Linux distributions using apt. ```bash # mac brew install mpich # debian sudo apt install mpich ``` -------------------------------- ### Setup Sampler with Gradient Functions Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Initializes the PTMCMCSampler with gradient-enabled likelihood and prior functions. It requires the number of dimensions, likelihood and prior functions (and their gradients), and an initial covariance matrix. The output directory is also specified. ```python import numpy as np from PTMCMCSampler import PTMCMCSampler # Define likelihood and prior functions (and their gradients) def lnlike(x): # Example likelihood function return -0.5 * np.sum(x**2) def lnprior(x): # Example prior function return 0.0 if np.all(np.abs(x) < 10) else -np.inf def lnlike_grad(x): # Example gradient of likelihood return -x def lnprior_grad(x): # Example gradient of prior return np.zeros_like(x) ndim = 10 cov = np.eye(ndim) * 1.0 sampler = PTMCMCSampler.PTSampler( ndim, lnlike, lnprior, cov, logl_grad=lnlike_grad, # Gradient-enabled likelihood logp_grad=lnprior_grad, # Gradient-enabled prior outDir="./chains" ) p0 = np.random.randn(ndim) # Run the sampler sampler.sample( p0, Niter=50000, burn=5000, thin=10, NUTSweight=20, HMCweight=20, MALAweight=0, HMCstepsize=0.1, HMCsteps=300, SCAMweight=10, AMweight=10, DEweight=10 ) ``` -------------------------------- ### Install GitHub Version of acor Source: https://github.com/nanograv/ptmcmcsampler/blob/master/README.md Command to install the latest development version of the 'acor' library from GitHub using pip. This is recommended for Python 3 kernels when using the sampler's correlation length calculation feature. ```bash pip install git+https://github.com/dfm/acor.git@master ``` -------------------------------- ### Install PTMCMCSampler via conda Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Installs the PTMCMCSampler library using conda. For MPI support, `mpi4py` must also be installed. ```bash # Basic installation conda install -c conda-forge ptmcmcsampler # With MPI support conda install -c conda-forge ptmcmcsampler mpi4py ``` -------------------------------- ### Install PTMCMCSampler via conda Source: https://github.com/nanograv/ptmcmcsampler/blob/master/README.md Installation of the PTMCMCSampler package from the conda-forge channel. Includes instructions for installing with MPI support using mpi4py. ```bash conda install -c conda-forge ptmcmcsampler # for MPI support use conda install -c conda-forge ptmcmcsampler mpi4py ``` -------------------------------- ### Run PTMCMCSampler Script with MPI Source: https://github.com/nanograv/ptmcmcsampler/blob/master/README.md Example command to execute a Python script containing PTMCMCSampler with MPI support. The `-np` flag specifies the number of temperature chains to run. ```bash mpirun -np script.py ``` -------------------------------- ### Verify Likelihood Gradients with Numdifftools Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/curved_likelihood.ipynb Demonstrates the accuracy of the implemented likelihood gradients by comparing them against gradients computed using `numdifftools`. It initializes a starting point `p0`, calculates the analytical gradient using `cl.lnlikefn_grad`, and the numerical gradient using `nd.Jacobian`. ```python # Demonstrate that the gradients are accurate p0 = np.array([-0.1, -0.5]) # np.array([-0.07943648, -0.63131195]) # np.random.randn(2) ndjac = nd.Jacobian(cl.lnlikefn) ndhess = nd.Hessian(cl.lnlikefn) print(p0) print(cl.lnlikefn_grad(p0)[1]) print(ndjac(p0)) ``` -------------------------------- ### Initialize Gaussian Likelihood and Transform (Python) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Initializes a Gaussian likelihood object and applies an interval transform. This setup is used for defining the probability distributions and their transformations within the sampler. ```python ndim = 40 glo = GaussianLikelihood(ndim=ndim, pmin=0.0, pmax=10.0) glt = intervalTransform(glo, pmin=0.0, pmax=10) gl = glt ``` -------------------------------- ### Run PTMCMC Sampler Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/curved_likelihood.ipynb Executes the MCMC sampling process using the initialized `PTMCMCSampler`. It specifies the starting position `p0`, the total number of samples, burn-in period, and thinning interval. Various jump proposal weights (SCAM, AM, DE, NUTS, HMC) and HMC parameters are also set. ```python sampler.sample(p0, 100000, burn=10000, thin=1, SCAMweight=10, AMweight=10, DEweight=10, NUTSweight=10, HMCweight=10, MALAweight=0, HMCsteps=50, HMCstepsize=0.08) ``` -------------------------------- ### Initialize Sampler Start Position and Covariance Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Sets the initial position `p0` for the MCMC sampler by drawing random uniform values within the defined parameter bounds. It also initializes the jump covariance matrix `cov` with small diagonal values. ```python # Set the start position and the covariance p0 = np.random.uniform(pmin, pmax, ndim) cov = np.eye(ndim) * 0.1**2 ``` -------------------------------- ### Get Jump Statistics Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Retrieves and plots the acceptance rates for different jump proposals used during the sampling process. It uses `glob` to find jump files and `matplotlib` to visualize the acceptance rates over time. ```python jumpfiles = glob.glob('chains/*jump.txt') jumps = map(np.loadtxt, jumpfiles) for ct, j in enumerate(jumps): plt.plot(j, label=jumpfiles[ct].split('/')[-1].split('_jump.txt')[0]) plt.legend(loc='best', frameon=False) plt.ylabel('Acceptance Rate') plt.ylim(0.0, 1.1) ``` -------------------------------- ### Run MCMC Sampler with sample() Method in Python Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Shows how to run the PTMCMC sampler using the `sample()` method with detailed parameter control. This includes setting the number of iterations, temperature ladder, burn-in, thinning, and adaptive covariance updates. ```python import numpy as np from PTMCMCSampler import PTMCMCSampler # Setup problem ndim = 10 mu = np.zeros(ndim) icov = np.eye(ndim) def lnlike(x): diff = x - mu return -0.5 * np.dot(diff, np.dot(icov, diff)) def lnprior(x): if np.all(np.abs(x) < 20): return 0.0 return -np.inf # Initialize sampler cov = np.eye(ndim) * 0.5**2 sampler = PTMCMCSampler.PTSampler(ndim, lnlike, lnprior, cov, outDir="./chains") # Run with full parameter control p0 = np.random.randn(ndim) sampler.sample( p0, # Initial parameter vector Niter=50000, # Total number of iterations ladder=None, # Custom temperature ladder (None = auto-generate) Tmin=1, # Minimum temperature Tmax=None, # Maximum temperature (None = auto-calculate) Tskip=100, # Steps between temperature swap attempts isave=1000, # Write to file every isave samples covUpdate=1000, # Update covariance every N iterations SCAMweight=20, # Weight for Single Component Adaptive Metropolis AMweight=20, # Weight for Adaptive Metropolis DEweight=20, # Weight for Differential Evolution burn=10000, # Burn-in iterations (DE starts after this) thin=10 # Record every thin-th sample ) # Output files: # ./chains/chain_1.0.txt - Main chain (T=1) # ./chains/cov.npy - Final covariance matrix # ./chains/jumps.txt - Jump proposal statistics ``` -------------------------------- ### Initialize PTSampler Class in Python Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Demonstrates the initialization of the `PTSampler` class in Python. This involves defining log-likelihood and log-prior functions, and setting up the initial sampler parameters like dimensionality and covariance matrix. ```python import numpy as np from PTMCMCSampler import PTMCMCSampler # Define log-likelihood function def log_likelihood(x): """Gaussian log-likelihood centered at origin.""" return -0.5 * np.sum(x**2) # Define log-prior function (uniform prior) def log_prior(x): """Uniform prior on [-10, 10]^ndim.""" if np.all(x >= -10) and np.all(x <= 10): return 0.0 return -np.inf # Setup sampler ndim = 5 cov = np.eye(ndim) * 0.1**2 # Initial proposal covariance sampler = PTMCMCSampler.PTSampler( ndim, # Number of dimensions log_likelihood, # Log-likelihood function log_prior, # Log-prior function cov, # Initial covariance matrix outDir="./chains", # Output directory for chain files verbose=True, # Print progress updates resume=False # Resume from previous run ) # Initial parameter vector p0 = np.random.uniform(-5, 5, ndim) # Run sampler sampler.sample( p0, Niter=100000, # Number of iterations burn=10000, # Burn-in period thin=10 # Thinning factor ) # Output: Chain files written to ./chains/chain_1.0.txt ``` -------------------------------- ### Build and Run PTMCMCSampler Docker Image (Development) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/README.md Docker commands to build a development image of PTMCMCSampler, including all dependencies, and then run the container with the working directory mounted. ```bash # Build the image docker build --pull -t ptmcmc --build-arg "TARGET_ENV=dev" --no-cache . # Run the image, mounting the working directory on the host OS to /code/ inside the container. # MPI won't work if we run as the root user (the default). docker run -it --rm --user mcmc_user -v $(pwd)/:/code ptmcmc # Exit back to host OS CTRL-D ``` -------------------------------- ### Build and Run PTMCMCSampler Docker Image (Production) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/README.md Docker commands to build a production image of PTMCMCSampler, optionally including MPI and acor support, and then run the container with a mounted data directory. ```bash # Build the image, tagging it as `ptmcmc:latest`. # # This example includes both optional MPI support and the optional `acor` library # (you can omit either / both). docker build --pull --build-arg "MPI=1" --build-arg "ACOR=1" -t ptmcmc --no-cache . # Run the image, mounting the `data/` subdirectory on your computer # to `/code/data/` inside the Docker container. Note that MPI won't work # if we run as the root user (the default). docker run -it --rm --user mcmc_user -v $(pwd)/data:/code/data ptmcmc # When finished with the container, exit back to the host OS CTRL^D ``` -------------------------------- ### Initialize PTMCMCSampler Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/curved_likelihood.ipynb Initializes the `PTMCMCSampler.PTSampler` for parallel tempering MCMC. It takes the number of dimensions, log-likelihood function, log-prior function, an initial covariance matrix, and optionally gradient functions. The `outDir` specifies the directory to save chain files. ```python # Start position & covariance based on ML & Hessian (for Hessian, use stepsize = 0.045) p0 = result['x'] h0 = ndhess(p0) cov = sl.cho_solve(sl.cho_factor(-h0), np.eye(len(h0))) # Hessian not the best option for this multi-modal problem. Use custom value: cov = np.diag([1.0, 1.0]) sampler = PTMCMCSampler.PTSampler(2, cl.lnlikefn, cl.lnpriorfn, np.copy(cov), logl_grad=cl.lnlikefn_grad, logp_grad=cl.lnpriorfn_grad, outDir='./chains') ``` -------------------------------- ### Initialize PTMCMCSampler (Python) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Initializes the `PTMCMCSampler.PTSampler` with the specified dimensions, likelihood function, prior function, initial covariance, and gradient functions. It also sets the output directory for chain files. ```python sampler = PTMCMCSampler.PTSampler(ndim, gl.lnlikefn, gl.lnpriorfn, np.copy(cov), logl_grad=gl.lnlikefn_grad, logp_grad=gl.lnpriorfn_grad, outDir='./chains') ``` -------------------------------- ### Prepare Release: Update Local Repository and Run Tests (Bash) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/RELEASE.md This snippet ensures the local 'master' branch is up-to-date with the remote repository and runs local tests using 'make test'. It's a crucial first step before creating a release tag to verify the code's stability. ```bash git checkout master git pull origin master make test ``` -------------------------------- ### Verify Gradients and Hessians with Numerical Differentiation (Python) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Demonstrates the accuracy of analytical gradients and Hessians by comparing them with numerical approximations using the `numdifftools` library. It prints the first few elements of the initial parameters, analytical gradient, numerical Jacobian, analytical Hessian diagonal, and numerical Hessian diagonal. ```python # Demonstrate that the gradients are accurate p0 = np.ones(ndim)*0.01 ndjac = nd.Jacobian(gl.lnlikefn) ndhes = nd.Hessian(gl.lnlikefn) ndhesd = nd.Hessdiag(gl.lnlikefn) print(p0[:4]) print(gl.lnlikefn_grad(p0)[1][:4]) print(ndjac(p0)[:4]) print(np.diag(gl.hessian(p0))[:4]) print(ndhesd(p0)[:4]) ``` -------------------------------- ### Run PTMCMCSampler (Python) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Executes the PTMCMCSampler with a specified number of steps and burn-in period. It configures various jump proposal methods (DE, AM, SCAM, NUTS, HMC) with their respective weights and parameters. The output includes warnings about covariance selection and acceptance rates. ```python sampler.sample(p0, 60000, burn=500, thin=1, covUpdate=500, SCAMweight=10, AMweight=10, DEweight=10, NUTSweight=10, HMCweight=10, MALAweight=0, HMCsteps=100, HMCstepsize=0.4) ``` -------------------------------- ### Run PTMCMCSampler Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Executes the PTMCMCSampler for a specified number of steps. Parameters like `burn`, `thin`, `covUpdate`, and weights for different proposal types (`SCAMweight`, `AMweight`, `DEweight`) can be configured. ```python sampler.sample(p0, 100000, burn=500, thin=1, covUpdate=500, SCAMweight=20, AMweight=20, DEweight=20) ``` -------------------------------- ### Create and Push Git Tag for Release (Bash) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/RELEASE.md This command sequence creates a new git tag for the release (e.g., 'v2.1.3') and pushes it to the remote repository. This tag is essential for identifying specific release versions and is used in subsequent release steps. ```bash git tag v2.1.3 git push origin v2.1.3 ``` -------------------------------- ### Load and Plot MCMC Chain Data Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/curved_likelihood.ipynb Loads the generated MCMC chain data from 'chains/chain_1.txt' using `np.loadtxt`. It then uses the `corner` library to create a corner plot of the first two dimensions of the chain, with 50 bins for visualization. ```python data = np.loadtxt('chains/chain_1.txt') corner.corner(data[:,:2], bins=50); ``` -------------------------------- ### Running Parallel Tempering with MPI Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Configures and runs the PTMCMCSampler using MPI for parallel execution across multiple processes, each running a chain at a different temperature. It requires the mpi4py library and involves passing the MPI communicator to the sampler. Temperature swaps are attempted periodically. ```python #!/usr/bin/env python """ Save as: run_parallel.py Run with: mpirun -np 4 python run_parallel.py """ import numpy as np from mpi4py import MPI from PTMCMCSampler import PTMCMCSampler # MPI communicator comm = MPI.COMM_WORLD rank = comm.Get_rank() nprocs = comm.Get_size() # Define problem ndim = 15 def lnlike(x): # Multi-modal likelihood with two peaks peak1 = -0.5 * np.sum((x - 3)**2) peak2 = -0.5 * np.sum((x + 3)**2) return np.logaddexp(peak1, peak2) def lnprior(x): return 0.0 if np.all(np.abs(x) < 10) else -np.inf # Setup sampler with MPI communicator cov = np.eye(ndim) * 0.5**2 sampler = PTMCMCSampler.PTSampler( ndim, lnlike, lnprior, cov, comm=comm, # Pass MPI communicator outDir="./chains" ) # Initial position (each chain starts at same point) p0 = np.zeros(ndim) # Run parallel tempering # Temperature ladder auto-generated: T = [1.0, T1, T2, ...] for nprocs chains sampler.sample( p0, Niter=100000, Tmin=1.0, # Minimum temperature (coldest chain) Tmax=100.0, # Maximum temperature (hottest chain) Tskip=100, # Attempt swap every 100 iterations burn=10000, thin=10, writeHotChains=True # Also write hot chain outputs ) # Output: ./chains/chain_1.0.txt (T=1, main results) # ./chains/chain_X.Y.txt (hot chains if writeHotChains=True) ``` -------------------------------- ### Import Libraries for PTMCMCSampler Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Imports necessary libraries for running the PTMCMCSampler, including numpy for numerical operations, matplotlib for plotting, corner for corner plots, glob for file searching, and the PTMCMCSampler itself. The `%matplotlib inline` command is specific to environments like Jupyter notebooks. ```python import numpy as np import matplotlib.pylab as plt import corner import glob from PTMCMCSampler import PTMCMCSampler %matplotlib inline ``` -------------------------------- ### Import Libraries for PTMCMCSampler Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/curved_likelihood.ipynb Imports necessary libraries for numerical operations, plotting, MCMC sampling, and optimization. It includes numpy, matplotlib, corner, numdifftools, glob, scipy, and the PTMCMCSampler itself. The %matplotlib inline command is used for displaying plots directly in the notebook. ```python import numpy as np import matplotlib.pylab as plt import corner import numdifftools as nd import glob import scipy.optimize as so import scipy.linalg as sl from PTMCMCSampler import PTMCMCSampler %matplotlib inline ``` -------------------------------- ### Resuming Sampling from Previous Chains Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Allows resuming a PTMCMCSampler run from existing chain files by setting the `resume` parameter to `True` during sampler initialization. This is useful for extending sampling or recovering from interruptions. The sampler automatically detects and loads the latest state from the specified output directory. ```python import numpy as np from PTMCMCSampler import PTMCMCSampler def lnlike(x): return -0.5 * np.sum(x**2) def lnprior(x): return 0.0 if np.all(np.abs(x) < 10) else -np.inf ndim = 5 cov = np.eye(ndim) * 0.5**2 # First run sampler = PTMCMCSampler.PTSampler( ndim, lnlike, lnprior, cov, outDir="./chains", resume=False ) p0 = np.random.randn(ndim) sampler.sample(p0, Niter=10000, burn=1000, thin=10, isave=1000) # Output: Finished 100.00 percent # Resume and extend the chain sampler_resume = PTMCMCSampler.PTSampler( ndim, lnlike, lnprior, cov, outDir="./chains", resume=True # Resume from existing chain ) sampler_resume.sample(p0, Niter=20000, burn=1000, thin=10, isave=1000) # Output: Resuming run from chain file ./chains/chain_1.0.txt # Resuming with 1001 samples from file representing 10001 original samples ``` -------------------------------- ### Load and Process Chain Data (Python) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Loads chain data from a text file and separates the chain samples from other information (e.g., temperature, log likelihood). It then selects a portion of the chain for plotting. ```python data = np.loadtxt('chains/chain_1.txt') chaint = data[:,:-4] ``` -------------------------------- ### intervalTransform wrapper for Hamiltonian samplers Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Provides a wrapper class for likelihood objects to implement coordinate transformations from an interval to all real numbers, suitable for Hamiltonian MCMC samplers. It includes forward and backward transformations, log-Jacobian calculations, and derivatives. ```python class intervalTransform(object): """ Wrapper class of the likelihood for Hamiltonian samplers. This implements a coordinate transformation for all parameters from an interval to all real numbers. """ def __init__(self, likob, pmin=None, pmax=None): """Initialize the intervalLikelihood with a ptaLikelihood object""" self.likob = likob if pmin is None: self.a = likob.a else: self.a = pmin * np.ones_like(likob.a) if pmax is None: self.b = likob.b else: self.b = pmax * np.ones_like(likob.b) def forward(self, x): """Forward transform the real coordinates (on the interval) to the transformed coordinates (on all real numbers) """ p = np.atleast_2d(x.copy()) posinf, neginf = (self.a == x), (self.b == x) m = ~(posinf | neginf) p[:,m] = np.log((p[:,m] - self.a[m]) / (self.b[m] - p[:,m])) p[:,posinf] = np.inf p[:,neginf] = -np.inf return p.reshape(x.shape) def backward(self, p): """Backward transform the transformed coordinates (on all real numbers) to the real coordinates (on the interval) """ x = np.atleast_2d(p.copy()) x[:,:] = (self.b[:] - self.a[:]) * np.exp(x[:,:]) / (1 + np.exp(x[:,:])) + self.a[:] return x.reshape(p.shape) def logjacobian_grad(self, p): """Return the log of the Jacobian at point p""" lj = np.sum( np.log(self.b[:]-self.a[:]) + p[:] - 2*np.log(1.0+np.exp(p[:])) ) lj_grad = np.zeros_like(p) lj_grad[:] = (1 - np.exp(p[:])) / (1 + np.exp(p[:])) return lj, lj_grad def dxdp(self, p): """Derivative of x wrt p (jacobian for chain-rule) - diagonal""" pp = np.atleast_2d(p) d = np.ones_like(pp) d[:,:] = (self.b[:]-self.a[:])*np.exp(pp[:,:])/(1+np.exp(pp[:,:]))**2 return d.reshape(p.shape) def d2xd2p(self, p): """Derivative of x wrt p (jacobian for chain-rule) - diagonal""" pp = np.atleast_2d(p) d = np.zeros_like(pp) d[:,:] = (self.b[:]-self.a[:])*(np.exp(2*pp[:,:])-np.exp(pp[:,:]))/(1+np.exp(pp[:,:]))**3 return d.reshape(p.shape) def logjac_hessian(self, p): """The Hessian of the log-jacobian""" # p should not be more than one-dimensional assert len(p.shape) == 1 return np.diag(-2*np.exp(p) / (1+np.exp(p))**2) def lnlikefn_grad(self, p, **kwargs): """The log-likelihood in the new coordinates""" x = self.backward(p) ll, ll_grad = self.likob.lnlikefn_grad(x, **kwargs) lj, lj_grad = self.logjacobian_grad(p) return ll+lj, ll_grad*self.dxdp(p)+lj_grad def lnlikefn(self, p, **kwargs): return self.lnlikefn_grad(p)[0] def lnpriorfn_grad(self, p, **kwargs): """The log-prior in the new coordinates. Do not include the Jacobian""" x = self.backward(p) lp, lp_grad = self.likob.lnpriorfn_grad(x) return lp, lp_grad*self.dxdp(p) def lnpriorfn(self, p, **kwargs): return self.lnpriorfn_grad(p)[0] def logpostfn_grad(self, p, **kwargs): """The log-posterior in the new coordinates""" x = self.backward(p) lp, lp_grad = self.likob.lnpost_grad(x) lj, lj_grad = self.logjacobian_grad(p) return lp+lj, lp_grad*self.dxdp(p)+lj_grad def hessian(self, p): """The Hessian matrix in the new coordinates""" # p should not be more than one-dimensional assert len(p.shape) == 1 ``` -------------------------------- ### Load and Plot Posterior Samples Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Loads the MCMC chain data from a file, separates the parameter samples from other information (log-posterior, log-likelihood, etc.), and plots the trace of the first parameter after discarding a burn-in period. ```python data = np.loadtxt('chains/chain_1.txt') chaint = data[:,:-4] # throw out first 25% of chain as burn in burn = int(0.25*chaint.shape[0]) plt.plot(data[burn:,-4]) ``` -------------------------------- ### Add Custom Jump Proposal to Cycle - Python Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Demonstrates how to add a custom jump proposal function to the sampler's proposal cycle with a specified weight. The custom jump function must accept the current position, iteration number, and inverse temperature, returning the proposed position and the log forward-backward probability ratio. This allows for tailored exploration of the parameter space. ```python import numpy as np from PTMCMCSampler import PTMCMCSampler class GaussianLikelihood: def __init__(self, ndim, pmin, pmax): self.pmin, self.pmax = pmin, pmax self.mu = np.random.uniform(pmin, pmax, ndim) cov = 0.5 - np.random.rand(ndim**2).reshape((ndim, ndim)) cov = np.triu(cov) cov += cov.T - np.diag(cov.diagonal()) self.icov = np.linalg.inv(np.dot(cov, cov)) def lnlikefn(self, x): diff = x - self.mu return -0.5 * np.dot(diff, np.dot(self.icov, diff)) def lnpriorfn(self, x): if np.all(x >= self.pmin) and np.all(x <= self.pmax): return 0.0 return -np.inf # Custom uniform jump proposal class UniformJump: def __init__(self, pmin, pmax): self.pmin = pmin self.pmax = pmax def jump(self, x, iter, beta): """ Custom jump proposal function. Parameters: x: Current parameter vector iter: Current iteration number beta: Inverse temperature (1/T) Returns: q: Proposed parameter vector lqxy: Log of forward/backward jump probability ratio """ lqxy = 0 # Symmetric proposal q = np.random.uniform(self.pmin, self.pmax, len(x)) return q, lqxy # Setup ndim = 20 pmin, pmax = 0.0, 10.0 glo = GaussianLikelihood(ndim, pmin, pmax) p0 = np.random.uniform(pmin, pmax, ndim) cov = np.eye(ndim) * 0.1**2 sampler = PTMCMCSampler.PTSampler( ndim, glo.lnlikefn, glo.lnpriorfn, cov, outDir="./chains" ) # Add custom jump with weight 5 ujump = UniformJump(pmin, pmax) sampler.addProposalToCycle(ujump.jump, 5) # Run sampler - custom jump will be used with probability 5/(20+20+20+5) sampler.sample(p0, 10000, burn=500, thin=1, covUpdate=500, SCAMweight=20, AMweight=20, DEweight=20) ``` -------------------------------- ### Generate Corner Plot for Original Chain Samples (Python) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Creates a corner plot for the first three dimensions of the chain samples after transforming them back to the original parameter space. This allows for the analysis of parameter correlations and distributions in their native units. ```python corner.corner(chain[:,:3], bins=50); ``` -------------------------------- ### Using Gradient-Based Samplers (HMC, NUTS, MALA) - Python Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Illustrates how to utilize gradient information for more efficient sampling with PTMCMCSampler using algorithms like Hamiltonian Monte Carlo (HMC), No-U-Turn Sampler (NUTS), and Metropolis-Adjusted Langevin Algorithm (MALA). This requires defining likelihood and prior functions that return both the log-probability and its gradient with respect to the parameters. ```python import numpy as np from PTMCMCSampler import PTMCMCSampler # Define likelihood with gradient def lnlike_grad(x): """ Log-likelihood function that returns both value and gradient. Returns: lnlike: Log-likelihood value grad: Gradient vector (dlnlike/dx) """ lnlike = -0.5 * np.sum(x**2) grad = -x # Gradient of Gaussian return lnlike, grad # Define prior with gradient def lnprior_grad(x): """ Log-prior function that returns both value and gradient. Returns: lnprior: Log-prior value grad: Gradient vector (dlnprior/dx) """ if np.all(np.abs(x) < 20): return 0.0, np.zeros_like(x) return -np.inf, np.zeros_like(x) # Non-gradient versions for sampler initialization def lnlike(x): return -0.5 * np.sum(x**2) def lnprior(x): return 0.0 if np.all(np.abs(x) < 20) else -np.inf # Note: The actual sampler initialization and sampling call would follow, # specifying the use of gradient-based methods if supported by the sampler class. # Example (conceptual, actual API might differ): # sampler = PTMCMCSampler.PTSampler(ndim, lnlike_grad, lnprior_grad, cov, outDir="./chains", use_gradient=True) # sampler.sample(p0, 10000) ``` -------------------------------- ### Generate Corner Plot for Transformed Chain Samples (Python) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Creates a corner plot (scatter plot matrix) for the first three dimensions of the transformed chain samples using the `corner` library. This visualization helps in understanding the correlations and distributions of parameters in the transformed space. ```python corner.corner(chaint[:,:3], bins=50); ``` -------------------------------- ### Load and Analyze PTMCMCSampler Chain Data (Python) Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Loads chain data from a text file, separates parameters and diagnostic information, discards burn-in samples, computes mean and standard deviation for parameters, and prints acceptance rates. Requires numpy and matplotlib. ```python import numpy as np import matplotlib.pyplot as plt # Load chain data chain = np.loadtxt("./chains/chain_1.0.txt") # Determine number of dimensions and extract data ndim = chain.shape[1] - 4 samples = chain[:, :ndim] lnpost = chain[:, -4] lnlike = chain[:, -3] acc_rate = chain[:, -2] pt_acc_rate = chain[:, -1] # Discard burn-in (first 10% of samples) burnin = int(0.1 * len(samples)) samples_burned = samples[burnin:] # Compute statistics mean = np.mean(samples_burned, axis=0) std = np.std(samples_burned, axis=0) # Print parameter estimates print(f"Parameter estimates (mean +/- std):") for i in range(ndim): print(f" x[{i}] = {mean[i]:.4f} +/- {std[i]:.4f}") # Print final acceptance rates print(f"\nFinal acceptance rate: {acc_rate[-1]:.3f}") print(f"PT swap acceptance rate: {pt_acc_rate[-1]:.3f}") # Plot trace and histogram for the first parameter fig, axes = plt.subplots(1, 2, figsize=(12, 4)) axes[0].plot(samples[:, 0], alpha=0.7) axes[0].axvline(burnin, color='r', linestyle='--', label='Burn-in') axes[0].set_xlabel("Iteration") axes[0].set_ylabel("x[0]") axes[0].legend() axes[1].hist(samples_burned[:, 0], bins=50, density=True) axes[1].set_xlabel("x[0]") axes[1].set_ylabel("Density") plt.tight_layout() plt.savefig("chain_analysis.png") ``` -------------------------------- ### Define Custom Uniform Jump Proposal Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Defines a custom jump proposal class `UniformJump` that draws new parameters uniformly within specified bounds. The `jump` method implements the logic for proposing a new state, returning the proposed parameters `q` and the log probability ratio `lqxy`. ```python class UniformJump(object): def __init__(self, pmin, pmax): """Draw random parameters from pmin, pmax""" self.pmin = pmin self.pmax = pmax def jump(self, x, it, beta): """ Function prototype must read in parameter vector x, sampler iteration number it, and inverse temperature beta """ # log of forward-backward jump probability lqxy = 0 # uniformly drawm parameters q = np.random.uniform(self.pmin, self.pmax, len(x)) return q, lqxy ``` -------------------------------- ### Maximize Likelihood Function using SciPy Minimize (Python) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Maximizes the likelihood function using `scipy.optimize.minimize` with the Newton-CG method. It requires the function, its gradient, and its Hessian. The output shows the optimization progress and convergence. ```python # Maximize using scipy result = so.minimize(lambda x: -gl.lnlikefn(x), p0, jac=lambda x: -gl.lnlikefn_grad(x)[1], method='Newton-CG', hess=lambda x: -gl.hessian(x), options={'disp':True}) ``` -------------------------------- ### Add Custom Jump to Sampler Cycle Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Adds the custom `UniformJump` proposal to the sampler's proposal cycle with a specified weight. This integrates the custom jump into the MCMC sampling process. ```python # add to jump proposal cycle ujump = UniformJump(pmin, pmax) sampler.addProposalToCycle(ujump.jump, 5) ``` -------------------------------- ### Reading Chain Output Files Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Describes the format of chain output files generated by PTMCMCSampler. Each line represents a sample, containing the log-posterior, log-likelihood, and parameter values. The file is tab-separated with `ndim + 4` columns. This information is crucial for post-processing and analysis of the sampling results. ```python import numpy as np import matplotlib.pyplot as plt # Load chain file # Assuming chain_1.0.txt exists in the current directory # The file contains columns: logpost, loglike, param1, param2, ..., paramN # Example: Load the chain file into a numpy array # chain_data = np.loadtxt("./chains/chain_1.0.txt") # The first column is log-posterior, second is log-likelihood # log_posterior = chain_data[:, 0] # log_likelihood = chain_data[:, 1] # The remaining columns are the sampled parameters # samples = chain_data[:, 2:] # Example of plotting the log-posterior # plt.figure() # plt.plot(log_posterior) # plt.xlabel("Iteration") # plt.ylabel("Log Posterior") # plt.title("Log Posterior over Iterations") # plt.show() # Example of plotting a specific parameter trace # plt.figure() # plt.plot(samples[:, 0]) # Plot the first parameter # plt.xlabel("Iteration") # plt.ylabel("Parameter 1 Value") # plt.title("Trace Plot for Parameter 1") # plt.show() ``` -------------------------------- ### Transform Chain Samples Back to Original Space (Python) Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Applies the inverse transformation to the chain samples, converting them from the transformed space back to the original parameter space. This is necessary for interpreting the results in the context of the original problem. ```python chain = glt.backward(chaint) ``` -------------------------------- ### Plot Parameter Posteriors using Corner Plot Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Generates a corner plot to visualize the posterior distributions of the first 10 parameters. It uses the `corner` library, overlaying the true parameter values (`glo.mu`) for comparison. ```python # get the true values and plot the posteriors for the first 10 parameters truth = glo.mu corner.corner(chaint[burn:,:10], bins=50, truths=truth[:10]); ``` -------------------------------- ### Define Gaussian Likelihood and Prior Functions Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/simple.ipynb Defines a Gaussian likelihood and a uniform prior using a class structure. The `GaussianLikelihood` class initializes parameters like mean and covariance for the Gaussian distribution and defines `lnlikefn` for the log-likelihood and `lnpriorfn` for the log-prior. This structure is useful for storing additional data or parameters. ```python class GaussianLikelihood(object): def __init__(self, ndim=2, pmin=-10, pmax=10): self.a = np.ones(ndim)*pmin self.b = np.ones(ndim)*pmax # get means self.mu = np.random.uniform(pmin, pmax, ndim) # ... and a positive definite, non-trivial covariance matrix. cov = 0.5-np.random.rand(ndim**2).reshape((ndim, ndim)) cov = np.triu(cov) cov += cov.T - np.diag(cov.diagonal()) self.cov = np.dot(cov,cov) # Invert the covariance matrix first. self.icov = np.linalg.inv(self.cov) def lnlikefn(self, x): diff = x - self.mu return -np.dot(diff,np.dot(self.icov, diff))/2.0 def lnpriorfn(self, x): if np.all(self.a <= x) and np.all(self.b >= x): return 0.0 else: return -np.inf ``` -------------------------------- ### GaussianLikelihood class for MCMC sampling Source: https://github.com/nanograv/ptmcmcsampler/blob/master/examples/gaussian_likelihood.ipynb Implements a Gaussian likelihood function with gradient and Hessian calculations. It defines the log-likelihood, log-prior, and log-posterior functions, along with their gradients, suitable for use with MCMC samplers. ```python class GaussianLikelihood(object): def __init__(self, ndim=2, pmin=-10, pmax=10): self.a = np.ones(ndim)*pmin self.b = np.ones(ndim)*pmax def lnlikefn(self, x): return -0.5*np.sum(x**2)-len(x)*0.5*np.log(2*np.pi) def lnlikefn_grad(self, x): ll = -0.5*np.sum(x**2)-len(x)*0.5*np.log(2*np.pi) ll_grad = -x return ll, ll_grad def lnpriorfn(self, x): if np.all(self.a <= x) and np.all(self.b >= x): return 0.0 else: return -np.inf return 0.0 def lnpriorfn_grad(self, x): return self.lnpriorfn(x), np.zeros_like(x) def lnpost_grad(self, x): ll, ll_grad = self.lnlikefn_grad(x) lp, lp_grad = self.lnpriorfn_grad(x) return ll+lp, ll_grad+lp_grad def lnpost(self, x): return self.lnpost_grad(x)[0] def hessian(self, x): return -np.eye(len(x)) ``` -------------------------------- ### Parameter Groups for Block Updates Source: https://context7.com/nanograv/ptmcmcsampler/llms.txt Enables block updates for specific groups of parameters by defining a `groups` list during sampler initialization. This is beneficial when parameters are correlated or have different scales, allowing for more efficient sampling. The covariance matrix should be structured accordingly, with block-diagonal form often being suitable. ```python import numpy as np from PTMCMCSampler import PTMCMCSampler def lnlike(x): # First 3 params are correlated, last 2 are independent return -0.5 * (np.sum(x[:3]**2) + 10*np.sum(x[3:]**2)) def lnprior(x): return 0.0 if np.all(np.abs(x) < 10) else -np.inf ndim = 5 # Define parameter groups for block updates groups = [ np.array([0, 1, 2]), # Group 1: first three parameters np.array([3, 4]) # Group 2: last two parameters ] # Build block-diagonal covariance cov = np.zeros((ndim, ndim)) cov[:3, :3] = np.eye(3) * 0.3**2 # Larger steps for first group cov[3:, 3:] = np.eye(2) * 0.1**2 # Smaller steps for second group sampler = PTMCMCSampler.PTSampler( ndim, lnlike, lnprior, cov, groups=groups, # Specify parameter groups outDir="./chains" ) p0 = np.random.randn(ndim) sampler.sample(p0, Niter=50000, burn=5000, thin=10) # SCAM and AM jumps will update parameters within each group separately ```