{"id":51341020,"url":"https://github.com/vpetreski/cp-deep-dive","last_synced_at":"2026-07-02T07:33:49.200Z","repository":{"id":355506486,"uuid":"1215488067","full_name":"vpetreski/cp-deep-dive","owner":"vpetreski","description":"A top-to-bottom deep dive into Constraint Programming with OR-Tools CP-SAT — in Python and Kotlin — culminating in a full end-to-end Nurse Scheduling Problem app (FastAPI + Ktor 3 + React 19). Includes cpsat-kt, an idiomatic Kotlin DSL over CP-SAT.","archived":false,"fork":false,"pushed_at":"2026-05-30T02:18:48.000Z","size":1326,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-30T02:20:33.695Z","etag":null,"topics":["combinatorial-optimization","constraint-programming","cp-sat","dsl","educational","fastapi","kotlin","ktor","learning-resources","minizinc","nurse-scheduling","operations-research","optimization","or-tools","ortools","python","react","scheduling"],"latest_commit_sha":null,"homepage":"https://vanja.io/the-field-that-schedules-your-world/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vpetreski.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-20T00:59:17.000Z","updated_at":"2026-05-30T02:18:51.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vpetreski/cp-deep-dive","commit_stats":null,"previous_names":["vpetreski/cp-deep-dive"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/vpetreski/cp-deep-dive","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetreski%2Fcp-deep-dive","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetreski%2Fcp-deep-dive/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetreski%2Fcp-deep-dive/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetreski%2Fcp-deep-dive/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vpetreski","download_url":"https://codeload.github.com/vpetreski/cp-deep-dive/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vpetreski%2Fcp-deep-dive/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35038239,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-02T02:00:06.368Z","response_time":173,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["combinatorial-optimization","constraint-programming","cp-sat","dsl","educational","fastapi","kotlin","ktor","learning-resources","minizinc","nurse-scheduling","operations-research","optimization","or-tools","ortools","python","react","scheduling"],"created_at":"2026-07-02T07:33:44.553Z","updated_at":"2026-07-02T07:33:49.190Z","avatar_url":"https://github.com/vpetreski.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# cp-deep-dive\n\n*A practical, top-to-bottom deep dive into Constraint Programming with\nOR-Tools CP-SAT — in Python **and** Kotlin — culminating in a full\nend-to-end Nurse Scheduling Problem (NSP) application.*\n\n\u003e Why does this repo exist? Read the companion essay:\n\u003e **[The field that schedules your world](https://vanja.io/the-field-that-schedules-your-world/)**\n\u003e — a plain-English tour of Constraint Programming and why the Nurse Scheduling\n\u003e Problem is the perfect way to learn it.\n\n[![CI](https://github.com/vpetreski/cp-deep-dive/actions/workflows/ci.yml/badge.svg)](https://github.com/vpetreski/cp-deep-dive/actions/workflows/ci.yml)\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)\n[![Python](https://img.shields.io/badge/python-3.12%2B-informational)](https://www.python.org/)\n[![Kotlin](https://img.shields.io/badge/kotlin-2.3%2B-7F52FF)](https://kotlinlang.org/)\n[![JDK](https://img.shields.io/badge/JDK-25_LTS-orange)](https://adoptium.net/)\n\n---\n\n## Estimated time to mastery\n\n| What | Hours |\n|---|---|\n| Reading + coding the 18 chapters (one concept → Python → Kotlin → MiniZinc) | **~66 h** |\n| Working through end-of-chapter exercises | **+20–30 h** |\n| Reading the linked papers and the OR-Tools / MiniZinc docs | **+5–10 h** |\n| **Total — cold start to \"I can model and solve a real production problem\"** | **~100–120 h** |\n\nMost people finish the 18-chapter spine in **2–3 weeks full-time**, or\n**about 3 months** at 8–10 hours a week. Time compresses significantly if you\nalready know one of the two languages or have prior OR / SAT experience.\n\nSee [`docs/plan.md`](docs/plan.md) for per-chapter hour targets and\n[`PROGRESS.md`](PROGRESS.md) for a personal tracker you can fork.\n\n---\n\n## Table of contents\n\n- [What you'll learn](#what-youll-learn)\n- [Who this is for](#who-this-is-for)\n- [The 18-chapter ladder](#the-18-chapter-ladder)\n- [What you'll build](#what-youll-build)\n- [Quick start](#quick-start)\n- [How to learn with this repo](#how-to-learn-with-this-repo)\n- [Track your progress](#track-your-progress)\n- [Using Claude Code (optional but recommended)](#using-claude-code-optional-but-recommended)\n- [Repo layout](#repo-layout)\n- [Tech stack](#tech-stack)\n- [Status](#status)\n- [Contributing, licence, citation](#contributing-licence-citation)\n\n---\n\n## What you'll learn\n\n- The vocabulary of Constraint Programming: variables, domains, propagation,\n  search, global constraints, symmetry breaking, linear relaxations.\n- How **OR-Tools CP-SAT** — Google's hybrid CP + SAT + LP solver — actually\n  works, and how to coax it into solving your problem *fast*.\n- How to model in **Python** with the first-party bindings, and in **Kotlin**\n  with our idiomatic DSL [`cpsat-kt`](libs/cpsat-kt/) that wraps the\n  OR-Tools Java API without leaking its Java-isms.\n- How to use **MiniZinc** as a declarative companion — write the model\n  solver-agnostically, then port it to CP-SAT by hand.\n- How to build a full **Nurse Scheduling Problem** solver and ship it behind\n  twin FastAPI / Ktor 3 backends with a Vite + React web UI.\n- How to **compare** CP-SAT against **Timefold** (ex-OptaPlanner local search)\n  and **Choco** (classic CP backtracking) on the same instances, so you know\n  when each solver wins.\n\n## Who this is for\n\n- **Software engineers** who have a real scheduling / allocation / routing\n  problem and want to learn CP well enough to model it.\n- **Data scientists and ML engineers** exploring combinatorial decision-making\n  beyond gradient-based optimisation.\n- **CS students** who've seen SAT / ILP in class and want to see CP at\n  production scale.\n- **Polyglots** who are comfortable in either Python or Kotlin and want to\n  build fluency in the other.\n\nYou don't need prior CP experience. You do need comfort with one modern\nprogramming language (Python or Kotlin), basic git, and a willingness to read\nrunnable code.\n\n## The 18-chapter ladder\n\n```\nPhase 1  Intuition + vocabulary           ch. 1–3     first working solve\nPhase 2  Core modelling                   ch. 4–6     puzzles, optimization, global constraints\nPhase 3  Bridges                          ch. 7–8     MiniZinc → CP-SAT\nPhase 4  Scheduling primitives            ch. 9–10    job-shop + shifts\nPhase 5  Nurse Scheduling I / II / III    ch. 11–13   hard → soft → benchmarks\nPhase 6  Your own DSL library             ch. 14      cpsat-kt internals\nPhase 7  End-to-end NSP application       ch. 15–17   backends, frontend, deploy\nPhase 8  Ecosystem                        ch. 18      Timefold, Choco, retro\n```\n\nFull breakdown with hours and concrete deliverables per chapter:\n[`docs/plan.md`](docs/plan.md).\n\n## What you'll build\n\nWorking by the end of the curriculum:\n\n1. **`cpsat-kt`** — an idiomatic Kotlin DSL over OR-Tools CP-SAT, published\n   as v0.1.0 in this repo under `libs/cpsat-kt/` (41+ Kotest specs passing,\n   ready for Maven Central).\n2. **`nsp-core`** — a shared NSP solver library in both Python\n   (`apps/py-cp-sat/nsp-core/`) and Kotlin (`apps/kt-cp-sat/nsp-core/`).\n3. **`py-api` / `kt-api`** — two production-grade backends for the same\n   [OpenAPI 3.1 contract](apps/shared/openapi.yaml): FastAPI + SQLModel +\n   SSE, and Ktor 3 + Exposed + SSE. Same endpoints, same schemas,\n   byte-for-byte identical `/openapi.yaml` output, 30 and 17 tests respectively.\n4. **`web`** — a Vite + React 19 + React Router v7 frontend: instance upload,\n   live solve view (SSE-streamed incumbents), schedule / coverage / Gantt\n   views, infeasibility explorer, backend switch, dark mode.\n5. **Timefold and Choco ports** — the same NSP, solved two other ways, with\n   a benchmark harness that runs all three solvers on every instance and\n   emits CSV + per-run JSON under `benchmarks/results/`.\n\n## Quick start\n\n```bash\n# 1. Clone\ngit clone https://github.com/vpetreski/cp-deep-dive.git\ncd cp-deep-dive\n\n# 2. Read the overview + the plan (30 min)\n$EDITOR docs/overview.md docs/plan.md\n\n# 3. Open Chapter 1 and follow from there\n$EDITOR docs/chapters/01-what-is-cp.md\n```\n\nPer-language prerequisites (install only when you reach the phase that needs\nthem — each chapter README tells you):\n\n- **Python chapters (Phase 2+):** Python 3.12+, [uv](https://github.com/astral-sh/uv).\n  Then in the chapter directory: `uv sync --all-packages \u0026\u0026 uv run pytest`.\n- **Kotlin chapters (Phase 2+):** JDK 25 ([Temurin via SDKMAN](https://sdkman.io/)).\n  Then: `./gradlew test` (Gradle comes from the wrapper).\n- **MiniZinc chapters (Phase 3):** [MiniZinc 2.8+](https://www.minizinc.org/software.html).\n- **App build (Phase 7):** Node 22 LTS, Docker (for containerisation demo).\n\nTo run the finished end-to-end app today:\n\n```bash\n# Python backend\ncd apps/py-api \u0026\u0026 uv sync \u0026\u0026 uv run uvicorn py_api.main:app --reload\n\n# Kotlin backend (in another shell)\ncd apps/kt-api \u0026\u0026 ./gradlew run\n\n# Web UI (in a third shell)\ncd apps/web \u0026\u0026 npm ci \u0026\u0026 npm run dev\n```\n\nOpen `http://localhost:5173`, upload `data/nsp/toy-01.json`, and watch it solve.\n\n## How to learn with this repo\n\nLinear, one chapter at a time:\n\n1. Read `docs/chapters/NN-*.md` — intuition → formal → worked example.\n2. Run the **Python** code: `cd apps/py-cp-sat/chNN-* \u0026\u0026 uv run python -m \u003cpkg\u003e`.\n3. Run the **Kotlin** twin: `cd apps/kt-cp-sat/chNN-* \u0026\u0026 ./gradlew run`.\n4. Skim the MiniZinc model if the chapter has one in `apps/mzn/`.\n5. Do the 3–5 exercises at the end of the chapter; hidden answers live in\n   `solutions/` next to the exercise.\n6. Tick the chapter off in your fork's `PROGRESS.md`, commit, move on.\n\nDon't skip the Kotlin twin even if you're only here for Python (or vice\nversa): translating a model into a second language is the single best trick\nfor understanding *what the model actually means* rather than what it looks\nlike in one dialect.\n\n## Track your progress\n\n[`PROGRESS.md`](PROGRESS.md) is a personal, markdown-only tracker. Fork the\nrepo, open that file in your copy, and tick items off as you go. It has\nper-chapter checkboxes, space for estimated vs actual hours, a log for\nexercise answers, and prompts for end-of-phase reflection.\n\nBecause it's ordinary markdown, you can:\n\n- edit it in your editor or on GitHub directly;\n- commit it on your own branch (`learn/\u003cyou\u003e`) to have a history of your\n  progress;\n- ask Claude Code (see below) to \"update `PROGRESS.md` with what I just\n  finished\" — Claude can edit it the same way you can.\n\n## Using Claude Code (optional but recommended)\n\nThis repo was written alongside [Claude Code](https://claude.com/claude-code),\nand is instrumented for agentic collaboration:\n\n- **[`CLAUDE.md`](CLAUDE.md)** declares project-wide rules and routing\n  (where to write docs, which files are authoritative, commit conventions)\n  so Claude behaves consistently across sessions.\n- **[QMD](https://github.com/tobi/qmd)** indexes `docs/knowledge/` so Claude\n  can semantically retrieve chunks instead of reading whole files. The\n  `.mcp.json` in the repo root wires QMD in as an MCP server. A post-commit\n  hook re-indexes automatically.\n- **`claude-memory/`** (mirrored from `~/.claude/projects/\u003cslug\u003e/memory/`\n  per machine via `tools/setup-memory-hook.sh`) stores conversation-spanning\n  facts about you and how you like to work. Lives outside `.claude/` because\n  the latter is a hardcoded protected-path prefix that prompts on every edit.\n\nYou can absolutely learn the material without any of this — it's all plain\nmarkdown and code. But with Claude Code attached, you can:\n\n- ask \"why does CP-SAT prefer `AddAllowedAssignments` here?\" and get an\n  explanation grounded in the current chapter's knowledge docs;\n- paste an error from your exercise attempt and get a focused hint;\n- say \"mark Chapter 7 done in PROGRESS.md and open Chapter 8\" and have it\n  happen.\n\nPer-machine setup if you want the full experience:\n\n```bash\n./tools/setup-memory-link.sh     # once per machine\n./tools/setup-qmd-hook.sh        # once per machine\nqmd collection add docs --name cp-deep-dive-docs\nqmd update \u0026\u0026 qmd embed\n```\n\n## Repo layout\n\n```\ncp-deep-dive/\n├── README.md                    ← you are here\n├── CLAUDE.md                    ← project rules + agent routing\n├── PROGRESS.md                  ← personal learner tracker (fork \u0026 fill)\n├── CONTRIBUTING.md CODE_OF_CONDUCT.md SECURITY.md CHANGELOG.md CITATION.cff\n├── LICENSE (Apache-2.0) NOTICE\n├── docs/\n│   ├── overview.md              ← the field in one page\n│   ├── plan.md                  ← 18-chapter roadmap, hours, deliverables\n│   ├── chapters/                ← per-chapter teaching notes\n│   ├── knowledge/               ← reference encyclopedia (QMD-indexed)\n│   │   ├── cp-theory/ cp-sat/ cpsat-kt/ minizinc/\n│   │   ├── nurse-scheduling/ ecosystem/\n│   └── adr/                     ← architecture decision records\n├── libs/cpsat-kt/               ← our Kotlin DSL over OR-Tools CP-SAT\n├── specs/nsp-app/               ← locked v1.0 NSP app spec (11 files)\n├── apps/\n│   ├── py-cp-sat/               ← Python chapter code (ch02–ch13 + nsp-core)\n│   ├── kt-cp-sat/               ← Kotlin chapter code (ch02–ch13 + nsp-core)\n│   ├── mzn/                     ← MiniZinc teaching models\n│   ├── py-api/                  ← FastAPI NSP backend (Phase 7)\n│   ├── kt-api/                  ← Ktor 3 NSP backend (Phase 7)\n│   ├── web/                     ← Vite + React 19 + RR7 NSP frontend\n│   ├── shared/                  ← OpenAPI 3.1 + JSON Schemas\n│   └── alt-solver/              ← Timefold + Choco NSP ports\n├── benchmarks/                  ← cross-solver benchmark runner + baselines\n├── data/nsp/                    ← NSP instances (toy + NSPLib + INRC pointers)\n├── tools/                       ← Claude Code + QMD setup scripts\n└── .github/workflows/           ← CI (Python, Kotlin, Web jobs)\n```\n\n## Tech stack\n\n| Layer | Choice |\n|---|---|\n| Python | 3.12+ via [uv](https://github.com/astral-sh/uv) |\n| JVM | JDK 25 LTS |\n| Kotlin | 2.3+, Gradle 9.4+ Kotlin DSL |\n| Node | 22 LTS |\n| Primary solver | OR-Tools CP-SAT 9.15+ |\n| Kotlin DSL | [`cpsat-kt`](libs/cpsat-kt/) (ours, published from this repo) |\n| Modelling companion | MiniZinc 2.8+ |\n| Python backend | FastAPI + SQLModel + sse-starlette + Pydantic v2 |\n| Kotlin backend | Ktor 3.x + Exposed + kotlinx.coroutines |\n| Frontend | Vite + React 19 + React Router v7 + TypeScript 5 + Tailwind + shadcn/ui + TanStack Query |\n| Testing | pytest + Hypothesis (Py), Kotest 5 (Kt), Vitest + Playwright (Web) |\n| Lint | ruff + mypy --strict (Py), ktlint + detekt (Kt), eslint + `tsc --noEmit` (Web) |\n| Containers | Docker, Docker Compose |\n| CI | GitHub Actions |\n\n## Status\n\n**v0.1.0 — the curriculum is complete and runnable end-to-end.**\n\n- ✅ 18 chapters written (`docs/chapters/`)\n- ✅ `cpsat-kt` v0.1.0 with tests green\n- ✅ Python nsp-core + Kotlin nsp-core libraries\n- ✅ FastAPI backend (13 endpoints, 30 tests) and Ktor backend (13 endpoints, 17 tests)\n- ✅ Web UI (9 routes, instance upload, live solve, schedule / coverage / Gantt / infeasibility views)\n- ✅ Timefold + Choco ports\n- ✅ Benchmark harness with baseline results for CP-SAT, Choco, Timefold on `toy-01` and `toy-02`\n- ✅ NSP spec v1.0 locked (`specs/nsp-app/`)\n- ✅ GitHub Actions CI green (Python, Kotlin, Web)\n\nSee [`CHANGELOG.md`](CHANGELOG.md) for the full release notes.\n\n## Contributing, licence, citation\n\n- **Contributing:** see [`CONTRIBUTING.md`](CONTRIBUTING.md). Typo fixes and\n  clearer explanations are especially welcome; bigger changes should start as\n  an issue. The `cpsat-kt` library accepts feature PRs under semver.\n- **Code of Conduct:** [`CODE_OF_CONDUCT.md`](CODE_OF_CONDUCT.md) (Contributor\n  Covenant 2.1).\n- **Security:** private report flow in [`SECURITY.md`](SECURITY.md).\n- **Licence:** [Apache-2.0](LICENSE) — same as OR-Tools, with third-party\n  attributions in [`NOTICE`](NOTICE).\n- **Citation:** [`CITATION.cff`](CITATION.cff) — the \"Cite this repository\"\n  button on GitHub uses it.\n\nIf this curriculum helped you ship a real-world optimisation project, a\none-line note in the issue tracker would make the author's week.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvpetreski%2Fcp-deep-dive","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvpetreski%2Fcp-deep-dive","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvpetreski%2Fcp-deep-dive/lists"}