{"id":13749014,"url":"https://github.com/dandxy89/lp_parser_rs","last_synced_at":"2026-02-24T18:12:15.032Z","repository":{"id":206578698,"uuid":"717191067","full_name":"dandxy89/lp_parser_rs","owner":"dandxy89","description":"Rust LP File Parser and Diff tool","archived":false,"fork":false,"pushed_at":"2025-12-11T21:58:45.000Z","size":5780,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-13T22:27:51.093Z","etag":null,"topics":["diff","integer-programming","linear-programming","lp","lpfile","nom","parser","rust"],"latest_commit_sha":null,"homepage":"https://docs.rs/lp_parser_rs/latest/lp_parser_rs/","language":"Linear Programming","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/dandxy89.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","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":null,"dco":null,"cla":null}},"created_at":"2023-11-10T19:13:01.000Z","updated_at":"2025-12-11T21:58:35.000Z","dependencies_parsed_at":"2023-11-13T22:21:14.294Z","dependency_job_id":"bb5a9468-bddd-454a-b60d-db6ef8ca0d72","html_url":"https://github.com/dandxy89/lp_parser_rs","commit_stats":null,"previous_names":["dandxy89/congenial-enigma","dandxy89/lp_parser_rs"],"tags_count":62,"template":false,"template_full_name":null,"purl":"pkg:github/dandxy89/lp_parser_rs","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dandxy89%2Flp_parser_rs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dandxy89%2Flp_parser_rs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dandxy89%2Flp_parser_rs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dandxy89%2Flp_parser_rs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dandxy89","download_url":"https://codeload.github.com/dandxy89/lp_parser_rs/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dandxy89%2Flp_parser_rs/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28956869,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T18:30:42.805Z","status":"ssl_error","status_checked_at":"2026-01-31T18:30:19.593Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["diff","integer-programming","linear-programming","lp","lpfile","nom","parser","rust"],"created_at":"2024-08-03T07:00:54.008Z","updated_at":"2026-02-24T18:12:15.025Z","avatar_url":"https://github.com/dandxy89.png","language":"Linear Programming","funding_links":[],"categories":["Projects","Serialization \u0026 Parsing"],"sub_categories":["Libraries"],"readme":"# Rust LP File Parser, Writer, and Diff Tool\n\n[![Cargo Test](https://github.com/dandxy89/congenial-enigma/actions/workflows/cargo_test.yml/badge.svg)](https://github.com/dandxy89/congenial-enigma/actions/workflows/cargo_test.yml)\n[![Crates.io](https://img.shields.io/crates/v/lp_parser_rs.svg)](https://crates.io/crates/lp_parser_rs)\n[![Documentation](https://docs.rs/lp_parser_rs/badge.svg)](https://docs.rs/lp_parser_rs/)\n[![PyPI version](https://badge.fury.io/py/parse-lp.svg)](https://badge.fury.io/py/parse-lp)\n[![PyPI Downloads](https://static.pepy.tech/personalized-badge/parse-lp?period=total\u0026units=NONE\u0026left_color=BLACK\u0026right_color=GREEN\u0026left_text=downloads)](https://pepy.tech/projects/parse-lp)\n\n## Interactive TUI Diff Viewer (`lp_diff`)\n\nAn interactive terminal-based diff viewer for LP files, built with [ratatui](https://ratatui.rs). Compare two LP files with coefficient-level detail, fuzzy search, filtering, and integrated solving via [HiGHS](https://highs.dev).\n\n### Install\n\n```bash\n# From a cloned repo\ngit clone https://github.com/dandxy89/lp_parser_rs.git\ncd lp_parser_rs\ncargo install --path tui\n```\n\n### Quick Start\n\n```bash\nlp_diff base.lp modified.lp\n```\n\nFor a non interactive summary:\n\n```bash\nlp_diff base.lp modified.lp --summary\n```\n\n### Features\n\n- **Three-panel layout** — section selector, name list, and detail panel with coefficient-level side-by-side diffs\n- **Four sections** — Summary, Variables, Constraints, and Objectives\n- **Filtering** — show all (`a`), added (`+`), removed (`-`), or modified (`m`) entries\n- **Telescope-style search** — fuzzy (default), regex (`r:`), or substring (`s:`) across all sections\n- **HiGHS solver** — press `S` to solve either or both files and compare results\n- **Vim-style navigation** — `j`/`k`, `g`/`G`, `Ctrl+d`/`Ctrl+u`, jumplist (`Ctrl+o`/`Ctrl+i`)\n- **Clipboard \u0026 export** — yank names/details (`y`/`Y`), write solve diffs to CSV (`w`)\n- **Built-in help** — press `?` for full keybindings reference\n\nSee [`tui/README.md`](tui/README.md) for the complete keybindings reference and detailed documentation.\n\n## Overview\n\nA robust Rust library for parsing, modifying, and writing Linear Programming (LP) files. Built on the [LALRPOP](https://github.com/lalrpop/lalrpop) parser generator, this crate provides comprehensive support for the LP file format with the ability to parse, programmatically modify, and regenerate LP files according to major industry specifications.\n\nThe Grammar is defined with the [lp.lalrpop](/rust/src/lp.lalrpop) file - should you be curious...\n\n### Supported Specifications\n\n- [IBM CPLEX v22.1.1](https://www.ibm.com/docs/en/icos/22.1.1?topic=cplex-lp-file-format-algebraic-representation)\n- [FICO Xpress](https://www.fico.com/fico-xpress-optimization/docs/dms2020-03/solver/optimizer/HTML/chapter10_sec_section102.html)\n- [Gurobi](https://www.gurobi.com/documentation/current/refman/lp_format.html)\n- Mosek\n\n## Features\n\n### Core Functionality\n\n- **Problem Definition**\n  - Problem name and sense specification\n  - Single and multi-objective optimisation support\n  - Comprehensive constraint handling\n\n- **Variable Support**\n  - Integer, general, bounded, free, semi-continuous variables\n\n- **LP File Writing and Modification**\n  - Generate LP files from parsed problems\n  - Modify objectives, constraints, and variables programmatically\n  - Round-trip compatibility (parse → modify → write → parse)\n  - Maintain proper LP format specifications\n\n### Advanced Features\n\n- **Problem Analysis**\n  - Comprehensive statistics: variable/constraint counts, matrix density, sparsity metrics\n  - Variable analysis: type distribution, unused/fixed variables, invalid bounds detection\n  - Constraint analysis: type distribution, empty/singleton constraints, RHS ranges\n  - Coefficient analysis: ranges, large/small coefficient detection, scaling ratios\n  - Issue detection with severity levels (errors, warnings, info)\n  - Configurable thresholds for different problem domains\n\n- **LP File Comparison (`diff` feature)**\n  - Identify added, removed, and modified elements\n  - Useful for model version control and validation\n\n- **Serialisation (`serde` feature)**\n  - Full serialisation support for all model structures\n  - Compatible with various data formats\n  - Enables integration with other tools and systems\n\n## Quick Start\n\n### Installation\n\nAdd to your `Cargo.toml`:\n\n```toml\n[dependencies]\nlp_parser_rs = \"3.0.0\" # x-release-please-version\n```\n\n### Basic Usage\n\nUsing the library directly:\n\n```rust\nuse lp_parser_rs::{parser::parse_file, problem::LpProblem};\nuse std::path::Path;\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    // Parse LP file content\n    let content = parse_file(Path::new(\"problem.lp\"))?;\n\n    // Parse into LP problem structure\n    let problem = LpProblem::parse(\u0026content)?;\n\n    // Access problem components\n    println!(\"Problem name: {:?}\", problem.name());\n    println!(\"Objective count: {}\", problem.objective_count());\n    println!(\"Constraint count: {}\", problem.constraint_count());\n    println!(\"Variable count: {}\", problem.variable_count());\n\n    Ok(())\n}\n```\n\n### LP File Writing and Modification\n\n```rust\nuse lp_parser_rs::{problem::LpProblem, writer::write_lp_string, model::*};\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    // Parse an existing LP file\n    let lp_content = std::fs::read_to_string(\"problem.lp\")?;\n    let mut problem = LpProblem::parse(\u0026lp_content)?;\n\n    // Modify objectives\n    problem.update_objective_coefficient(\"profit\", \"x1\", 5.0)?;\n    problem.rename_objective(\"profit\", \"total_profit\")?;\n\n    // Modify constraints\n    problem.update_constraint_coefficient(\"capacity\", \"x1\", 2.0)?;\n    problem.update_constraint_rhs(\"capacity\", 200.0)?;\n    problem.rename_constraint(\"capacity\", \"production_limit\")?;\n\n    // Modify variables\n    problem.rename_variable(\"x1\", \"production_a\")?;\n    problem.update_variable_type(\"production_a\", VariableType::Integer)?;\n\n    // Write back to LP format\n    let modified_lp = write_lp_string(\u0026problem)?;\n    std::fs::write(\"modified_problem.lp\", modified_lp)?;\n\n    Ok(())\n}\n```\n\n### Enable Optional Features\n\n```toml\n[dependencies]\nlp_parser_rs = { version = \"3.0.0\", features = [\"serde\", \"diff\"] } # x-release-please-version\n```\n\n## Command-Line Interface\n\nThe `lp_parser` binary provides a comprehensive CLI for working with LP files.\n\n### Installation\n\n```bash\n# Install with all features\ncargo install lp_parser_rs --all-features\n\n# Or build from source\ngit clone https://github.com/dandxy89/lp_parser_rs.git\ncd lp_parser_rs/rust\ncargo build --release --all-features\n```\n\n### Commands\n\n```\nlp_parser \u003cCOMMAND\u003e\n\nCommands:\n  parse    Parse an LP file and display its structure\n  info     Show detailed statistics about an LP problem\n  analyze  Analyze problem structure, detect issues, and report statistics\n  diff     Compare two LP files (requires 'diff' feature)\n  convert  Convert LP file to another format\n  solve    Solve an LP problem using external solvers (requires 'lp-solvers' feature)\n\nGlobal Options:\n  -v, --verbose    Increase output verbosity\n  -q, --quiet      Suppress non-essential output\n  -h, --help       Print help\n  -V, --version    Print version\n```\n\n### Examples\n\n**Parse and display an LP file:**\n\n```bash\nlp_parser parse problem.lp\n```\n\n**Get problem statistics:**\n\n```bash\nlp_parser info problem.lp\n# With detailed listings\nlp_parser info problem.lp --variables --constraints --objectives\n```\n\n**Analyze problem structure and detect issues:**\n\n```bash\n# Full analysis with statistics and issue detection\nlp_parser analyze problem.lp\n\n# Show only warnings and errors\nlp_parser analyze problem.lp --issues-only\n\n# Output as JSON or YAML\nlp_parser analyze problem.lp --format json --pretty\nlp_parser analyze problem.lp --format yaml -o analysis.yaml\n\n# Custom thresholds for numerical issue detection\nlp_parser analyze problem.lp --large-coeff-threshold 1e8 --ratio-threshold 1e5\n```\n\nExample analysis output:\n```yaml\nsummary:\n  name: diet\n  sense: Minimize\n  objective_count: 1\n  constraint_count: 7\n  variable_count: 16\n  total_nonzeros: 64\n  density: 0.571\nsparsity:\n  min_vars_per_constraint: 6\n  max_vars_per_constraint: 10\nvariables:\n  type_distribution:\n    upper_bounded: 9\n    double_bounded: 7\n  discrete_variable_count: 0\nconstraints:\n  type_distribution:\n    equality: 7\n  rhs_range:\n    min: 30.0\n    max: 50000.0\ncoefficients:\n  constraint_coeff_range:\n    min: 0.1\n    max: 3055.2\n  coefficient_ratio: 101840.0\nissues: []\n```\n\n**Output as JSON or YAML:**\n\n```bash\nlp_parser info problem.lp --format json --pretty\nlp_parser parse problem.lp --format yaml -o problem.yaml\n```\n\n**Compare two LP files:**\n\n```bash\nlp_parser diff old_model.lp new_model.lp\nlp_parser diff old.lp new.lp --format json --pretty\n```\n\n**Convert between formats:**\n\n```bash\n# To LP (with formatting options)\nlp_parser convert problem.lp --format lp --precision 4 --compact\n\n# To CSV (creates constraints.csv, objectives.csv, variables.csv)\nlp_parser convert problem.lp --format csv --output ./output_dir\n\n# To JSON/YAML\nlp_parser convert problem.lp --format json --pretty -o problem.json\nlp_parser convert problem.lp --format yaml -o problem.yaml\n```\n\n**Solve with external solvers:**\n```bash\n# Using CBC (default)\nlp_parser solve problem.lp\n\n# Using GLPK\nlp_parser solve problem.lp --solver glpk\n\n# Output solution as JSON\nlp_parser solve problem.lp --format json --pretty\n```\n\n## Solving with External Solvers (`lp-solvers` feature)\n\nEnable the `lp-solvers` feature to solve parsed LP problems using external solvers like CBC, Gurobi, CPLEX, or GLPK via the [lp-solvers](https://crates.io/crates/lp-solvers) crate:\n\n```toml\n[dependencies]\nlp_parser_rs = { version = \"3.0.0\", features = [\"lp-solvers\"] } # x-release-please-version\nlp-solvers = \"1.1\"\n```\n\n```rust\nuse lp_parser_rs::{problem::LpProblem, ToLpSolvers};\nuse lp_solvers::solvers::{CbcSolver, SolverTrait};\n\nfn main() -\u003e Result\u003c(), Box\u003cdyn std::error::Error\u003e\u003e {\n    let lp_content = r\"\nMinimize\n obj: 2 x + 3 y\nSubject To\n c1: x + y \u003c= 10\n c2: x \u003e= 2\nBounds\n x \u003e= 0\n y \u003e= 0\nEnd\n\";\n\n    let problem = LpProblem::parse(lp_content)?;\n    let compat = problem.to_lp_solvers()?;\n\n    // Check for any compatibility warnings\n    for warning in compat.warnings() {\n        eprintln!(\"Warning: {}\", warning);\n    }\n\n    // Solve using CBC solver (must be installed on your system)\n    let solver = CbcSolver::new();\n    let solution = solver.run(\u0026compat)?;\n    println!(\"Solution status: {:?}\", solution.status);\n\n    Ok(())\n}\n```\n\n**Limitations:** The lp-solvers compatibility layer does not support multiple objectives (returns an error), strict inequalities (`\u003c`, `\u003e`), or SOS constraints (ignored with a warning).\n\n## API Reference\n\n### Problem Modification Methods\n\nThe `LpProblem` struct provides comprehensive methods for modifying LP problems:\n\n#### Objective Modifications\n- `update_objective_coefficient(objective_name, variable_name, coefficient)` - Update or add a coefficient in an objective\n- `rename_objective(old_name, new_name)` - Rename an objective\n- `remove_objective(objective_name)` - Remove an objective\n\n#### Constraint Modifications\n- `update_constraint_coefficient(constraint_name, variable_name, coefficient)` - Update or add a coefficient in a constraint\n- `update_constraint_rhs(constraint_name, new_rhs)` - Update the right-hand side value\n- `rename_constraint(old_name, new_name)` - Rename a constraint\n- `remove_constraint(constraint_name)` - Remove a constraint\n\n#### Variable Modifications\n- `rename_variable(old_name, new_name)` - Rename a variable across all objectives and constraints\n- `update_variable_type(variable_name, new_type)` - Change variable type (Binary, Integer, etc.)\n- `remove_variable(variable_name)` - Remove a variable from all objectives and constraints\n\n### Writing LP Files\n\n```rust\nuse lp_parser_rs::writer::{write_lp_string, write_lp_string_with_options, LpWriterOptions};\n\n// Write with default options\nlet lp_content = write_lp_string(\u0026problem)?;\n\n// Write with custom options\nlet options = LpWriterOptions {\n    include_problem_name: true,\n    max_line_length: 80,\n    decimal_precision: 6,\n    include_section_spacing: true,\n};\nlet lp_content = write_lp_string_with_options(\u0026problem, \u0026options)?;\n```\n\n## Development\n\n### Testing\n\nThe project uses snapshot testing via `insta` for reliable test management:\n\n```bash\n# Run all tests with all features enabled\ncargo insta test --all-features\n\n# Review snapshot changes\ncargo insta review\n```\n\n## Test Data Sources\n\nThe test suite includes data from various open-source projects:\n\n- [Jplex](https://github.com/asbestian/jplex/blob/main/instances/afiro.lp)\n- [LPWriter.jl](https://github.com/odow/LPWriter.jl/blob/master/test/model2.lp)\n- [Lp-Parser](https://github.com/aphi/Lp-Parser)\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdandxy89%2Flp_parser_rs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdandxy89%2Flp_parser_rs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdandxy89%2Flp_parser_rs/lists"}