ortidy
OR (operations research) on tidy dataframes — a backend-agnostic dataframe façade over Google OR-Tools.
ortidyis the revival ofpandas-or, rebuilt around Narwhals so it works natively with pandas, Polars, and more — pandas in, pandas out; Polars in, Polars out.pandas-orusers: see Migrating.
The thesis: bridge operations research and the data ecosystem so solver outputs come back as tidy dataframes ready for analysis, plotting, and dashboards.
Installation
pip install ortidy
ortidy brings its own OR-Tools. Bring your own dataframe backend (pandas,
polars, …) — install whichever you already use.
Quickstart
Every solver accepts a native frame, returns the same backend, and hands back
a SolveResult carrying the result frame, a status, the objective, and
solve metadata.
import pandas as pd
import ortidy
items = pd.DataFrame({"value": [60, 100, 120], "weight": [10, 20, 30]})
result = ortidy.knapsack(items, capacity=50)
print(result.status) # SolveStatus.OPTIMAL
print(result.objective) # 220
print(result.frame) # items + an `isIncluded` boolean column
Every solver is a plain function — pass a native frame (pandas, Polars, …) and
get a SolveResult back in the same backend.
Result contract
Three result shapes cover every solver:
| Shape | Solvers | Result |
|---|---|---|
| selection | knapsack, multi_knapsack, bin_packing |
rows mapped to bins/resources |
| edge-flow | solve_routing (more in progress) |
values on an edge list |
| interval-schedule | scheduling (roadmap) | intervals on a timeline |
Every solver returns a SolveResult:
result.frame # native dataframe, same backend as the input
result.status # OPTIMAL / FEASIBLE / INFEASIBLE / UNBOUNDED / MODEL_INVALID
result.objective # objective value (None when no solution)
result.metadata # solver name, wall time, bounds, …
bool(result) # True when OPTIMAL or FEASIBLE — a FEASIBLE solution is a success
Solvers
| Shape | Function | Problem |
|---|---|---|
| selection | knapsack |
0/1 & multidimensional knapsack |
| selection | multi_knapsack |
multiple knapsack |
| selection | bin_packing |
bin packing (minimize bins) |
| selection | assignment |
linear assignment (+ teams / allowed groups) |
| selection | generalized_assignment |
GAP (capacity-limited agents) |
| selection | facility_location |
uncapacitated facility location |
| selection | set_cover |
set cover / partition |
| selection | blend |
diet / blending LP (continuous quantities) |
| edge-flow | max_flow / min_cost_flow / shortest_path |
network flow |
| edge-flow | transportation |
transportation problem |
| edge-flow | solve_routing (+ distance_matrix) |
routing (TSP/VRP/CVRP/VRPTW/pickups/optional visits) |
| interval-schedule | shift_scheduling |
employee rostering |
| interval-schedule | job_shop |
job-shop scheduling |
| interval-schedule | interval_assignment |
fixed-time tasks → min-cost resources (rotations, gates) |
See the docs for a worked example of each.
Sample datasets ship with the package:
from ortidy import data
items = data.items_knapsack() # pandas by default
items = data.items_knapsack("polars") # or Polars
Examples
Runnable notebooks live in examples/ — knapsack/bin-packing, a
haversine world-tour TSP, and capacitated vehicle routing, each plotted with
Plotly. Try them in your browser with no install:
Migrating from pandas-or
ortidy is pandas-or renamed and rebuilt. Install ortidy and import ortidy
(the old pandas-or 0.1.3 on PyPI is unmaintained). The key changes:
- Solvers return a
SolveResultobject, not a bare frame /None. - Rows are identified by explicit id columns, never a positional index.
- The backend is whatever you pass in (pandas, Polars, …), not just pandas.
License
Apache-2.0.
Metadata
Release files for ortidy 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ortidy-0.6.0.tar.gz | 240.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ortidy-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 293.9 kB
Release files / ortidy-0.6.0.tar.gz
| Download URL | ortidy-0.6.0.tar.gz |
|---|---|
| Size | 240.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a72ad6315641dbb0777bf0e105cb51cb4cbc9b37c10e6e3b721ee3583ef80d43
|
|
BLAKE2b-256 checksum How to use checksums |
7c29d657cfe4bc35bc91b97ec9f2f76396f8078daf9c76428da4997aad35ab4e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / ortidy-0.6.0-py3-none-any.whl
| Download URL | ortidy-0.6.0-py3-none-any.whl |
|---|---|
| Size | 53.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
874d0ae72839b0707be548d3426b55375c2aba48cfda6bdc6650c95699f57bb0
|
|
BLAKE2b-256 checksum How to use checksums |
9e04b412ea80bed8659100e75e8594710190749c8165e83cd322b854cd05f3c6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|