parse-lp 2.4.3__tar.gz → 2.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {parse_lp-2.4.3 → parse_lp-2.5.0}/Cargo.lock +1 -1
- parse_lp-2.5.0/PKG-INFO +213 -0
- parse_lp-2.5.0/README.md +194 -0
- parse_lp-2.5.0/parse_lp/__init__.py +39 -0
- parse_lp-2.5.0/parse_lp/parse_lp.pyi +179 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/pyproject.toml +12 -5
- {parse_lp-2.4.3 → parse_lp-2.5.0}/python/Cargo.toml +2 -2
- {parse_lp-2.4.3 → parse_lp-2.5.0}/python/MANIFEST.in +3 -2
- parse_lp-2.5.0/python/README.md +194 -0
- parse_lp-2.5.0/python/parse_lp/__init__.py +39 -0
- parse_lp-2.5.0/python/parse_lp/parse_lp.pyi +179 -0
- parse_lp-2.5.0/python/parse_lp/py.typed +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/python/python/CHANGELOG.md +7 -0
- parse_lp-2.5.0/python/src/lib.rs +256 -0
- parse_lp-2.5.0/python/tests/__init__.py +0 -0
- parse_lp-2.5.0/python/tests/fixtures/minimize.lp +16 -0
- parse_lp-2.5.0/python/tests/fixtures/simple.lp +12 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/python/tests/test_csv_writer.py +0 -5
- parse_lp-2.5.0/python/tests/test_lp_parser.py +219 -0
- parse_lp-2.5.0/python/uv.lock +253 -0
- parse_lp-2.5.0/rust/resources/afiro.lp +36 -0
- parse_lp-2.4.3/PKG-INFO +0 -43
- parse_lp-2.4.3/README.md +0 -25
- parse_lp-2.4.3/parse_lp/__init__.py +0 -3
- parse_lp-2.4.3/python/README.md +0 -25
- parse_lp-2.4.3/python/parse_lp/__init__.py +0 -3
- parse_lp-2.4.3/python/src/lib.rs +0 -51
- parse_lp-2.4.3/python/uv.lock +0 -232
- {parse_lp-2.4.3 → parse_lp-2.5.0}/Cargo.toml +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/LICENSE-APACHE +0 -0
- /parse_lp-2.4.3/python/tests/__init__.py → /parse_lp-2.5.0/parse_lp/py.typed +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/python/.cargo/config.toml +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/python/CHANGELOG.md +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/python/LICENSE-APACHE +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/python/Makefile +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/python/resources/afiro.lp +0 -0
- {parse_lp-2.4.3/rust/resources → parse_lp-2.5.0/python/tests/fixtures}/afiro.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/CHANGELOG.md +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/Cargo.toml +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/README.md +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/benches/lp_parsing.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/benches/parsing_micro.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/1obj_1cons_all_variables_with_bounds.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/2obj_2cons_all_variable_types.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/2obj_2cons_only_binary_vars.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/3obj_2cons.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/AmericanSteelProblem.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/BeerDistributionProblem.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/ComputerPlantProblem.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/WhiskasModel2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/afiro_ext.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/blank_lines.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/boeing1.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/boeing2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/carbon.png +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/complex_names.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/corrupt.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/cplex.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/diet.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/empty_bounds.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/fit1d.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/fit2d.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/infile_comments.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/infile_comments2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/invalid.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/kb2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/limbo.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/lol.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/milo1.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/missing_signs.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/model.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/model2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/mosek.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/mosek_bounds.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/no_end_section.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/optional_labels.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/output.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/output2_1.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/output2_2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/output2_3.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/output2_4.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/output_cplex_2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/pulp.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/pulp2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/sc50a.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/scientific_notation.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/scientific_notation_2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/semi_continuous.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/sos.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/sudoku.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/test.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/test2.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/test_copy.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/resources/wbm.lp +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/rust/CHANGELOG.md +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/bin/main.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/builder.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/context.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/csv.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/error.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/lib.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/model.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parser.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/coefficient.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/constraint.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/mod.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/number.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/objective.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/parser_traits.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/problem_name.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/sense.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/sos_constraint.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/parsers/variable.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/perf.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/problem.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/snapshots/lp_parser_rs__problem__test__minified_example.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/snapshots/lp_parser_rs__problem__test__small_input.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/src/validation.rs +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__afiro.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__afiro_ext.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__american_steel_problem.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__beer_distribution_problem.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__blank_lines.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__boeing1.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__boeing2.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__complex_names.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__computer_plant_problem.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__cplex.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__diet.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__empty_bounds.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__fit1d.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__infile_comments.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__infile_comments2.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__kb2.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__limbo.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__lol.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__milo1.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__missing_signs.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__model.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__model2.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__mosek.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__mosek_bounds.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__nom_fit2d.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__obj3_2cons.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__obj_1cons_all_variables_with_bounds.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__obj_2cons_all_variable_types.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__obj_2cons_only_binary_vars.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__output.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__output2_1.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__output2_2.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__output2_3.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__output2_4.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__pulp.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__pulp2.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__sc50a.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__scientific_notation.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__scientific_notation_2.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__sos.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__sudoku.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__test.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__test2.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__wbm.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/snapshots/test_nom_from_file__whiskas_model_2.snap +0 -0
- {parse_lp-2.4.3 → parse_lp-2.5.0}/rust/tests/test_nom_from_file.rs +0 -0
parse_lp-2.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: parse_lp
|
|
3
|
+
Version: 2.5.0
|
|
4
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
5
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
6
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
8
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
9
|
+
License-File: LICENSE-APACHE
|
|
10
|
+
Summary: A LP file format parser for Python, powered by Rust
|
|
11
|
+
Keywords: linear-programming,optimization,parser,integer-programming,math
|
|
12
|
+
Author: Dan Dixey, Dan Dixey <dan@functorml.co.uk>
|
|
13
|
+
Author-email: Dan Dixey, Dan Dixey <dan@functorml.co.uk>
|
|
14
|
+
License: MIT OR Apache-2.0
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
17
|
+
Project-URL: Source Code, https://github.com/dandxy89/lp_parser_rs
|
|
18
|
+
|
|
19
|
+
# parse_lp
|
|
20
|
+
|
|
21
|
+
A LP file format parser for Python, powered by Rust.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **Complete LP Support**: Handles all standard LP file format features
|
|
26
|
+
- **Easy Data Access**: Direct access to problem components (variables, constraints, objectives)
|
|
27
|
+
- **CSV Export**: Export parsed data to CSV files for further analysis
|
|
28
|
+
- **Problem Comparison**: Compare two LP problems to identify differences
|
|
29
|
+
- **Type Safety**: Full type hints for better IDE support and development experience
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install parse_lp
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from parse_lp import LpParser
|
|
41
|
+
|
|
42
|
+
# Parse an LP file
|
|
43
|
+
parser = LpParser("path/to/problem.lp")
|
|
44
|
+
parser.parse()
|
|
45
|
+
|
|
46
|
+
# Access problem information
|
|
47
|
+
print(f"Problem: {parser.name}")
|
|
48
|
+
print(f"Sense: {parser.sense}")
|
|
49
|
+
print(f"Variables: {parser.variable_count()}")
|
|
50
|
+
print(f"Constraints: {parser.constraint_count()}")
|
|
51
|
+
|
|
52
|
+
# Export to CSV files
|
|
53
|
+
parser.to_csv("output_directory/")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Usage Examples
|
|
57
|
+
|
|
58
|
+
### Basic Parsing and Information
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from parse_lp import LpParser
|
|
62
|
+
|
|
63
|
+
parser = LpParser("optimization_problem.lp")
|
|
64
|
+
parser.parse()
|
|
65
|
+
|
|
66
|
+
# Get problem overview
|
|
67
|
+
print(f"Problem Name: {parser.name}")
|
|
68
|
+
print(f"Optimization Sense: {parser.sense}")
|
|
69
|
+
print(f"Variables: {parser.variable_count()}")
|
|
70
|
+
print(f"Constraints: {parser.constraint_count()}")
|
|
71
|
+
print(f"Objectives: {parser.objective_count()}")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Accessing Problem Data
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
# Access objectives
|
|
78
|
+
for i, objective in enumerate(parser.objectives):
|
|
79
|
+
print(f"Objective {i+1}: {objective['name']}")
|
|
80
|
+
for coef in objective['coefficients']:
|
|
81
|
+
print(f" {coef['name']}: {coef['value']}")
|
|
82
|
+
|
|
83
|
+
# Access variables
|
|
84
|
+
for var_name, var_info in parser.variables.items():
|
|
85
|
+
print(f"Variable {var_name}:")
|
|
86
|
+
print(f" Type: {var_info['var_type']}")
|
|
87
|
+
if 'bounds' in var_info:
|
|
88
|
+
bounds = var_info['bounds']
|
|
89
|
+
if 'lower' in bounds:
|
|
90
|
+
print(f" Lower bound: {bounds['lower']}")
|
|
91
|
+
if 'upper' in bounds:
|
|
92
|
+
print(f" Upper bound: {bounds['upper']}")
|
|
93
|
+
|
|
94
|
+
# Access constraints
|
|
95
|
+
for constraint in parser.constraints:
|
|
96
|
+
print(f"Constraint {constraint['name']}:")
|
|
97
|
+
print(f" Type: {constraint['type']}")
|
|
98
|
+
if constraint['type'] == 'standard':
|
|
99
|
+
print(f" Sense: {constraint['sense']}")
|
|
100
|
+
print(f" RHS: {constraint['rhs']}")
|
|
101
|
+
print(f" Coefficients: {len(constraint['coefficients'])}")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### CSV Export
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
import os
|
|
108
|
+
|
|
109
|
+
# Create output directory
|
|
110
|
+
os.makedirs("output", exist_ok=True)
|
|
111
|
+
|
|
112
|
+
# Export to CSV files
|
|
113
|
+
parser.to_csv("output/")
|
|
114
|
+
|
|
115
|
+
# Files created:
|
|
116
|
+
# - output/variables.csv
|
|
117
|
+
# - output/constraints.csv
|
|
118
|
+
# - output/objectives.csv
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Problem Comparison
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
# Parse two different versions of a problem
|
|
125
|
+
parser1 = LpParser("problem_v1.lp")
|
|
126
|
+
parser1.parse()
|
|
127
|
+
|
|
128
|
+
parser2 = LpParser("problem_v2.lp")
|
|
129
|
+
parser2.parse()
|
|
130
|
+
|
|
131
|
+
# Compare the problems
|
|
132
|
+
diff = parser1.compare(parser2)
|
|
133
|
+
|
|
134
|
+
print("Comparison Results:")
|
|
135
|
+
print(f"Name changed: {diff['name_changed']}")
|
|
136
|
+
print(f"Sense changed: {diff['sense_changed']}")
|
|
137
|
+
print(f"Variable count difference: {diff['variable_count_diff']}")
|
|
138
|
+
print(f"Added variables: {diff['added_variables']}")
|
|
139
|
+
print(f"Removed variables: {diff['removed_variables']}")
|
|
140
|
+
print(f"Modified variables: {diff['modified_variables']}")
|
|
141
|
+
print(f"Added constraints: {diff['added_constraints']}")
|
|
142
|
+
print(f"Removed constraints: {diff['removed_constraints']}")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Objectives Structure
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
[
|
|
149
|
+
{
|
|
150
|
+
"name": "objective_name",
|
|
151
|
+
"coefficients": [
|
|
152
|
+
{"name": "variable_name", "value": 1.5},
|
|
153
|
+
{"name": "another_var", "value": -2.0}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Variables Structure
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
{
|
|
163
|
+
"variable_name": {
|
|
164
|
+
"name": "variable_name",
|
|
165
|
+
"var_type": "Continuous", # or "Binary", "Integer", etc.
|
|
166
|
+
"bounds": { # Optional
|
|
167
|
+
"lower": 0.0, # Optional
|
|
168
|
+
"upper": 100.0 # Optional
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Constraints Structure
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
[
|
|
178
|
+
{
|
|
179
|
+
"name": "constraint_name",
|
|
180
|
+
"type": "standard", # or "sos"
|
|
181
|
+
"sense": "LessOrEqual", # "Equal", "GreaterOrEqual"
|
|
182
|
+
"rhs": 10.0,
|
|
183
|
+
"coefficients": [
|
|
184
|
+
{"name": "variable_name", "value": 2.0}
|
|
185
|
+
]
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"name": "sos_constraint",
|
|
189
|
+
"type": "sos",
|
|
190
|
+
"sos_type": "SOS1", # or "SOS2"
|
|
191
|
+
"variables": ["var1", "var2", "var3"]
|
|
192
|
+
}
|
|
193
|
+
]
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Supported LP Format Features
|
|
197
|
+
|
|
198
|
+
- Multiple objective functions
|
|
199
|
+
- Standard constraints (≤, =, ≥)
|
|
200
|
+
- Variable bounds
|
|
201
|
+
- Variable types (continuous, binary, integer)
|
|
202
|
+
- SOS (Special Ordered Sets) constraints
|
|
203
|
+
- Problem names and comments
|
|
204
|
+
- Scientific notation in coefficients
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
|
|
209
|
+
|
|
210
|
+
## Contributing
|
|
211
|
+
|
|
212
|
+
Issues and pull requests are welcome at: <https://github.com/dandxy89/lp_parser_rs>
|
|
213
|
+
|
parse_lp-2.5.0/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# parse_lp
|
|
2
|
+
|
|
3
|
+
A LP file format parser for Python, powered by Rust.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Complete LP Support**: Handles all standard LP file format features
|
|
8
|
+
- **Easy Data Access**: Direct access to problem components (variables, constraints, objectives)
|
|
9
|
+
- **CSV Export**: Export parsed data to CSV files for further analysis
|
|
10
|
+
- **Problem Comparison**: Compare two LP problems to identify differences
|
|
11
|
+
- **Type Safety**: Full type hints for better IDE support and development experience
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install parse_lp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from parse_lp import LpParser
|
|
23
|
+
|
|
24
|
+
# Parse an LP file
|
|
25
|
+
parser = LpParser("path/to/problem.lp")
|
|
26
|
+
parser.parse()
|
|
27
|
+
|
|
28
|
+
# Access problem information
|
|
29
|
+
print(f"Problem: {parser.name}")
|
|
30
|
+
print(f"Sense: {parser.sense}")
|
|
31
|
+
print(f"Variables: {parser.variable_count()}")
|
|
32
|
+
print(f"Constraints: {parser.constraint_count()}")
|
|
33
|
+
|
|
34
|
+
# Export to CSV files
|
|
35
|
+
parser.to_csv("output_directory/")
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Usage Examples
|
|
39
|
+
|
|
40
|
+
### Basic Parsing and Information
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from parse_lp import LpParser
|
|
44
|
+
|
|
45
|
+
parser = LpParser("optimization_problem.lp")
|
|
46
|
+
parser.parse()
|
|
47
|
+
|
|
48
|
+
# Get problem overview
|
|
49
|
+
print(f"Problem Name: {parser.name}")
|
|
50
|
+
print(f"Optimization Sense: {parser.sense}")
|
|
51
|
+
print(f"Variables: {parser.variable_count()}")
|
|
52
|
+
print(f"Constraints: {parser.constraint_count()}")
|
|
53
|
+
print(f"Objectives: {parser.objective_count()}")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Accessing Problem Data
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
# Access objectives
|
|
60
|
+
for i, objective in enumerate(parser.objectives):
|
|
61
|
+
print(f"Objective {i+1}: {objective['name']}")
|
|
62
|
+
for coef in objective['coefficients']:
|
|
63
|
+
print(f" {coef['name']}: {coef['value']}")
|
|
64
|
+
|
|
65
|
+
# Access variables
|
|
66
|
+
for var_name, var_info in parser.variables.items():
|
|
67
|
+
print(f"Variable {var_name}:")
|
|
68
|
+
print(f" Type: {var_info['var_type']}")
|
|
69
|
+
if 'bounds' in var_info:
|
|
70
|
+
bounds = var_info['bounds']
|
|
71
|
+
if 'lower' in bounds:
|
|
72
|
+
print(f" Lower bound: {bounds['lower']}")
|
|
73
|
+
if 'upper' in bounds:
|
|
74
|
+
print(f" Upper bound: {bounds['upper']}")
|
|
75
|
+
|
|
76
|
+
# Access constraints
|
|
77
|
+
for constraint in parser.constraints:
|
|
78
|
+
print(f"Constraint {constraint['name']}:")
|
|
79
|
+
print(f" Type: {constraint['type']}")
|
|
80
|
+
if constraint['type'] == 'standard':
|
|
81
|
+
print(f" Sense: {constraint['sense']}")
|
|
82
|
+
print(f" RHS: {constraint['rhs']}")
|
|
83
|
+
print(f" Coefficients: {len(constraint['coefficients'])}")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### CSV Export
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
import os
|
|
90
|
+
|
|
91
|
+
# Create output directory
|
|
92
|
+
os.makedirs("output", exist_ok=True)
|
|
93
|
+
|
|
94
|
+
# Export to CSV files
|
|
95
|
+
parser.to_csv("output/")
|
|
96
|
+
|
|
97
|
+
# Files created:
|
|
98
|
+
# - output/variables.csv
|
|
99
|
+
# - output/constraints.csv
|
|
100
|
+
# - output/objectives.csv
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Problem Comparison
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
# Parse two different versions of a problem
|
|
107
|
+
parser1 = LpParser("problem_v1.lp")
|
|
108
|
+
parser1.parse()
|
|
109
|
+
|
|
110
|
+
parser2 = LpParser("problem_v2.lp")
|
|
111
|
+
parser2.parse()
|
|
112
|
+
|
|
113
|
+
# Compare the problems
|
|
114
|
+
diff = parser1.compare(parser2)
|
|
115
|
+
|
|
116
|
+
print("Comparison Results:")
|
|
117
|
+
print(f"Name changed: {diff['name_changed']}")
|
|
118
|
+
print(f"Sense changed: {diff['sense_changed']}")
|
|
119
|
+
print(f"Variable count difference: {diff['variable_count_diff']}")
|
|
120
|
+
print(f"Added variables: {diff['added_variables']}")
|
|
121
|
+
print(f"Removed variables: {diff['removed_variables']}")
|
|
122
|
+
print(f"Modified variables: {diff['modified_variables']}")
|
|
123
|
+
print(f"Added constraints: {diff['added_constraints']}")
|
|
124
|
+
print(f"Removed constraints: {diff['removed_constraints']}")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Objectives Structure
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
[
|
|
131
|
+
{
|
|
132
|
+
"name": "objective_name",
|
|
133
|
+
"coefficients": [
|
|
134
|
+
{"name": "variable_name", "value": 1.5},
|
|
135
|
+
{"name": "another_var", "value": -2.0}
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Variables Structure
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
{
|
|
145
|
+
"variable_name": {
|
|
146
|
+
"name": "variable_name",
|
|
147
|
+
"var_type": "Continuous", # or "Binary", "Integer", etc.
|
|
148
|
+
"bounds": { # Optional
|
|
149
|
+
"lower": 0.0, # Optional
|
|
150
|
+
"upper": 100.0 # Optional
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Constraints Structure
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
[
|
|
160
|
+
{
|
|
161
|
+
"name": "constraint_name",
|
|
162
|
+
"type": "standard", # or "sos"
|
|
163
|
+
"sense": "LessOrEqual", # "Equal", "GreaterOrEqual"
|
|
164
|
+
"rhs": 10.0,
|
|
165
|
+
"coefficients": [
|
|
166
|
+
{"name": "variable_name", "value": 2.0}
|
|
167
|
+
]
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"name": "sos_constraint",
|
|
171
|
+
"type": "sos",
|
|
172
|
+
"sos_type": "SOS1", # or "SOS2"
|
|
173
|
+
"variables": ["var1", "var2", "var3"]
|
|
174
|
+
}
|
|
175
|
+
]
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Supported LP Format Features
|
|
179
|
+
|
|
180
|
+
- Multiple objective functions
|
|
181
|
+
- Standard constraints (≤, =, ≥)
|
|
182
|
+
- Variable bounds
|
|
183
|
+
- Variable types (continuous, binary, integer)
|
|
184
|
+
- SOS (Special Ordered Sets) constraints
|
|
185
|
+
- Problem names and comments
|
|
186
|
+
- Scientific notation in coefficients
|
|
187
|
+
|
|
188
|
+
## License
|
|
189
|
+
|
|
190
|
+
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
|
|
191
|
+
|
|
192
|
+
## Contributing
|
|
193
|
+
|
|
194
|
+
Issues and pull requests are welcome at: <https://github.com/dandxy89/lp_parser_rs>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""parse_lp - A fast LP file format parser for Python, powered by Rust.
|
|
2
|
+
|
|
3
|
+
This package provides a high-performance parser for Linear Programming (LP) files,
|
|
4
|
+
leveraging Rust for speed and Python for ease of use.
|
|
5
|
+
|
|
6
|
+
Key Features:
|
|
7
|
+
- Fast parsing of LP files of various formats
|
|
8
|
+
- Export parsed data to CSV files
|
|
9
|
+
- Access to problem components (variables, constraints, objectives)
|
|
10
|
+
- Compare two LP problems to find differences
|
|
11
|
+
- Type hints for better IDE support
|
|
12
|
+
|
|
13
|
+
Example Usage:
|
|
14
|
+
>>> from parse_lp import LpParser
|
|
15
|
+
>>>
|
|
16
|
+
>>> # Parse an LP file
|
|
17
|
+
>>> parser = LpParser("optimization_problem.lp")
|
|
18
|
+
>>> parser.parse()
|
|
19
|
+
>>>
|
|
20
|
+
>>> # Access problem information
|
|
21
|
+
>>> print(f"Problem name: {parser.name}")
|
|
22
|
+
>>> print(f"Variables: {parser.variable_count()}")
|
|
23
|
+
>>> print(f"Constraints: {parser.constraint_count()}")
|
|
24
|
+
>>>
|
|
25
|
+
>>> # Export to CSV files
|
|
26
|
+
>>> parser.to_csv("output/")
|
|
27
|
+
>>>
|
|
28
|
+
>>> # Compare two problems
|
|
29
|
+
>>> parser2 = LpParser("modified_problem.lp")
|
|
30
|
+
>>> parser2.parse()
|
|
31
|
+
>>> diff = parser.compare(parser2)
|
|
32
|
+
>>> print(f"Added variables: {diff['added_variables']}")
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from .parse_lp import LpParser
|
|
37
|
+
|
|
38
|
+
__version__ = "2.4.2"
|
|
39
|
+
__all__ = ["LpParser"]
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
"""Type stubs for parse_lp module."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
class LpParser:
|
|
6
|
+
"""A fast LP file format parser.
|
|
7
|
+
|
|
8
|
+
This class provides functionality to parse Linear Programming (LP) files
|
|
9
|
+
and access the parsed data or export it to CSV format.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
lp_file: Path to the LP file being parsed.
|
|
13
|
+
name: Name of the LP problem (after parsing).
|
|
14
|
+
sense: Optimization sense ('maximize' or 'minimize').
|
|
15
|
+
objectives: List of objective functions with coefficients.
|
|
16
|
+
constraints: List of constraints with their properties.
|
|
17
|
+
variables: Dictionary of variables with their properties.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
>>> from parse_lp import LpParser
|
|
21
|
+
>>> parser = LpParser("path/to/problem.lp")
|
|
22
|
+
>>> parser.parse() # Parse the file
|
|
23
|
+
>>> print(f"Problem: {parser.name}")
|
|
24
|
+
>>> print(f"Variables: {parser.variable_count()}")
|
|
25
|
+
>>> parser.to_csv("output/directory/")
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
def __init__(self, lp_file: str) -> None:
|
|
29
|
+
"""Initialize the LP parser with a file path.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
lp_file: Path to the LP file to parse.
|
|
33
|
+
|
|
34
|
+
Raises:
|
|
35
|
+
FileExistsError: If the specified file does not exist.
|
|
36
|
+
"""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def lp_file(self) -> str:
|
|
41
|
+
"""Get the path to the LP file.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
The path to the LP file being parsed.
|
|
45
|
+
"""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def name(self) -> Optional[str]:
|
|
50
|
+
"""Get the name of the LP problem.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
The problem name if available and parsed, None otherwise.
|
|
54
|
+
"""
|
|
55
|
+
...
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def sense(self) -> Optional[str]:
|
|
59
|
+
"""Get the optimization sense of the problem.
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
'maximize' or 'minimize' if parsed, None otherwise.
|
|
63
|
+
"""
|
|
64
|
+
...
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def objectives(self) -> List[Dict[str, Any]]:
|
|
68
|
+
"""Get the list of objective functions.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
List of dictionaries containing objective information:
|
|
72
|
+
- name: Name of the objective
|
|
73
|
+
- coefficients: List of coefficient dictionaries with 'name' and 'value'
|
|
74
|
+
"""
|
|
75
|
+
...
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def constraints(self) -> List[Dict[str, Any]]:
|
|
79
|
+
"""Get the list of constraints.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
List of dictionaries containing constraint information:
|
|
83
|
+
- name: Name of the constraint
|
|
84
|
+
- type: 'standard' or 'sos'
|
|
85
|
+
- For standard constraints: coefficients, sense, rhs
|
|
86
|
+
- For SOS constraints: sos_type, variables
|
|
87
|
+
"""
|
|
88
|
+
...
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def variables(self) -> Dict[str, Dict[str, Any]]:
|
|
92
|
+
"""Get the dictionary of variables.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Dictionary mapping variable names to their properties:
|
|
96
|
+
- name: Variable name
|
|
97
|
+
- var_type: Type of variable (e.g., 'Continuous', 'Binary', 'Integer')
|
|
98
|
+
- bounds: Optional dictionary with 'lower' and/or 'upper' bounds
|
|
99
|
+
"""
|
|
100
|
+
...
|
|
101
|
+
|
|
102
|
+
def parse(self) -> None:
|
|
103
|
+
"""Parse the LP file.
|
|
104
|
+
|
|
105
|
+
This method reads and parses the LP file, storing the problem
|
|
106
|
+
data internally for later access.
|
|
107
|
+
|
|
108
|
+
Raises:
|
|
109
|
+
RuntimeError: If the LP file cannot be read or parsed.
|
|
110
|
+
"""
|
|
111
|
+
...
|
|
112
|
+
|
|
113
|
+
def to_csv(self, base_directory: str) -> None:
|
|
114
|
+
"""Export the parsed LP problem to CSV files.
|
|
115
|
+
|
|
116
|
+
This method parses the LP file (if not already parsed) and exports
|
|
117
|
+
the problem data (variables, constraints, and objectives) to separate
|
|
118
|
+
CSV files in the specified directory.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
base_directory: Path to the directory where CSV files will be saved.
|
|
122
|
+
The directory must exist.
|
|
123
|
+
|
|
124
|
+
Raises:
|
|
125
|
+
NotADirectoryError: If base_directory is not a valid directory.
|
|
126
|
+
RuntimeError: If the LP file cannot be read or parsed, or if
|
|
127
|
+
CSV files cannot be written.
|
|
128
|
+
"""
|
|
129
|
+
...
|
|
130
|
+
|
|
131
|
+
def variable_count(self) -> int:
|
|
132
|
+
"""Get the number of variables in the problem.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Number of variables, or 0 if not parsed.
|
|
136
|
+
"""
|
|
137
|
+
...
|
|
138
|
+
|
|
139
|
+
def constraint_count(self) -> int:
|
|
140
|
+
"""Get the number of constraints in the problem.
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Number of constraints, or 0 if not parsed.
|
|
144
|
+
"""
|
|
145
|
+
...
|
|
146
|
+
|
|
147
|
+
def objective_count(self) -> int:
|
|
148
|
+
"""Get the number of objective functions in the problem.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Number of objectives, or 0 if not parsed.
|
|
152
|
+
"""
|
|
153
|
+
...
|
|
154
|
+
|
|
155
|
+
def compare(self, other: "LpParser") -> Dict[str, Any]:
|
|
156
|
+
"""Compare this LP problem with another.
|
|
157
|
+
|
|
158
|
+
Both parsers must be parsed before comparison.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
other: Another LpParser instance to compare with.
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
Dictionary containing comparison results:
|
|
165
|
+
- name_changed: Whether problem names differ
|
|
166
|
+
- sense_changed: Whether optimization senses differ
|
|
167
|
+
- variable_count_diff: Difference in variable counts
|
|
168
|
+
- constraint_count_diff: Difference in constraint counts
|
|
169
|
+
- objective_count_diff: Difference in objective counts
|
|
170
|
+
- added_variables: Variables in 'other' but not in 'self'
|
|
171
|
+
- removed_variables: Variables in 'self' but not in 'other'
|
|
172
|
+
- modified_variables: Variables that exist in both but differ
|
|
173
|
+
- added_constraints: Constraints in 'other' but not in 'self'
|
|
174
|
+
- removed_constraints: Constraints in 'self' but not in 'other'
|
|
175
|
+
|
|
176
|
+
Raises:
|
|
177
|
+
RuntimeError: If either parser hasn't been parsed yet.
|
|
178
|
+
"""
|
|
179
|
+
...
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "parse_lp"
|
|
3
|
-
description = "A
|
|
3
|
+
description = "A LP file format parser for Python, powered by Rust"
|
|
4
4
|
license = { file = "LICENSE-APACHE" }
|
|
5
5
|
requires-python = ">=3.9"
|
|
6
6
|
keywords = [
|
|
@@ -29,10 +29,10 @@ manifest-path = "python/Cargo.toml"
|
|
|
29
29
|
|
|
30
30
|
[dependency-groups]
|
|
31
31
|
dev = [
|
|
32
|
-
"mypy>=1.
|
|
33
|
-
"pip>=25.
|
|
34
|
-
"pytest>=8.
|
|
35
|
-
"ruff>=0.
|
|
32
|
+
"mypy>=1.17.0",
|
|
33
|
+
"pip>=25.1.1",
|
|
34
|
+
"pytest>=8.4.1",
|
|
35
|
+
"ruff>=0.12.5",
|
|
36
36
|
"wheel>=0.45.1",
|
|
37
37
|
]
|
|
38
38
|
|
|
@@ -43,6 +43,13 @@ ignore = ["E501"]
|
|
|
43
43
|
[tool.ruff.lint.isort]
|
|
44
44
|
known-first-party = ["parse_lp"]
|
|
45
45
|
|
|
46
|
+
[tool.pytest.ini_options]
|
|
47
|
+
testpaths = ["tests"]
|
|
48
|
+
python_files = "test_*.py"
|
|
49
|
+
python_classes = "Test*"
|
|
50
|
+
python_functions = "test_*"
|
|
51
|
+
addopts = "-v --color=yes"
|
|
52
|
+
|
|
46
53
|
[tool.coverage.run]
|
|
47
54
|
branch = true
|
|
48
55
|
source = ["parse_lp"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "parse_lp"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.5.0"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
authors = ["Dan Dixey", "Dan Dixey <dan@functorml.co.uk>"]
|
|
6
6
|
rust-version = "1.70.0"
|
|
@@ -21,7 +21,7 @@ name = "parse_lp"
|
|
|
21
21
|
crate-type = ["cdylib"]
|
|
22
22
|
|
|
23
23
|
[dependencies]
|
|
24
|
-
lp_parser_rs = { path = "../rust", features = ["csv"] }
|
|
24
|
+
lp_parser_rs = { path = "../rust", features = ["csv", "diff", "serde"] }
|
|
25
25
|
pyo3 = { version = "0.25.1", features = [
|
|
26
26
|
"extension-module",
|
|
27
27
|
"abi3",
|