Metadata-Version: 2.5
Name: lp2graph
Version: 0.4.0
Summary: Typed-graph representation of LP, MIP, and MILP formulations.
Project-URL: Homepage, https://github.com/joernmht/lp2graph
Project-URL: Documentation, https://github.com/joernmht/lp2graph#readme
Project-URL: Issues, https://github.com/joernmht/lp2graph/issues
Project-URL: Source, https://github.com/joernmht/lp2graph
Author: lp2graph contributors
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: gnn,graph,linear-programming,milp,optimization
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.11
Requires-Dist: jsonschema>=4.0
Requires-Dist: pydantic>=2.0
Provides-Extra: all
Requires-Dist: hdbscan>=0.8; extra == 'all'
Requires-Dist: highspy>=1.7; extra == 'all'
Requires-Dist: networkx>=3.0; extra == 'all'
Requires-Dist: nltk>=3.8; extra == 'all'
Requires-Dist: pulp<4,>=2.8; extra == 'all'
Requires-Dist: pyomo>=6.7; extra == 'all'
Requires-Dist: torch-geometric>=2.4; extra == 'all'
Requires-Dist: torch>=2.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: jsonschema>=4.0; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: networkx>=3.0; extra == 'dev'
Requires-Dist: pre-commit>=3.6; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff<0.16,>=0.15.12; extra == 'dev'
Provides-Extra: dgl
Requires-Dist: dgl>=2.0; (python_version < '3.13') and extra == 'dgl'
Requires-Dist: torch>=2.0; extra == 'dgl'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.25; extra == 'docs'
Provides-Extra: gurobi
Requires-Dist: gurobipy>=11.0; extra == 'gurobi'
Provides-Extra: mining
Requires-Dist: hdbscan>=0.8; extra == 'mining'
Requires-Dist: networkx>=3.0; extra == 'mining'
Requires-Dist: nltk>=3.8; extra == 'mining'
Requires-Dist: pyomo>=6.7; extra == 'mining'
Provides-Extra: networkx
Requires-Dist: networkx>=3.0; extra == 'networkx'
Provides-Extra: pyg
Requires-Dist: torch-geometric>=2.4; extra == 'pyg'
Requires-Dist: torch>=2.0; extra == 'pyg'
Provides-Extra: pyomo
Requires-Dist: pyomo>=6.7; extra == 'pyomo'
Provides-Extra: solver
Requires-Dist: highspy>=1.7; extra == 'solver'
Requires-Dist: pulp<4,>=2.8; extra == 'solver'
Description-Content-Type: text/markdown

# lp2graph

[![ci](https://github.com/joernmht/lp2graph/actions/workflows/ci.yml/badge.svg)](https://github.com/joernmht/lp2graph/actions/workflows/ci.yml)
[![docs](https://github.com/joernmht/lp2graph/actions/workflows/docs.yml/badge.svg)](https://github.com/joernmht/lp2graph/actions/workflows/docs.yml)
[![PyPI](https://img.shields.io/pypi/v/lp2graph.svg)](https://pypi.org/project/lp2graph/)
[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE)

**Typed-graph representation of LP, MIP, and MILP formulations.**

`lp2graph` is a focused library for representing optimization problems as
typed graphs and deriving multiple views of them — schema, hybrid, and
ground — from a single canonical data model. It ships:

- A version-stable JSON schema for formulations.
- Three view derivations that turn a formulation into a typed graph.
- Structural metrics computed deterministically over the model and views.
- SVG renderers and a static interactive viewer.
- Export adapters to PyG, DGL, NetworkX, LaTeX, and Pyomo.

The core has no solver dependency. Pyomo, JuMP, and friends are optional
extras.

## Install

```bash
pip install lp2graph                       # core only
pip install "lp2graph[networkx]"           # NetworkX export
pip install "lp2graph[pyg]"                # PyG export
pip install "lp2graph[all]"                # everything
```

## 60-second tour

```python
from lp2graph import load
from lp2graph.views import schema, hybrid, ground
from lp2graph.metrics.structural import structural_summary
from lp2graph.metrics.flags import presence_flags
from lp2graph.render.svg import render_svg

f = load("formulations/constraints/mip_2_1_big_m.json")

# Three views from one canonical model.
g_schema  = schema(f)                       # templates and indices
g_hybrid  = hybrid(f)                       # + offset-labeled edges
g_ground  = ground(f, {"I": 4})             # + degeneracy filters

# Metrics, deterministic.
print(structural_summary(g_schema)["graph_diameter"].value)
print(presence_flags(f)["has_big_m"].value)

# Render with the deliberate visual identity.
open("graph.svg", "w").write(render_svg(g_hybrid, title=f.name))
```

Or from the command line:

```bash
lp2graph validate formulations/constraints/lp_1_1_fixed_sequence.json
lp2graph render   formulations/constraints/mip_2_1_big_m.json --view hybrid --output mip_2_1.svg
lp2graph metrics  formulations/constraints/mip_2_4_time_indexed.json
lp2graph export   formulations/constraints/mip_2_8_pesp.json --format latex
```

## Text ⇄ graph, and solving (deterministic, no LLM)

Beyond the views, lp2graph offers a **bidirectional, deterministic**
interface between a formulation's *text* and its *graph*, plus a real
solver back-end:

```bash
# graph -> paper-style LaTeX (\mathcal sets, \sum, \forall, big-M) and back
lp2graph latex   formulations/constraints/pesp_solvable.json --output pesp.tex
lp2graph parse   pesp.tex                         # LaTeX -> canonical JSON

# ground with instance data and solve the MILP (CBC / HiGHS / Gurobi)
lp2graph solve   formulations/constraints/assignment.json \
                 --instance corpus/validation/codec_pipeline/instances/assignment_4x4.json

# graph -> natural-language problem description (+ data tables)
lp2graph describe formulations/constraints/pesp_solvable.json --instance ...
```

```python
from lp2graph import load, to_canonical_latex, from_canonical_latex, describe
from lp2graph.solve import Instance, solve

f = load("formulations/constraints/assignment.json")
g = from_canonical_latex(to_canonical_latex(f))   # text round-trips the graph
print(solve(g, Instance(cardinalities={"W": 4, "J": 4},
                        parameters={"c": [[9, 2, 7, 8], ...]})).objective)
```

The codec is a tested fixed point and the solvable content round-trips
exactly; an [end-to-end suite](corpus/validation/codec_pipeline/) confirms
the JSON→LaTeX→parse→ground→solve loop reproduces independently-known
optima across CBC/HiGHS/Gurobi. See
[`docs/text-graph-interface.md`](docs/text-graph-interface.md).

## What goes in, what comes out

A **formulation** is a JSON document validated against
[`schema/canonical.schema.json`](schema/canonical.schema.json). It declares
*index families* (e.g. `I`, `T`), *parameters*, *variable templates*,
*constraint templates* with quantifiers and bindings, and an optional
*objective* with first-class terms.

`load()`/`loads()` enforce that schema on every document before the typed
model sees it, so a file that violates the published contract is refused with
spec-grounded messages naming the source. The schema ships inside the package;
read it with the accessor rather than by path, since its location differs
between a wheel and a source checkout:

```python
import lp2graph
schema = lp2graph.canonical_schema()        # parsed dict, cached
path = lp2graph.canonical_schema_path()     # on-disk location
```

The **schema view** exposes templates and indices — the topology of the
problem. The **hybrid view** adds per-term offset, sign, and modulo
labels. The **ground view** materializes every instance at given index
cardinalities and applies degeneracy filters.

See [`docs/data-model.md`](docs/data-model.md) and
[`docs/views.md`](docs/views.md) for the long form.

## Status

v0.1 is an alpha. The schema and the canonical model are stable for a
representative cross-section of formulations; the catalog is in active
expansion. Tracked open questions live as `open-question` issues so they
are visible.

## Documentation

- [Data model](docs/data-model.md)
- [Views](docs/views.md)
- [Metrics](docs/metrics.md)
- [Add a formulation](docs/add-a-formulation.md)
- [Design context](docs/design-context.md) (the seed document)
- [Extraction report](docs/extraction-report.md) (provenance from the source repo)
- ADRs in [`docs/adr/`](docs/adr/)

## Contributing

See [`CONTRIBUTING.md`](CONTRIBUTING.md). Bugs, new formulations, design
decisions, and good-first-issues all have dedicated templates.

## AI disclaimer

This repository was developed with substantial assistance from AI coding tools
(primarily Anthropic's Claude). Code, documentation and results have been
reviewed by the author, who takes full responsibility for the content.

## License

Apache 2.0. Portions adapted from
[`joernmht/raiLPminerExperimentation`](https://github.com/joernmht/raiLPminerExperimentation)
under MIT — see [`docs/extraction-report.md`](docs/extraction-report.md).
