Imaging (MCMC)
SQUEEZE-style image reconstruction by Markov-chain Monte Carlo, in two flavours: simulated annealing (reconstruct_squeeze) and parallel tempering (reconstruct_squeeze_tempered, which also returns a log evidence). See the SQUEEZE (MCMC) guide for the method and worked examples.
Unlike the gradient reconstructions, the image is represented as a bag of nelements discrete flux quanta on the pixel grid. Positivity and total flux are exact by construction, non-convex regularizers such as L0 are available, and the result is a posterior mean image rather than a MAP point.
| Function | Description |
|---|---|
reconstruct_squeeze(x_start, data, ft) | MCMC image reconstruction by simulated annealing |
SqueezeSparco(; f_star, ud, …) | SPARCO chromatic star + background model |
reconstruct_squeeze_tempered(data, ft) | Parallel-tempered version (needs using Pigeons) |
default_nelements(data, nx) | Default number of flux quanta for a dataset |
Both drivers accept monitor = n to redraw the image and a χ²r / parameter trace panel every n iterations, and print_every = n for the C-format text diagnostic line. Both are off by default.
Regularizers
Passed as regularizers = [["l0", λ], ["tv", λ], …], the same convention as reconstruct.
| Name | Form on the integer histogram | Typical λ |
|---|---|---|
"l0" | count of nonzero pixels | 1 – 20 |
"tv" | Σ √(dx²+dy²) / nelements, backward differences | 200 – 2000 |
"entropy" | Σ_{x>0} lgamma(x) (quantised / Poisson prior) | 1 – 10 |
"compactness" | Σ r²·x² | 20 – 500 |
"centering" | centroid / second-moment penalty | 1 (auto) |
"priorimage" | Σ -log(prior[pixel]) over quanta; see prior_image | 1 (auto) |
These are SQUEEZE's forms, evaluated on the integer histogram with a /nelements normalisation. They are not the gradient-oriented versions in oichi2.jl (tv, entropy, compactness), which are defined on the normalised pixel image. The definitions differ, so the useful λ ranges differ too — by up to three orders of magnitude between regularizers, as the table shows. Do not carry a λ over from reconstruct.
API
OITOOLS.reconstruct_squeeze — Function
reconstruct_squeeze(data, ft; kwargs...) -> (image, diagnostics)
reconstruct_squeeze(x_start, data, ft; kwargs...) -> (image, diagnostics)SQUEEZE-style MCMC image reconstruction.
The image is represented as a bag of nelements discrete flux quanta on the pixel grid, sampled by Metropolis-Hastings with simulated annealing. This gives positivity and fixed total flux for free, admits non-convex regularizers such as L0, and returns a posterior mean image rather than a MAP point.
x_start selects the starting configuration; omit it for SQUEEZE's own default.
| value | meaning |
|---|---|
:point_source (default) | all quanta on the centre pixel — a Dirac, as when C is run without -i |
:random | quanta scattered uniformly (an OITOOLS addition; gives multiple chains genuinely different starts) |
an nx × nx image | digitised into quanta — C's -i |
Strings work too ("point_source", "random"). Note the default is a point source, not a random or flat image: the annealing is expected to spread the flux out from it.
ft follows the same convention as reconstruct / reconstruct_bsmem: the image geometry is taken from the Fourier operator, not from keywords.
- Pass a DFT matrix (
setup_ft(data, nx, pixsize; mode="dft")orsetup_dft) and it is used directly — this is what the sampler wants, and nothing is rebuilt. - Pass an NFFT plan and
nx/pixsizeare recovered from it exactly asreconstruct_bsmemdoes, then a DFT matrix is built internally. The sampler cannot use an NFFT plan: it needs O(nuv) access to a single column per move (the rank-1 update), which a transform-based operator cannot provide.
Keyword arguments
nelements: number of flux quanta (defaultdefault_nelements).niter: sweeps; each sweep isnelementsproposals.nchains: independent annealing restarts, run on separate threads.regularizers: OITOOLS-style[["l0", λ], ["tv", λ], ...]. Supported names arel0,tv,entropy,compactness,centering,priorimage. These are SQUEEZE's forms on the integer histogram, not OITOOLS' differentiable versions.weights: observable weights, default[1.0,1.0,1.0]= V², T3amp, T3phi, as inreconstruct(padded to 7 internally).prior_image: annx × nxmap of per-pixel prior probabilities (C's-p). It becomes an additive penalty-log(p)per quantum, withp <= 0mapped to1e12— which is what makes it a mask: no quantum can ever sit on a zero-prior pixel. Its weight defaults to 1 and can be set explicitly with["priorimage", λ]inregularizers. Supplying one disables auto-centering, since the prior already fixes the position (C warns about this combination).pixsize: only needed to override the value recovered fromft, or to supply one whenftis a bare DFT matrix andoutfileis set (the FITS WCS header).tmin,chi2_temp,chi2_target: annealing schedule (C's-tm,-ct,-fc).f_anywhere,f_copycat: fixed proposal fractions.model: an optionalSqueezeSparcochromatic star + background model.print_every: C-format text diagnostic line every n sweeps.monitor: if > 0, redraw a live image and trace display everymonitorsweeps (chain 1 only). Off by default, and free when off — one integer comparison per sweep. Enabling it pins chain 1 to the calling thread, because drawing must happen on the main thread; the other chains still run in parallel.monitor_colormapselects the image colour map.seed: per-chain streams are a pure function of(seed, chain), so results are reproducible regardless of thread scheduling.
Notes
COPYCAT proposals are asymmetric and irreversible; they are an effective optimizer heuristic for annealing but are not a valid sampler move. Set f_copycat=0 if you want the post-burn-in samples to be a defensible posterior.
reconstruct_squeeze(data, ft; kwargs...)Start from SQUEEZE's default configuration — a point source at the centre of the grid, the equivalent of running the C code without -i. Identical to passing :point_source as x_start.
reconstruct_squeeze(x_start, data::AbstractArray{<:OIdata}, ft; kwargs...)Convenience dispatch matching the rest of the reconstruct* family, so the usual data = readoifits(file); ft = setup_ft(data, nx, pixsize; mode="dft") pattern works without indexing. Only the monochromatic, single-epoch case is supported.
OITOOLS.reconstruct_squeeze_tempered — Function
reconstruct_squeeze_tempered(data, ft; kwargs...)Parallel-tempered SQUEEZE reconstruction, built on Pigeons.jl.
Requires Pigeons to be loaded:
using OITOOLS, Pigeons
img, diag = reconstruct_squeeze_tempered(data, ft; n_rounds = 10, n_chains = 10)Unlike reconstruct_squeeze, which anneals (an optimizer that floors at T = 1), this samples the posterior at β = 1 with a full temperature ladder, and returns a log normalising constant logZ alongside the mean image.
OITOOLS.SqueezeSparco — Type
SqueezeSparco(; f_star, ud, env_indx, lambda0, f_bg, bg_indx, free, stepsize)SPARCO model state for reconstruct_squeeze.
Parameters, in C's order:
| # | name | meaning |
|---|---|---|
| 1 | f_star | stellar flux fraction at lambda0 |
| 2 | ud | uniform-disc diameter of the star, mas (0 = point source) |
| 3 | env_indx | flux power-law index of the environment (the image) |
| 4 | lambda0 | reference wavelength, metres, must be > 0 |
| 5 | f_bg | over-resolved background flux fraction at lambda0 |
| 6 | bg_indx | flux power-law index of the background |
free lists the parameters the sampler may vary, by name or index; everything else is held fixed. stepsize is the two-point lattice half-width per parameter and is adapted toward a 0.3 acceptance rate during the run.
The model is only meaningful on polychromatic data: with a single wavelength every (λ/λ0)^x is a constant and the three indices are exactly degenerate.
OITOOLS.default_nelements — Function
default_nelements(data, nx)C's heuristic (squeeze.c:298): 2·ceil(nx · ndata^(1/3)), floored at 500.
reconstruct_squeeze_tempered lives in a package extension and only becomes available once you using Pigeons. It is not installed with OITOOLS, and CI does not exercise it — Pigeons pulls in MPI.jl, which is not worth building across every CI configuration for an opt-in feature.