Rust LP File Parser, Writer, and Diff Tool
April 20, 2026 · View on GitHub
A robust Rust library and CLI for parsing, analysing, modifying, and writing Linear Programming (LP) files. Built on LALRPOP; grammar lives in lp.lalrpop.
Supported specifications: IBM CPLEX v22.1.1, FICO Xpress, Gurobi, Mosek.
Features
- Parsing & writing — round-trip LP files (parse → modify → write → parse) with configurable formatting
- Problem modification — rename / update / remove objectives, constraints, variables, coefficients, and RHS values
- Variable types — integer, general, bounded, free, semi-continuous
- Analysis — statistics, matrix density, sparsity, coefficient ranges, issue detection with configurable thresholds
- Diff (
difffeature) — structural comparison between two LP files - Serialisation (
serdefeature) — JSON / YAML support - External solvers (
lp-solversfeature) — CBC, Gurobi, CPLEX, GLPK via the lp-solvers crate
Library Usage
Add to Cargo.toml:
[dependencies]
lp_parser_rs = { version = "3.0.0", features = ["serde", "diff"] } # x-release-please-version
Parse and inspect:
use lp_parser_rs::{parser::parse_file, problem::LpProblem};
use std::path::Path;
let content = parse_file(Path::new("problem.lp"))?;
let problem = LpProblem::parse(&content)?;
println!("{} objectives, {} constraints, {} variables",
problem.objective_count(), problem.constraint_count(), problem.variable_count());
Modify and write:
use lp_parser_rs::{problem::LpProblem, writer::write_lp_string, model::VariableType};
let mut problem = LpProblem::parse(&std::fs::read_to_string("problem.lp")?)?;
problem.update_objective_coefficient("profit", "x1", 5.0)?;
problem.rename_objective("profit", "total_profit")?;
problem.update_constraint_coefficient("capacity", "x1", 2.0)?;
problem.update_constraint_rhs("capacity", 200.0)?;
problem.rename_variable("x1", "production_a")?;
problem.update_variable_type("production_a", VariableType::Integer)?;
std::fs::write("modified.lp", write_lp_string(&problem)?)?;
Available modification methods on LpProblem: update_objective_coefficient, rename_objective, remove_objective, update_constraint_coefficient, update_constraint_rhs, rename_constraint, remove_constraint, rename_variable, update_variable_type, remove_variable.
Writer options: write_lp_string_with_options(&problem, &LpWriterOptions { include_problem_name, max_line_length, decimal_precision, include_section_spacing }).
Command-Line Interface (lp_parser)
Install
cargo install lp_parser_rs --all-features
# Or from source
git clone https://github.com/dandxy89/lp_parser_rs.git
cd lp_parser_rs/rust && cargo build --release --all-features
Global options
| Flag | Description |
|---|---|
-v, --verbose | Increase output verbosity (repeatable) |
-q, --quiet | Suppress non-essential output |
-h, --help / -V, --version | Print help / version |
parse — display file structure
| Option | Default | Description |
|---|---|---|
<FILE> | — | Path to the LP file (required) |
-o, --output <PATH> | stdout | Write output to file |
-f, --format <FMT> | text | text, json (serde), yaml (serde) |
--pretty | off | Pretty-print JSON/YAML |
lp_parser parse problem.lp
lp_parser parse problem.lp --format yaml -o problem.yaml
info — summary statistics
Adds to the parse options:
| Option | Description |
|---|---|
--variables | List all variables with their types |
--constraints | List all constraints |
--objectives | List all objectives |
lp_parser info problem.lp
lp_parser info problem.lp --variables --constraints --objectives
lp_parser info problem.lp --format json --pretty
analyze — structural analysis & issue detection
Adds to the parse options:
| Option | Default | Description |
|---|---|---|
--issues-only | off | Skip full analysis; show warnings/errors only |
--large-coeff-threshold <F> | 1e9 | Warn on coefficients larger than this |
--small-coeff-threshold <F> | 1e-9 | Warn on coefficients smaller than this |
--ratio-threshold <F> | 1e6 | Warn on coefficient scaling ratios above this |
lp_parser analyze problem.lp
lp_parser analyze problem.lp --issues-only
lp_parser analyze problem.lp --large-coeff-threshold 1e8 --ratio-threshold 1e5
lp_parser analyze problem.lp --format yaml -o analysis.yaml
Example output
summary: { name: diet, sense: Minimize, objective_count: 1, constraint_count: 7, variable_count: 16, density: 0.571 }
variables: { type_distribution: { upper_bounded: 9, double_bounded: 7 }, discrete_variable_count: 0 }
constraints: { type_distribution: { equality: 7 }, rhs_range: { min: 30.0, max: 50000.0 } }
coefficients: { constraint_coeff_range: { min: 0.1, max: 3055.2 }, coefficient_ratio: 101840.0 }
issues: []
diff — compare two LP files (requires diff feature)
| Option | Default | Description |
|---|---|---|
<FILE1> <FILE2> | — | Base and comparison files |
-o, --output <PATH> | stdout | Write output to file |
-f, --format <FMT> | text | text, json, yaml |
--pretty | off | Pretty-print structured output |
--abs-tol <F> | 0.0 | Absolute tolerance for numeric comparisons |
--rel-tol <F> | 0.0 | Relative tolerance: ` |
--rename <PATTERN> <REPL> | — | Regex rewrite applied to names in both files before matching; repeatable |
lp_parser diff old.lp new.lp
lp_parser diff old.lp new.lp --abs-tol 1e-6 --rel-tol 1e-9
lp_parser diff old.lp new.lp --rename '\[\d+\]$' '[N]' --format json --pretty
convert — translate to another format
| Option | Default | Description |
|---|---|---|
<FILE> | — | Path to the LP file |
-o, --output <PATH> | stdout | Output file or directory (required for CSV) |
-f, --format <FMT> | lp | lp, csv, json, yaml |
--pretty | off | Pretty-print JSON/YAML |
--precision <N> | 6 | Decimal precision for numbers |
--max-line-length <N> | 80 | Line-wrap threshold for LP output |
--no-problem-name | off | Omit problem-name comment in LP output |
--compact | off | No section spacing |
lp_parser convert problem.lp --format lp --precision 4 --compact
lp_parser convert problem.lp --format csv --output ./out # writes constraints.csv, objectives.csv, variables.csv
lp_parser convert problem.lp --format json --pretty -o problem.json
solve — run an external solver (requires lp-solvers feature)
| Option | Default | Description |
|---|---|---|
<FILE> | — | Path to the LP file |
-s, --solver <NAME> | cbc | cbc, gurobi, cplex, glpk |
-o, --output <PATH> | stdout | Write solution to file |
-f, --format <FMT> | text | text, json, yaml |
--pretty | off | Pretty-print structured output |
lp_parser solve problem.lp
lp_parser solve problem.lp --solver glpk
lp_parser solve problem.lp --format json --pretty
The selected solver binary must be installed on your PATH. The compatibility layer does not support multiple objectives (errors), strict inequalities (<, >), or SOS constraints (ignored with a warning).
Interactive TUI Diff Viewer (lp_diff)
A terminal UI for comparing LP/MPS files with coefficient-level side-by-side diffs, fuzzy search, filtering, and integrated HiGHS solving. Built with ratatui.
cargo install --path tui
lp_diff base.lp modified.lp # interactive
lp_diff base.lp modified.lp --summary # non-interactive summary
Tolerance & rename (parity with lp_parser diff)
lp_diff accepts the same name-rewrite and numeric-tolerance flags as the CLI diff command. Active options are shown on the Summary panel (and in --summary output) so results are reproducible.
| Option | Default | Description |
|---|---|---|
--abs-tol <F> | 0.0 | Absolute tolerance for RHS & coefficient comparisons |
--rel-tol <F> | 0.0 | Relative tolerance: ` |
--rename <PATTERN> <REPL> | — | Regex rewrite applied to names in both files before matching; repeatable |
# Collapse indexed names (e.g. x[1,2,foo] / x[9,9,baz] → x[idx]) so structural diffs survive renumbering
lp_diff base.lp modified.lp --rename '\[\d+,\d+,[^]]*\]$' '[idx]'
# Hide near-equal RHS/coefficient drift
lp_diff base.lp modified.lp --abs-tol 1e-4 --rel-tol 1e-6
# Combine with --summary for scripting
lp_diff base.lp modified.lp --summary --rename '\[\d+\]$' '[idx]' --abs-tol 1e-6
Highlights: three-panel layout, four sections (Summary / Variables / Constraints / Objectives), filtering (a/+/-/m), telescope-style search (fuzzy, r: regex, s: substring), HiGHS solve-and-compare (S), vim-style navigation and jumplist, clipboard yank (y/Y), CSV export (w), ? for full help.
See tui/README.md for the complete reference.
Development
cargo insta test --all-features # run tests
cargo insta review # review snapshot changes
Test data sources: Jplex, LPWriter.jl, Lp-Parser.
Contributing
Contributions are welcome — please open a Pull Request.