Rust LP File Parser, Writer, and Diff Tool

April 20, 2026 · View on GitHub

Cargo Test Crates.io Documentation PyPI version PyPI Downloads

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 (diff feature) — structural comparison between two LP files
  • Serialisation (serde feature) — JSON / YAML support
  • External solvers (lp-solvers feature) — 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

FlagDescription
-v, --verboseIncrease output verbosity (repeatable)
-q, --quietSuppress non-essential output
-h, --help / -V, --versionPrint help / version

parse — display file structure

OptionDefaultDescription
<FILE>Path to the LP file (required)
-o, --output <PATH>stdoutWrite output to file
-f, --format <FMT>texttext, json (serde), yaml (serde)
--prettyoffPretty-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:

OptionDescription
--variablesList all variables with their types
--constraintsList all constraints
--objectivesList 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:

OptionDefaultDescription
--issues-onlyoffSkip full analysis; show warnings/errors only
--large-coeff-threshold <F>1e9Warn on coefficients larger than this
--small-coeff-threshold <F>1e-9Warn on coefficients smaller than this
--ratio-threshold <F>1e6Warn 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)

OptionDefaultDescription
<FILE1> <FILE2>Base and comparison files
-o, --output <PATH>stdoutWrite output to file
-f, --format <FMT>texttext, json, yaml
--prettyoffPretty-print structured output
--abs-tol <F>0.0Absolute tolerance for numeric comparisons
--rel-tol <F>0.0Relative 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

OptionDefaultDescription
<FILE>Path to the LP file
-o, --output <PATH>stdoutOutput file or directory (required for CSV)
-f, --format <FMT>lplp, csv, json, yaml
--prettyoffPretty-print JSON/YAML
--precision <N>6Decimal precision for numbers
--max-line-length <N>80Line-wrap threshold for LP output
--no-problem-nameoffOmit problem-name comment in LP output
--compactoffNo 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)

OptionDefaultDescription
<FILE>Path to the LP file
-s, --solver <NAME>cbccbc, gurobi, cplex, glpk
-o, --output <PATH>stdoutWrite solution to file
-f, --format <FMT>texttext, json, yaml
--prettyoffPretty-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.

OptionDefaultDescription
--abs-tol <F>0.0Absolute tolerance for RHS & coefficient comparisons
--rel-tol <F>0.0Relative 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.