Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Every change requires review from the maintainer before merge.
* @davidkhjo
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ jobs:
- name: Type-check
run: uv run mypy
- name: Test
run: uv run pytest
run: uv run pytest --cov --cov-report=term-missing
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ checkpoints/
.idea/
.vscode/
site/

# Nia tooling config (local only)
nia.json
29 changes: 21 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,11 @@ synthetic archives in `tmp_path`); never add a test that hits the network.

1. Branch from `main`.
2. Keep the change focused; add or update tests.
3. Ensure `uv run pytest`, `uv run ruff check .`, `uv run ruff format --check .`,
and `uv run mypy` are green.
4. Open a PR against `main`. CI runs the suite on Python 3.10–3.13.

Pull requests are also reviewed by Claude (`.github/workflows/claude-code-review.yml`).
It stays inactive until a maintainer adds the `CLAUDE_CODE_OAUTH_TOKEN` repository
secret (from `claude setup-token`) and sets the repository variable
`ENABLE_CLAUDE_REVIEW` to `true`.
3. Ensure `make check` (lint, type-check, tests) is green — or run
`uv run ruff check .`, `uv run ruff format --check .`, `uv run mypy`, and
`uv run pytest` individually.
4. Open a PR against `main`. CI runs the suite on Python 3.10–3.13, and every PR
is reviewed by Claude before it can be merged. Only a maintainer merges.

## Adding a loss or sampler

Expand All @@ -65,3 +62,19 @@ secret (from `claude setup-token`) and sets the repository variable
- A **sampler** subclasses `ebm.samplers.base.Sampler` and implements `step`;
the base class handles the detach/freeze loop. Add a test that it targets a
known distribution and, for MH samplers, exposes `last_accept_rate`.

## Releasing (maintainers)

The version lives in one place, `src/ebm/__init__.py`, and hatchling reads it.
To cut a release:

```bash
# 1. update CHANGELOG.md, then bump (also commits + tags):
make bump-patch # or bump-minor / bump-major
# 2. publish:
git push --follow-tags
gh release create vX.Y.Z --title vX.Y.Z --notes "See CHANGELOG.md"
```

The GitHub release triggers `publish.yml`, which builds and uploads to PyPI via
trusted publishing.
24 changes: 24 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Developer shortcuts. The version lives only in src/ebm/__init__.py
# (hatchling reads it); these targets bump it, commit, and tag in one step.

.PHONY: test lint typecheck cov check bump-patch bump-minor bump-major

test: ; uv run pytest
lint: ; uv run ruff check . && uv run ruff format --check .
typecheck: ; uv run mypy
cov: ; uv run pytest --cov --cov-report=term-missing
check: lint typecheck test

# make bump-patch # 0.12.0 -> 0.12.1 (also: bump-minor, bump-major)
# Update CHANGELOG.md first; after bumping, `git push --follow-tags` and cut a
# release with `gh release create vX.Y.Z --title vX.Y.Z`.
bump-patch: ; @$(MAKE) _bump PART=patch
bump-minor: ; @$(MAKE) _bump PART=minor
bump-major: ; @$(MAKE) _bump PART=major

_bump:
uv run hatch version $(PART)
@V=$$(uv run hatch version); \
git commit -am "v$$V"; \
git tag "v$$V"; \
echo "bumped to v$$V — run: git push --follow-tags"
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

[![CI](https://github.com/davidkhjo/ebmkit/actions/workflows/ci.yml/badge.svg)](https://github.com/davidkhjo/ebmkit/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/ebmkit.svg)](https://pypi.org/project/ebmkit/)
[![coverage](https://img.shields.io/badge/coverage-95%25-brightgreen.svg)](https://github.com/davidkhjo/ebmkit/actions/workflows/ci.yml)
[![Python](https://img.shields.io/pypi/pyversions/ebmkit.svg)](https://pypi.org/project/ebmkit/)
[![downloads](https://img.shields.io/pypi/dm/ebmkit.svg)](https://pypi.org/project/ebmkit/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/davidkhjo/ebmkit/blob/main/LICENSE)

A small, reliable PyTorch toolkit for training and using **energy-based models** —
the MCMC samplers, training losses, replay buffers, and diagnostics every EBM
project otherwise rebuilds from scratch, as composable objects with tested defaults.
**Energy-based models in PyTorch** — samplers, training losses, and honest
evaluation, as composable objects with tested defaults.

An EBM is an unnormalized density `p(x) ∝ exp(-E(x))` defined by a network
`E: (B, *shape) -> (B,)`. `torch` is the only runtime dependency.
Expand Down
20 changes: 0 additions & 20 deletions nia.json

This file was deleted.

13 changes: 11 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "ebmkit"
version = "0.12.0"
dynamic = ["version"]
description = "A PyTorch library for training and using energy-based models (EBMs)"
readme = "README.md"
license = "MIT"
Expand Down Expand Up @@ -33,14 +33,17 @@ dependencies = ["torch>=2.0"]

[project.optional-dependencies]
viz = ["matplotlib>=3.7"]
dev = ["pytest>=8.0", "ruff>=0.4", "mypy>=1.8", "matplotlib>=3.7"]
dev = ["pytest>=8.0", "pytest-cov>=5.0", "ruff>=0.4", "mypy>=1.8", "hatch>=1.9", "matplotlib>=3.7"]

[project.urls]
Homepage = "https://github.com/davidkhjo/ebmkit"
Repository = "https://github.com/davidkhjo/ebmkit"
Issues = "https://github.com/davidkhjo/ebmkit/issues"
Changelog = "https://github.com/davidkhjo/ebmkit/blob/main/CHANGELOG.md"

[tool.hatch.version]
path = "src/ebm/__init__.py"

[tool.hatch.build.targets.wheel]
packages = ["src/ebm"]

Expand All @@ -56,6 +59,12 @@ select = ["E", "F", "W", "I", "UP", "B", "SIM"]
files = ["src/ebm"]
ignore_missing_imports = true # torch / matplotlib ship partial stubs

[tool.coverage.run]
source = ["ebm"]

[tool.coverage.report]
show_missing = true

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = "-q"
Loading
Loading