Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/navigator_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Navigator Check

# Thin caller for PyAutoHands's reusable navigator-catalogue check. The check
# logic (path/banner lint + catalogue staleness) and its entrypoints live in
# PyAutoHands/autobuild; this repo only declares which generator project to run.
# See PyAutoLabs/PyAutoHands/.github/workflows/navigator_check.yml.

on: [push, pull_request]

permissions:
contents: read

jobs:
navigator:
uses: PyAutoLabs/PyAutoHands/.github/workflows/navigator_check.yml@main
with:
project: howtofit
10 changes: 10 additions & 0 deletions .navigator_check_ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Paths exempt from the navigator path/banner checks (see
# PyAutoHands/autobuild/check_navigator.py). One path or glob per line.
#
# CLAUDE.md's "Relationship to autofit_workspace" section mentions sibling
# autofit_workspace scripts in prose (as the next destination after a concept).
# Those paths live in the separate autofit_workspace repo, not here, so the
# path-existence check would flag them as missing. Exempt them.
scripts/cookbooks/
scripts/searches/
scripts/overview/overview_2_science_workflow.py
92 changes: 92 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# HowToFit — Agent Instructions

This is the **HowToFit** tutorial lecture series for **PyAutoFit**, a Python probabilistic
programming library for Bayesian model fitting. Tutorials teach new users how to compose, fit, and
interpret probabilistic models from first principles. It is the teaching companion to
`../autofit_workspace`. These are the canonical, agent-agnostic instructions for this repo.

## Repository Structure

- `scripts/` — Runnable Python tutorial scripts:
- `chapter_1_introduction/` — Models, fitting data, non-linear searches, results and samples
- `chapter_2_scientific_workflow/` — Reserved stub for future material (empty except README)
- `chapter_3_graphical_models/` — Individual / graphical / hierarchical models, Expectation Propagation
- `simulators/` — Simulator scripts that generate the tutorial 1D datasets at runtime
- `notebooks/` — Jupyter versions, generated from `scripts/` (do not edit directly)
- `config/` — PyAutoFit configuration YAML
- `dataset/` — Empty in the repo; written at runtime by the simulator scripts
- `output/` — Model-fit results (generated at runtime, not committed)

## Running Scripts

Scripts are run **from the repo root** so relative paths to `dataset/` and `output/` resolve. A
tutorial that needs a dataset invokes `scripts/simulators/simulators.py` via `subprocess` if the
dataset folder is absent — no manual simulate-then-run step.

```bash
python scripts/chapter_1_introduction/tutorial_1_models.py
```

Fast mode for integration: `PYAUTO_TEST_MODE=1` skips sampling (`=2` also bypasses; combine with
`PYAUTO_SKIP_FIT_OUTPUT=1 PYAUTO_SKIP_VISUALIZATION=1 PYAUTO_SKIP_CHECKS=1` for a fast smoke run).
Most tutorials use the `af.ex` namespace for example components (`af.ex.Gaussian`, `af.ex.Analysis`)
and the generic `af.Model` / `af.Collection` API.

## Testing

On CI, every PR is gated on Python **3.12 and 3.13** by `smoke_tests.yml` (runs
`python .github/scripts/run_smoke.py`, driven by `smoke_tests.txt` + `config/build/env_vars.yaml` —
the definition of green), `navigator_check.yml` (PyAutoHands's reusable navigator-catalogue check;
see *Notebooks vs Scripts*), and `url_check.yml` (link checking). The smoke and navigator jobs check
out **PyAutoHands** as a sibling and run the PyAuto* libraries from the **same-named branch** of each
source repo, so a HowToFit PR is validated against matching library branches.

## Sandboxed / restricted runs

If `numba` or `matplotlib` cannot write to the default cache locations, point them at writable dirs:

```bash
NUMBA_CACHE_DIR=/tmp/numba_cache MPLCONFIGDIR=/tmp/matplotlib python scripts/chapter_1_introduction/tutorial_1_models.py
```

## Notebooks vs Scripts

Notebooks in `notebooks/` are **generated** from the `.py` scripts via PyAutoHands. **Always edit the
`.py` scripts, never the `.ipynb` directly.** The `# %%` marker alternates code and markdown cells.
Regenerate from the repo root:

```bash
PYTHONPATH=../PyAutoHands/autobuild python3 ../PyAutoHands/autobuild/generate.py howtofit
```

The `howtofit` project target is registered in PyAutoHands (`run_all.py`, `navigator.py`, `config/`).
The navigator catalogue — `llms-full.txt` + `workspace_index.json` — is what `navigator_check.yml`
gates; it is rebuilt by the same PyAutoHands generate/merge flow that builds the notebooks. Commit
regenerated notebooks and catalogue alongside the script changes.

## Bulk-edit safety

When editing the same region across many scripts in one pass, only rewrite the targeted region.
**Never produce a whole-file write unless you have read the entire current file** — a whole-file
write from a header skim silently deletes every section below the header.

## Related Repos

- `../PyAutoFit` — source library.
- `../autofit_workspace` — the user-facing workspace (tutorials point here as the next destination).
- `../PyAutoHands` — notebook generation + CI tooling.

## Task Workflows

**`[API Update]` issues:** find every renamed/moved/removed/changed public API, update each tutorial
script (preserving the teaching prose), run `python .github/scripts/run_smoke.py`, and fix `[FAIL]`
entries until the summary passes; regenerate notebooks + catalogue after. **General issues:** edit
only files in `scripts/` (never `notebooks/`), preserve docstrings and explanations, test, then
regenerate. Flag any change that affects `autofit_workspace` or PyAutoFit in your PR.

## Never rewrite history

Never rewrite pushed history on any repo with a remote — no `git init` over a
tracked repo, no force-push to `main`, no fresh-start "Initial commit", no
`filter-repo` / `filter-branch` / `rebase -i` on pushed branches. To get a
clean tree: `git fetch origin && git reset --hard origin/main && git clean -fd`.
95 changes: 95 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# HowToFit

[Installation Guide](https://pyautofit.readthedocs.io/en/latest/installation/overview.html) |
[PyAutoFit readthedocs](https://pyautofit.readthedocs.io/en/latest/index.html) |
[Browse Chapter 1 With Images](markdown/README.md) |
[autofit_workspace](https://github.com/PyAutoLabs/autofit_workspace)

<img src="https://github.com/Jammy2211/PyAutoLogo/blob/main/gifs/pyautofit.gif?raw=true" width="900" />

Welcome to **HowToFit** — the tutorial lecture series for [PyAutoFit](https://github.com/PyAutoLabs/PyAutoFit),
an open-source probabilistic programming library for Bayesian model fitting.

**HowToFit** teaches new users how to compose, fit, and interpret probabilistic models with **PyAutoFit**.
It assumes minimal prior knowledge of statistics and takes you from first principles — what a model is,
what a non-linear search does, how a likelihood function is built — through to graphical and hierarchical
models for fitting large datasets simultaneously.

For experienced scientists who already know the fundamentals of Bayesian modeling, the
[autofit_workspace](https://github.com/PyAutoLabs/autofit_workspace) examples will be more appropriate —
they are concise, API-focused, and assume the concepts taught in **HowToFit** as background.

## Chapters

- `chapter_1_introduction` — Models, likelihoods, non-linear searches, why modeling is hard, and how to
interpret the results of a fit.
- `chapter_2_scientific_workflow` — Reserved for future material on building a full scientific
model-fitting workflow. Currently a stub; the corresponding overview lives in
`autofit_workspace/scripts/overview/overview_2_science_workflow.py`.
- `chapter_3_graphical_models` — Fitting many datasets simultaneously with graphical models,
hierarchical models, and Expectation Propagation.

Each chapter is organised into numbered tutorial files: `chapter_<N>_<name>/tutorial_<M>_<topic>.py`
(Python script) or the matching `.ipynb` in `notebooks/`. Tutorials build on each other within a
chapter and assume you have completed the earlier ones.

## Getting Started

You can run the tutorials on your own machine by following the
[PyAutoFit installation guide](https://pyautofit.readthedocs.io/en/latest/installation/overview.html),
then cloning this repository:

```bash
git clone https://github.com/PyAutoLabs/HowToFit.git
cd HowToFit
```

Alternatively, every tutorial can be opened directly in Google Colab via the links in each chapter's
`README.md`.

The tutorials are distributed as both Jupyter notebooks (`notebooks/`) and Python scripts (`scripts/`).
We recommend the notebooks for reading — figures render inline, and you can step through small code blocks
interactively. Use the Python scripts for actual **PyAutoFit** use.

## Before Chapter 1

Before starting chapter 1, open `start_here.py` for a one-page overview of the series, then begin
`scripts/chapter_1_introduction/tutorial_1_models.py`.

## Repository Structure

- `scripts/` — Runnable Python tutorial scripts, one subfolder per chapter.
- `notebooks/` — Jupyter notebook versions of the scripts (auto-generated; see below).
- `config/` — **PyAutoFit** configuration YAML files used by the tutorials.
- `dataset/` — Tutorial 1D datasets are generated at runtime by `scripts/simulators/simulators.py` —
no data files are committed.
- `output/` — Model-fit results (generated at runtime, not committed).

## Notebooks vs Scripts

Notebooks in `notebooks/` are generated from the Python files in `scripts/`. **Always edit the ``.py``
scripts, never the notebooks directly.** The `# %%` markers in each script alternate between code and
markdown cells, which [PyAutoHands](https://github.com/PyAutoLabs/PyAutoHands) uses to produce the
`.ipynb` files.

## Relationship to autofit_workspace

[autofit_workspace](https://github.com/PyAutoLabs/autofit_workspace) is the main user-facing workspace
for **PyAutoFit** — concise examples, cookbooks, and search templates aimed at users who already understand
probabilistic modeling. **HowToFit** is the teaching companion. Tutorials in chapters 1 and 3 reference
`autofit_workspace` scripts as the next place to go after the relevant concept has been introduced.

## Citations

If you use **HowToFit** or **PyAutoFit** in your research, please cite the references listed in
`CITATIONS.rst`.

## Community & Support

Support for **PyAutoFit** is available via our Slack workspace. Slack is invitation-only; send an email
if you'd like an invite.

For installation issues, bug reports, or feature requests, raise an issue on the
[PyAutoFit GitHub issues page](https://github.com/PyAutoLabs/PyAutoFit/issues) (for library issues)
or the [HowToFit GitHub issues page](https://github.com/PyAutoLabs/HowToFit/issues) (for tutorial
content issues).
16 changes: 16 additions & 0 deletions config/build/markdown_examples.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Curated examples rendered to executed markdown pages (markdown/) with real
# output images, for GitHub browsing. Built by PyAutoHands's generate_markdown.py
# (never TEST_MODE; features/ never rendered; order = execution + index order).
# Batch 2b: chapter_1_introduction (the intro lecture, in reading order).
- script: scripts/chapter_1_introduction/start_here.py
max_minutes: 30
- script: scripts/chapter_1_introduction/tutorial_1_models.py
max_minutes: 30
- script: scripts/chapter_1_introduction/tutorial_2_fitting_data.py
max_minutes: 30
- script: scripts/chapter_1_introduction/tutorial_3_non_linear_search.py
max_minutes: 90
- script: scripts/chapter_1_introduction/tutorial_4_why_modeling_is_hard.py
max_minutes: 120
- script: scripts/chapter_1_introduction/tutorial_5_results_and_samples.py
max_minutes: 90
47 changes: 47 additions & 0 deletions llms-full.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
AUTO-GENERATED by PyAutoHands — do not edit by hand; regenerate with generate.py.

# HowToFit Lectures — Full Catalogue

> Complete, generated listing of every script (and its matching notebook) in this
> workspace, grouped by top-level `scripts/` folder. This is the expanded companion to
> the curated `llms.txt` routing layer. Each entry links the script's title to its path
> and gives the first line of its docstring; `Contents:` lists the sections within.

## chapter_1_introduction

- [HowToFit Lectures](scripts/chapter_1_introduction/start_here.py): Welcome to the HowToFit Jupyter Notebook lectures!
- [Tutorial 1: Models](scripts/chapter_1_introduction/tutorial_1_models.py): At the heart of model-fitting is the model: a set of equations, numerical processes, and assumptions describing a physical system of interest. The goal of model-fitting is to better understand this physical system and develop predictive models that describe it more accurately.
- Contents: Paths, Model Parameterization, Model Composition, Model Creation, Model Mapping, Complex Models, Tuple Parameters, Extensibility, Wrap Up
- [Tutorial 2: Fitting Data](scripts/chapter_1_introduction/tutorial_2_fitting_data.py): We've learned that a model consists of equations, numerical processes, and assumptions that describe a physical system. Using **PyAutoFit**, we defined simple 1D models like the Gaussian, composed them into models using `Model` and `Collection` objects, and generated model data by varying their parameters.
- Contents: Data, Model Data, Residuals, Normalized Residuals, Chi Squared, Noise Normalization, Likelihood, Recap, Fitting Models, Guess 1, Guess 2, Guess 3, Extensibility, Wrap Up
- [Tutorial 3: Non Linear Search](scripts/chapter_1_introduction/tutorial_3_non_linear_search.py): In the previous tutorials, we laid the groundwork by defining a model and manually fitting it to data using fitting functions. We quantified the goodness of fit using the log likelihood and demonstrated that for models with only a few free parameters, we could achieve satisfactory fits by manually guessing parameter values. However, as the complexity of our models increased, this approach quickly became impractical.
- Contents: Parameter Space, Non-Linear Search, Search Types, Deeper Background, Data, Model, Priors, Analysis, Searches, Maximum Likelihood Estimation (MLE), Markov Chain Monte Carlo (MCMC), Nested Sampling, What is The Best Search To Use?, Wrap Up
- [Tutorial 4: Why Modeling Is Hard](scripts/chapter_1_introduction/tutorial_4_why_modeling_is_hard.py): We have successfully fitted a simple 1D Gaussian profile to a dataset using a non-linear search. While achieving an accurate model fit has been straightforward, the reality is that model fitting is a challenging problem where many things can go wrong.
- Contents: Data, Model, Analysis, Alternative Syntax, Collection, Search, Model Fit, Result, Why Modeling is Hard, Prior Tuning, Reducing Complexity, Search More Thoroughly, Summary, Run Times, Model Mismatch, Astronomy Example, Wrap Up
- [Tutorial 5: Results And Samples](scripts/chapter_1_introduction/tutorial_5_results_and_samples.py): In this tutorial, we'll cover all of the output that comes from a non-linear search's `Result` object.
- Contents: Data, Reused Functions, Model Fit, Result, Samples, Parameters, Figures of Merit, Instances, Vectors, Labels, Posterior / PDF, Plot, Errors, PDF, Other Results, Sample Instance, Bayesian Evidence, Derived Errors (PDF from samples), Samples Filtering, Latex

## chapter_3_graphical_models

- [Tutorial 1: Individual Models](scripts/chapter_3_graphical_models/tutorial_1_individual_models.py): In many examples, we fit one model to one dataset. For many problems, we may have a large dataset and are not interested in how well the model fits each individual dataset. Instead, we want to know how the model fits the full dataset, so that we can determine "global" trends of how the model fits the data.
- Contents: Real World Example, Example Source Code (`af.ex`), Model, Data, Model Fits (one-by-one), Results, Estimating the Centre, Posterior Multiplication, Wrap Up
- [Tutorial 2: Graphical Models](scripts/chapter_3_graphical_models/tutorial_2_graphical_model.py): We have fitted a dataset containing 5 noisy 1D Gaussian which had a shared `centre` value. We estimated the `centre` by fitting each dataset individually and combining the value of the `centre` inferred by each fit into an overall estimate, using a weighted average.
- Contents: Example Source Code (`af.ex`), Dataset, Analysis, Model, Analysis Factors, Factor Graph, Search, Result, Wrap Up
- [Tutorial 3: Graphical Benefits](scripts/chapter_3_graphical_models/tutorial_3_graphical_benefits.py): In the previous tutorials, we fitted a dataset containing 5 noisy 1D Gaussian which had a shared `centre` value and compared different approaches to estimate the shared `centre`. This included a simple approach fitting each dataset one-by-one and estimating the centre via a weighted average or posterior multiplication and a more complicated approach using a graphical model.
- Contents: The Model, Example Source Code (`af.ex`), Dataset, Analysis, Model (one-by-one), Model Fits (one-by-one), Centre Estimates (Weighted Average), Discussion, Model (Graphical), Analysis Factors, Factor Graph, Search, Result, Discussion, Posterior Multiplication, Wrap Up
- [Tutorial 4: Hierarchical](scripts/chapter_3_graphical_models/tutorial_4_hierachical_models.py): In the previous tutorial, we fitted a graphical model with the aim of determining an estimate of shared parameters, the `centre`'s of a dataset of 1D Gaussians. We did this by fitting all datasets simultaneously. When there are shared parameters in a model, this is a powerful and effective tool, but things may not always be so simple.
- Contents: Example Source Code (`af.ex`), Dataset, Analysis, Model Individual Factors, Analysis Factors, Model, Factor Graph, Search, Result, Comparison to One-by-One Fits, Benefits of Graphical Model, Wrap Up
- [Tutorial 5: Expectation Propagation](scripts/chapter_3_graphical_models/tutorial_5_expectation_propagation.py): In the previous tutorials, we fitted graphical models to dataset comprising many noisy 1D Gaussians. These had a shared and global value of their `centre`, or assumed their centres were hierarchically drawn from a parent Gaussian distribution. This provides the basis of composing and fitting complex graphical models to large datasets.
- Contents: Example Source Code (`af.ex`), Dataset, Analysis, Model, Analysis Factors, Factor Graph, Expectation Propagation, Cyclic Fitting, Result, Output, Results
- [Tutorial Optional: Hierarchical Expectation Propagation (EP)](scripts/chapter_3_graphical_models/tutorial_optional_hierarchical_ep.py): This optional tutorial gives an example of fitting a hierarchical model using EP.
- Contents: Example Source Code (`af.ex`), Dataset, Analysis, Model Individual Factors, Analysis Factors, Model, Factor Graph, Model Fit
- [Tutorial Optional: Hierarchical Individual](scripts/chapter_3_graphical_models/tutorial_optional_hierarchical_individual.py): In tutorial 4, we fit a hierarchical model using a graphical model, whereby all datasets are fitted simultaneously and the hierarchical parameters are fitted for simultaneously with the model parameters of each 1D Gaussian in each dataset.
- Contents: Example Source Code (`af.ex`), Dataset, Analysis, Model, Model Fits (one-by-one), Results, Overall Gaussian Parent Distribution, Model, Analysis + Search

## simulators

- [__Simulators__](scripts/simulators/simulators.py): These scripts simulate the 1D Gaussian datasets used to demonstrate model-fitting.
- Contents: Gaussian x1, Gaussian x1 (0), Gaussian x1 (1), Gaussian x1 (2), Gaussian x1 (Identical 0), Gaussian x1 (Identical 1), Gaussian x1 (Identical 2), Gaussian x1 + Exponential x1, Gaussian x2 + Exponential x1, Gaussian x2, Gaussian x3, Gaussian x5, Gaussian x1 unconvolved, Gaussian x1 convolved, Gaussian x1 with feature, Gaussian x2 split, Gaussian x1 time
- [__Simulators__](scripts/simulators/simulators_sample.py): These scripts simulates many 1D Gaussian datasets with a low signal to noise ratio, which are used to demonstrate model-fitting.
- Contents: Gaussian x1 low snr (centre fixed to 50.0), Gaussian x1 low snr (centre drawn from parent Gaussian distribution to 50.0), Gaussian x2 offset centre
- [util](scripts/simulators/util.py): (no summary in script docstring)
Loading
Loading