{"id":51672993,"url":"https://github.com/coldsmirk/oxidor","last_synced_at":"2026-07-15T02:33:48.194Z","repository":{"id":370990973,"uuid":"1297207751","full_name":"coldsmirk/oxidor","owner":"coldsmirk","description":"Unofficial Rust bindings for Google OR-Tools","archived":false,"fork":false,"pushed_at":"2026-07-12T14:25:56.000Z","size":461,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-12T15:11:32.928Z","etag":null,"topics":["bindings","constraint-programming","cp-sat","operations-research","optimization","or-tools","ortools","rust"],"latest_commit_sha":null,"homepage":null,"language":"Rust","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/coldsmirk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-07-11T06:57:52.000Z","updated_at":"2026-07-12T14:26:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/coldsmirk/oxidor","commit_stats":null,"previous_names":["coldsmirk/oxidor"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/coldsmirk/oxidor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldsmirk%2Foxidor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldsmirk%2Foxidor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldsmirk%2Foxidor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldsmirk%2Foxidor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coldsmirk","download_url":"https://codeload.github.com/coldsmirk/oxidor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coldsmirk%2Foxidor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35488230,"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-15T02:00:06.706Z","response_time":131,"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":["bindings","constraint-programming","cp-sat","operations-research","optimization","or-tools","ortools","rust"],"created_at":"2026-07-15T02:33:48.095Z","updated_at":"2026-07-15T02:33:48.188Z","avatar_url":"https://github.com/coldsmirk.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Oxidor\n\n**Unofficial Rust bindings for [Google OR-Tools](https://developers.google.com/optimization).**\n\n\u003e Status: early development (0.1.x, **not yet published to crates.io** — use a\n\u003e git dependency until the first release lands). Four solver families work end\n\u003e to end — CP-SAT, MathOpt (LP/MIP), routing (TSP/VRP), and the classic\n\u003e algorithms — verified by CI on three platforms. MSRV 1.85.\n\nOxidor binds the OR-Tools C++ solvers through a deliberately thin boundary:\nmodels are built as protobuf messages in pure Rust, and only `solve()`\ncrosses the FFI line — through the official C API where it suffices (CP-SAT;\nthe same architecture Google chose for its official Go bindings), and through\nOxidor's own exception-safe C shim where the C API is missing or too narrow\n(routing, the algorithms, MathOpt solve parameters, CP-SAT solution\ncallbacks). No C++ type ever surfaces in the API.\n\n## Quick start\n\n```toml\n[dependencies]\n# Zero local setup: the build downloads a SHA-256-verified static OR-Tools\n# bundle from this project's releases (see the platform table below).\noxidor = { git = \"https://github.com/coldsmirk/oxidor\", features = [\"download-prebuilt\"] }\n```\n\n```rust\nuse oxidor::CpModelBuilder;\n\nlet mut model = CpModelBuilder::new();\nlet x = model.new_int_var(0..=10);\nlet y = model.new_int_var(0..=10);\nmodel.add_less_or_equal(x + y, 14);\nmodel.maximize(2 * x + 3 * y);\n\nlet response = model.solve();\nif let Some(solution) = response.solution() {\n    println!(\"x = {}, y = {}\", solution.value(x), solution.value(y));\n}\n```\n\nLong solves take a first-class time limit\n(`model.solve_with_time_limit(Duration::from_secs(10))`), and every other\nCP-SAT knob is reachable through `solve_with_parameters(\u0026SatParameters { … })`.\nThe constraint catalog is complete: linear (in)equalities, Booleans,\n`all_different`, min/max/abs, integer product/division/modulo, `element`,\ntables, circuits, automata, reservoirs, intervals with `no_overlap` /\n`no_overlap_2d` / `cumulative`, inverse permutations, plus solution hints and\nassumptions. Streaming solution callbacks\n(`solve_with_solution_callback`) observe every feasible solution as the\nsearch finds it and can stop early; a raw `solve_model_proto` entry solves\nhand-built or hand-modified `CpModelProto`s.\n\nFor a real scheduling model — nurses, days, shifts, even workloads — see\n[`oxidor-cpsat/examples/nurse_scheduling.rs`](oxidor-cpsat/examples/nurse_scheduling.rs):\n\n```text\ncargo run -p oxidor-cpsat --example nurse_scheduling\n```\n\n## Getting the native library\n\nSolving needs the OR-Tools native library, obtained one of three ways:\n\n- **`download-prebuilt` feature** — fetches a static OR-Tools bundle built by\n  this project's CI from its GitHub releases (SHA-256 pinned in the crate,\n  cached under `~/.cache/oxidor`) and links it statically: no local setup,\n  self-contained binaries. Covers CP-SAT, routing, and the algorithms;\n  MathOpt's solver registry needs the dynamic library, so use\n  `ORTOOLS_PREFIX` for it.\n- **`ORTOOLS_PREFIX`** — point it at an extracted official [C++ release\n  archive](https://github.com/google/or-tools/releases) (dynamic linking, all\n  solvers; always wins when set):\n\n  ```sh\n  export ORTOOLS_PREFIX=/path/to/extracted/or-tools\n  ```\n\n- **Model building alone** (`default-features = false`) — pure Rust, needs\n  nothing.\n\nPrebuilt bundles currently exist for:\n\n| Target | `download-prebuilt` |\n|---|---|\n| `aarch64-apple-darwin` | ✅ |\n| `x86_64-unknown-linux-gnu` | ✅ |\n| `aarch64-unknown-linux-gnu` | ✅ |\n| `x86_64-apple-darwin` | ❌ — use `ORTOOLS_PREFIX` |\n| Windows | ❌ — untested altogether; `ORTOOLS_PREFIX` may work but is not covered by CI |\n\n## Beyond CP-SAT\n\nReach for CP-SAT when the problem is combinatorial (discrete choices,\nscheduling rules, logical conditions); reach for **MathOpt** when it is a\nclassic LP/MIP over continuous or integer quantities, with the solver chosen\nper call (Glop, SCIP, CP-SAT, and PDLP ship in the official archives):\n\n```rust\nuse oxidor::mathopt::{Model, SolverType};\n\nlet mut model = Model::new();\nlet x = model.new_continuous_variable(0.0..=10.0);\nlet y = model.new_continuous_variable(0.0..=10.0);\nmodel.add_less_or_equal(x + y, 14.0);\nmodel.maximize(2.0 * x + 3.0 * y);\n\nlet result = model.solve(SolverType::Glop)?;\nif let Some(solution) = result.primal_solution() {\n    println!(\"x = {}, y = {}\", solution.value(x), solution.value(y));\n}\n```\n\nMathOpt solves take per-call parameters (`solve_with_parameters` — time and\nsolution limits, gap tolerances, threads, seed) and a first-class\n`solve_with_time_limit`. Picking a `SolverType` the linked library does not\nregister fails cleanly with a `SolveError`; probe availability up front with\n`oxidor::mathopt::registered_solvers()`.\n\nLong solves can be stopped from another thread — CP-SAT via\n`StopToken`/`Stopper`, MathOpt via `SolveInterrupter` — and CP-SAT can\nenumerate a model's full solution set (`SolveResponse::solutions()`).\n\nVehicle routing (`routing` feature) works over a distance matrix and scales\nfrom a plain TSP to a VRP with capacities, time windows (a `TimeDimension`\nwith travel times, service times, and per-node windows — solutions then\nreport per-stop arrival times), pickup-and-delivery pairs, and per-vehicle\nfixed costs. The classic algorithms (`algorithms` feature) come as plain\ncalls:\n\n```rust\nuse oxidor::routing::RoutingProblem;\nuse oxidor::algorithms::solve_knapsack;\n\nlet response = RoutingProblem::from_matrix(matrix)?\n    .with_vehicles(2)\n    .with_capacities(demands, capacities)\n    .solve()?;\nif let Some(tour) = response.solution() {\n    println!(\"cost {}: {:?}\", tour.objective_value(), tour.routes());\n}\n\nlet packing = solve_knapsack(\u0026[60, 100, 120], \u0026[10, 20, 30], 50)?;\n```\n\nSolving compiles Oxidor's own small C++ shim (routing, the algorithm\nclasses, MathOpt parameters, and CP-SAT observers have no — or too narrow an\n— upstream C API), which needs the OR-Tools headers and a C++20 compiler;\nofficial archives and the prebuilt bundles both ship the headers. Every shim\nentry point catches C++ exceptions; they never cross into Rust.\n\n## Workspace layout\n\n| Crate | Role |\n|---|---|\n| [`oxidor`](oxidor/) | Umbrella crate: re-exports the per-solver APIs behind feature flags |\n| [`oxidor-cpsat`](oxidor-cpsat/) | Idiomatic API for the CP-SAT constraint programming solver |\n| [`oxidor-mathopt`](oxidor-mathopt/) | Idiomatic API for MathOpt: LP/MIP over Glop, SCIP, CP-SAT, PDLP |\n| [`oxidor-routing`](oxidor-routing/) | TSP / VRP with capacities, time windows, pickups-deliveries |\n| [`oxidor-algorithms`](oxidor-algorithms/) | Knapsack, max flow, min cost flow, linear sum assignment |\n| [`oxidor-protos`](oxidor-protos/) | Generated protobuf model types (pure Rust, committed to the repo) |\n| [`oxidor-sys`](oxidor-sys/) | Native library location, linkage, raw FFI, and the C++ shim |\n| [`xtask`](xtask/) | Maintainer tasks (`cargo run -p xtask -- gen-protos`); not published |\n\n## Development\n\n```sh\n# One-time setup: fetch the OR-Tools v9.15 C++ archive for your platform from\n#   https://github.com/google/or-tools/releases/tag/v9.15\n# and extract it to .ortools/v9.15 (gitignored), e.g. on Apple silicon:\nmkdir -p .ortools \u0026\u0026 cd .ortools\ncurl -L -o ortools.tar.gz https://github.com/google/or-tools/releases/download/v9.15/or-tools_arm64_macOS-26.2_cpp_v9.15.6755.tar.gz\ntar xzf ortools.tar.gz \u0026\u0026 mv or-tools_* v9.15 \u0026\u0026 rm ortools.tar.gz \u0026\u0026 cd ..\n\ncargo test --workspace   # .cargo/config.toml points ORTOOLS_PREFIX at .ortools/v9.15\n```\n\n`cargo run -p xtask -- gen-protos` regenerates `oxidor-protos/src/generated/`\nfrom the vendored `.proto` files (pure Rust via protox — no `protoc` needed);\nthe output is committed.\n\n## Roadmap\n\n1. **CP-SAT** — ✅ model builder with the full constraint catalog, solve\n   (+ first-class time limit and full `SatParameters`), interruptible solve\n   (`StopToken`/`Stopper`), solution enumeration, streaming solution\n   callbacks with early stop, hints/assumptions, raw-proto solve. Next:\n   possibly typed accessors for more response statistics.\n2. **Linear solving (MathOpt)** — ✅ LP/MIP model builder, per-call solver\n   choice (Glop / SCIP / CP-SAT / PDLP), per-solve parameters + time limit,\n   solver-registry probing, interruption, clean error paths. Next: dual\n   solution accessors (available today via `SolveResult::raw`).\n3. **Routing (VRP/TSP)** — ✅ TSP/CVRP over a distance matrix, time windows\n   with per-stop arrival times, pickups/deliveries, per-vehicle fixed costs;\n   search parameters as protos. Next: Rust transit callbacks (the callback\n   trampoline infrastructure already exists for CP-SAT), disjunctions /\n   optional visits.\n4. **Algorithms** — ✅ knapsack (multi-dimensional branch and bound), max\n   flow, min cost flow, linear sum assignment.\n5. **Distribution** — ✅ CI test matrix on three platforms; prebuilt static\n   bundles consumed by `download-prebuilt` (checksums pinned in-crate, e2e\n   tested in CI). Next: more targets (Intel macOS, Windows), a `vendored`\n   source-build mode, and the first crates.io release.\n\n## License\n\nApache-2.0, the same license as OR-Tools. This project is not affiliated\nwith or endorsed by Google.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoldsmirk%2Foxidor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoldsmirk%2Foxidor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoldsmirk%2Foxidor/lists"}