parse-lp 2.4.3__tar.gz → 2.6.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.
Files changed (168) hide show
  1. {parse_lp-2.4.3 → parse_lp-2.6.0}/Cargo.lock +2 -2
  2. parse_lp-2.6.0/PKG-INFO +303 -0
  3. parse_lp-2.6.0/README.md +284 -0
  4. parse_lp-2.6.0/parse_lp/__init__.py +73 -0
  5. parse_lp-2.6.0/parse_lp/parse_lp.pyi +179 -0
  6. {parse_lp-2.4.3 → parse_lp-2.6.0}/pyproject.toml +13 -5
  7. parse_lp-2.6.0/python/.gitignore +1 -0
  8. {parse_lp-2.4.3 → parse_lp-2.6.0}/python/Cargo.toml +2 -2
  9. {parse_lp-2.4.3 → parse_lp-2.6.0}/python/MANIFEST.in +3 -2
  10. {parse_lp-2.4.3 → parse_lp-2.6.0}/python/Makefile +3 -3
  11. parse_lp-2.6.0/python/README.md +284 -0
  12. parse_lp-2.6.0/python/parse_lp/__init__.py +73 -0
  13. parse_lp-2.6.0/python/parse_lp/parse_lp.pyi +179 -0
  14. parse_lp-2.6.0/python/parse_lp/py.typed +0 -0
  15. {parse_lp-2.4.3 → parse_lp-2.6.0}/python/python/CHANGELOG.md +14 -0
  16. parse_lp-2.6.0/python/src/lib.rs +485 -0
  17. parse_lp-2.6.0/python/tests/__init__.py +0 -0
  18. parse_lp-2.6.0/python/tests/fixtures/minimize.lp +16 -0
  19. parse_lp-2.6.0/python/tests/fixtures/simple.lp +12 -0
  20. {parse_lp-2.4.3 → parse_lp-2.6.0}/python/tests/test_csv_writer.py +0 -5
  21. parse_lp-2.6.0/python/tests/test_lp_parser.py +224 -0
  22. parse_lp-2.6.0/python/tests/test_lp_writer.py +358 -0
  23. parse_lp-2.6.0/python/uv.lock +283 -0
  24. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/Cargo.toml +1 -1
  25. parse_lp-2.6.0/rust/README.md +198 -0
  26. parse_lp-2.6.0/rust/resources/afiro.lp +36 -0
  27. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/rust/CHANGELOG.md +7 -0
  28. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/context.rs +1 -1
  29. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/lib.rs +1 -10
  30. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/model.rs +2 -2
  31. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/constraint.rs +7 -4
  32. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/perf.rs +2 -0
  33. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/problem.rs +755 -13
  34. parse_lp-2.6.0/rust/src/writer.rs +562 -0
  35. parse_lp-2.4.3/PKG-INFO +0 -43
  36. parse_lp-2.4.3/README.md +0 -25
  37. parse_lp-2.4.3/parse_lp/__init__.py +0 -3
  38. parse_lp-2.4.3/python/README.md +0 -25
  39. parse_lp-2.4.3/python/parse_lp/__init__.py +0 -3
  40. parse_lp-2.4.3/python/src/lib.rs +0 -51
  41. parse_lp-2.4.3/python/uv.lock +0 -232
  42. parse_lp-2.4.3/rust/README.md +0 -120
  43. {parse_lp-2.4.3 → parse_lp-2.6.0}/Cargo.toml +0 -0
  44. {parse_lp-2.4.3 → parse_lp-2.6.0}/LICENSE-APACHE +0 -0
  45. /parse_lp-2.4.3/python/tests/__init__.py → /parse_lp-2.6.0/parse_lp/py.typed +0 -0
  46. {parse_lp-2.4.3 → parse_lp-2.6.0}/python/.cargo/config.toml +0 -0
  47. {parse_lp-2.4.3 → parse_lp-2.6.0}/python/CHANGELOG.md +0 -0
  48. {parse_lp-2.4.3 → parse_lp-2.6.0}/python/LICENSE-APACHE +0 -0
  49. {parse_lp-2.4.3 → parse_lp-2.6.0}/python/resources/afiro.lp +0 -0
  50. {parse_lp-2.4.3/rust/resources → parse_lp-2.6.0/python/tests/fixtures}/afiro.lp +0 -0
  51. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/CHANGELOG.md +0 -0
  52. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/benches/lp_parsing.rs +0 -0
  53. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/benches/parsing_micro.rs +0 -0
  54. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/1obj_1cons_all_variables_with_bounds.lp +0 -0
  55. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/2obj_2cons_all_variable_types.lp +0 -0
  56. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/2obj_2cons_only_binary_vars.lp +0 -0
  57. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/3obj_2cons.lp +0 -0
  58. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/AmericanSteelProblem.lp +0 -0
  59. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/BeerDistributionProblem.lp +0 -0
  60. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/ComputerPlantProblem.lp +0 -0
  61. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/WhiskasModel2.lp +0 -0
  62. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/afiro_ext.lp +0 -0
  63. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/blank_lines.lp +0 -0
  64. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/boeing1.lp +0 -0
  65. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/boeing2.lp +0 -0
  66. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/carbon.png +0 -0
  67. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/complex_names.lp +0 -0
  68. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/corrupt.lp +0 -0
  69. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/cplex.lp +0 -0
  70. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/diet.lp +0 -0
  71. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/empty_bounds.lp +0 -0
  72. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/fit1d.lp +0 -0
  73. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/fit2d.lp +0 -0
  74. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/infile_comments.lp +0 -0
  75. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/infile_comments2.lp +0 -0
  76. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/invalid.lp +0 -0
  77. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/kb2.lp +0 -0
  78. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/limbo.lp +0 -0
  79. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/lol.lp +0 -0
  80. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/milo1.lp +0 -0
  81. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/missing_signs.lp +0 -0
  82. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/model.lp +0 -0
  83. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/model2.lp +0 -0
  84. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/mosek.lp +0 -0
  85. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/mosek_bounds.lp +0 -0
  86. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/no_end_section.lp +0 -0
  87. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/optional_labels.lp +0 -0
  88. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/output.lp +0 -0
  89. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/output2_1.lp +0 -0
  90. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/output2_2.lp +0 -0
  91. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/output2_3.lp +0 -0
  92. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/output2_4.lp +0 -0
  93. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/output_cplex_2.lp +0 -0
  94. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/pulp.lp +0 -0
  95. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/pulp2.lp +0 -0
  96. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/sc50a.lp +0 -0
  97. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/scientific_notation.lp +0 -0
  98. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/scientific_notation_2.lp +0 -0
  99. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/semi_continuous.lp +0 -0
  100. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/sos.lp +0 -0
  101. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/sudoku.lp +0 -0
  102. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/test.lp +0 -0
  103. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/test2.lp +0 -0
  104. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/test_copy.lp +0 -0
  105. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/resources/wbm.lp +0 -0
  106. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/bin/main.rs +0 -0
  107. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/builder.rs +0 -0
  108. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/csv.rs +0 -0
  109. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/error.rs +0 -0
  110. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parser.rs +0 -0
  111. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/coefficient.rs +0 -0
  112. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/mod.rs +0 -0
  113. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/number.rs +0 -0
  114. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/objective.rs +0 -0
  115. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/parser_traits.rs +0 -0
  116. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/problem_name.rs +0 -0
  117. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/sense.rs +0 -0
  118. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/sos_constraint.rs +0 -0
  119. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/parsers/variable.rs +0 -0
  120. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/snapshots/lp_parser_rs__problem__test__minified_example.snap +0 -0
  121. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/snapshots/lp_parser_rs__problem__test__small_input.snap +0 -0
  122. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/src/validation.rs +0 -0
  123. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__afiro.snap +0 -0
  124. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__afiro_ext.snap +0 -0
  125. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__american_steel_problem.snap +0 -0
  126. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__beer_distribution_problem.snap +0 -0
  127. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__blank_lines.snap +0 -0
  128. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__boeing1.snap +0 -0
  129. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__boeing2.snap +0 -0
  130. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__complex_names.snap +0 -0
  131. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__computer_plant_problem.snap +0 -0
  132. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__cplex.snap +0 -0
  133. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__diet.snap +0 -0
  134. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__empty_bounds.snap +0 -0
  135. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__fit1d.snap +0 -0
  136. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__infile_comments.snap +0 -0
  137. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__infile_comments2.snap +0 -0
  138. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__kb2.snap +0 -0
  139. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__limbo.snap +0 -0
  140. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__lol.snap +0 -0
  141. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__milo1.snap +0 -0
  142. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__missing_signs.snap +0 -0
  143. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__model.snap +0 -0
  144. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__model2.snap +0 -0
  145. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__mosek.snap +0 -0
  146. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__mosek_bounds.snap +0 -0
  147. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__nom_fit2d.snap +0 -0
  148. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__obj3_2cons.snap +0 -0
  149. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__obj_1cons_all_variables_with_bounds.snap +0 -0
  150. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__obj_2cons_all_variable_types.snap +0 -0
  151. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__obj_2cons_only_binary_vars.snap +0 -0
  152. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__output.snap +0 -0
  153. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__output2_1.snap +0 -0
  154. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__output2_2.snap +0 -0
  155. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__output2_3.snap +0 -0
  156. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__output2_4.snap +0 -0
  157. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__pulp.snap +0 -0
  158. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__pulp2.snap +0 -0
  159. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__sc50a.snap +0 -0
  160. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__scientific_notation.snap +0 -0
  161. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__scientific_notation_2.snap +0 -0
  162. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__sos.snap +0 -0
  163. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__sudoku.snap +0 -0
  164. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__test.snap +0 -0
  165. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__test2.snap +0 -0
  166. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__wbm.snap +0 -0
  167. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/snapshots/test_nom_from_file__whiskas_model_2.snap +0 -0
  168. {parse_lp-2.4.3 → parse_lp-2.6.0}/rust/tests/test_nom_from_file.rs +0 -0
@@ -310,7 +310,7 @@ checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
310
310
 
311
311
  [[package]]
312
312
  name = "lp_parser_rs"
313
- version = "2.4.3"
313
+ version = "2.5.0"
314
314
  dependencies = [
315
315
  "csv",
316
316
  "diff-struct",
@@ -432,7 +432,7 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
432
432
 
433
433
  [[package]]
434
434
  name = "parse_lp"
435
- version = "2.4.3"
435
+ version = "2.6.0"
436
436
  dependencies = [
437
437
  "lp_parser_rs",
438
438
  "pyo3",
@@ -0,0 +1,303 @@
1
+ Metadata-Version: 2.4
2
+ Name: parse_lp
3
+ Version: 2.6.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
+ [![PyPI version](https://badge.fury.io/py/parse-lp.svg)](https://badge.fury.io/py/parse-lp)
22
+
23
+ A LP file format parser, writer, and modifier for Python, powered by Rust.
24
+
25
+ ## Features
26
+
27
+ - **Complete LP Support**: Handles all standard LP file format features
28
+ - **Problem Modification**: Programmatically modify objectives, constraints, and variables
29
+ - **LP File Writing**: Generate LP files from modified problems with round-trip compatibility
30
+ - **Easy Data Access**: Direct access to problem components (variables, constraints, objectives)
31
+ - **CSV Export**: Export parsed data to CSV files for further analysis
32
+ - **Problem Comparison**: Compare two LP problems to identify differences
33
+ - **Type Safety**: Full type hints for better IDE support and development experience
34
+
35
+ ## Installation
36
+
37
+ ```bash
38
+ pip install parse_lp
39
+ ```
40
+
41
+ ## Quick Start
42
+
43
+ ```python
44
+ from parse_lp import LpParser
45
+
46
+ # Parse an LP file
47
+ parser = LpParser("path/to/problem.lp")
48
+ parser.parse()
49
+
50
+ # Access problem information
51
+ print(f"Problem: {parser.name}")
52
+ print(f"Sense: {parser.sense}")
53
+ print(f"Variables: {parser.variable_count()}")
54
+ print(f"Constraints: {parser.constraint_count()}")
55
+
56
+ # Modify the problem
57
+ parser.update_objective_coefficient("OBJ", "x1", 5.0)
58
+ parser.rename_variable("x2", "production")
59
+ parser.update_constraint_rhs("C1", 100.0)
60
+
61
+ # Write back to LP format
62
+ modified_lp = parser.to_lp_string()
63
+ parser.save_to_file("modified_problem.lp")
64
+
65
+ # Export to CSV files
66
+ parser.to_csv("output_directory/")
67
+ ```
68
+
69
+ ## Usage Examples
70
+
71
+ ### Basic Parsing and Information
72
+
73
+ ```python
74
+ from parse_lp import LpParser
75
+
76
+ parser = LpParser("optimization_problem.lp")
77
+ parser.parse()
78
+
79
+ # Get problem overview
80
+ print(f"Problem Name: {parser.name}")
81
+ print(f"Optimization Sense: {parser.sense}")
82
+ print(f"Variables: {parser.variable_count()}")
83
+ print(f"Constraints: {parser.constraint_count()}")
84
+ print(f"Objectives: {parser.objective_count()}")
85
+ ```
86
+
87
+ ### Accessing Problem Data
88
+
89
+ ```python
90
+ # Access objectives
91
+ for i, objective in enumerate(parser.objectives):
92
+ print(f"Objective {i+1}: {objective['name']}")
93
+ for coef in objective['coefficients']:
94
+ print(f" {coef['name']}: {coef['value']}")
95
+
96
+ # Access variables
97
+ for var_name, var_info in parser.variables.items():
98
+ print(f"Variable {var_name}:")
99
+ print(f" Type: {var_info['var_type']}")
100
+ if 'bounds' in var_info:
101
+ bounds = var_info['bounds']
102
+ if 'lower' in bounds:
103
+ print(f" Lower bound: {bounds['lower']}")
104
+ if 'upper' in bounds:
105
+ print(f" Upper bound: {bounds['upper']}")
106
+
107
+ # Access constraints
108
+ for constraint in parser.constraints:
109
+ print(f"Constraint {constraint['name']}:")
110
+ print(f" Type: {constraint['type']}")
111
+ if constraint['type'] == 'standard':
112
+ print(f" Sense: {constraint['sense']}")
113
+ print(f" RHS: {constraint['rhs']}")
114
+ print(f" Coefficients: {len(constraint['coefficients'])}")
115
+ ```
116
+
117
+ ### CSV Export
118
+
119
+ ```python
120
+ import os
121
+
122
+ # Create output directory
123
+ os.makedirs("output", exist_ok=True)
124
+
125
+ # Export to CSV files
126
+ parser.to_csv("output/")
127
+
128
+ # Files created:
129
+ # - output/variables.csv
130
+ # - output/constraints.csv
131
+ # - output/objectives.csv
132
+ ```
133
+
134
+ ### Problem Modification
135
+
136
+ ```python
137
+ from parse_lp import LpParser
138
+
139
+ # Parse an existing LP file
140
+ parser = LpParser("optimization_problem.lp")
141
+ parser.parse()
142
+
143
+ # Modify objectives
144
+ parser.update_objective_coefficient("profit", "x1", 5.0)
145
+ parser.rename_objective("profit", "total_profit")
146
+
147
+ # Modify constraints
148
+ parser.update_constraint_coefficient("capacity", "x1", 2.0)
149
+ parser.update_constraint_rhs("capacity", 200.0)
150
+ parser.rename_constraint("capacity", "production_limit")
151
+
152
+ # Modify variables
153
+ parser.rename_variable("x1", "production_a")
154
+ parser.update_variable_type("production_a", "integer")
155
+
156
+ # Set problem properties
157
+ parser.set_problem_name("Modified Optimization Problem")
158
+ parser.set_sense("minimize")
159
+
160
+ # Write back to LP format
161
+ modified_lp_content = parser.to_lp_string()
162
+ parser.save_to_file("modified_problem.lp")
163
+
164
+ # Verify round-trip compatibility
165
+ new_parser = LpParser("modified_problem.lp")
166
+ new_parser.parse()
167
+ print(f"Successfully modified and re-parsed: {new_parser.name}")
168
+ ```
169
+
170
+ ### Problem Comparison
171
+
172
+ ```python
173
+ # Parse two different versions of a problem
174
+ parser1 = LpParser("problem_v1.lp")
175
+ parser1.parse()
176
+
177
+ parser2 = LpParser("problem_v2.lp")
178
+ parser2.parse()
179
+
180
+ # Compare the problems
181
+ diff = parser1.compare(parser2)
182
+
183
+ print("Comparison Results:")
184
+ print(f"Name changed: {diff['name_changed']}")
185
+ print(f"Sense changed: {diff['sense_changed']}")
186
+ print(f"Variable count difference: {diff['variable_count_diff']}")
187
+ print(f"Added variables: {diff['added_variables']}")
188
+ print(f"Removed variables: {diff['removed_variables']}")
189
+ print(f"Modified variables: {diff['modified_variables']}")
190
+ print(f"Added constraints: {diff['added_constraints']}")
191
+ print(f"Removed constraints: {diff['removed_constraints']}")
192
+ ```
193
+
194
+ ### Objectives Structure
195
+
196
+ ```python
197
+ [
198
+ {
199
+ "name": "objective_name",
200
+ "coefficients": [
201
+ {"name": "variable_name", "value": 1.5},
202
+ {"name": "another_var", "value": -2.0}
203
+ ]
204
+ }
205
+ ]
206
+ ```
207
+
208
+ ### Variables Structure
209
+
210
+ ```python
211
+ {
212
+ "variable_name": {
213
+ "name": "variable_name",
214
+ "var_type": "Continuous", # or "Binary", "Integer", etc.
215
+ "bounds": { # Optional
216
+ "lower": 0.0, # Optional
217
+ "upper": 100.0 # Optional
218
+ }
219
+ }
220
+ }
221
+ ```
222
+
223
+ ### Constraints Structure
224
+
225
+ ```python
226
+ [
227
+ {
228
+ "name": "constraint_name",
229
+ "type": "standard", # or "sos"
230
+ "sense": "LessOrEqual", # "Equal", "GreaterOrEqual"
231
+ "rhs": 10.0,
232
+ "coefficients": [
233
+ {"name": "variable_name", "value": 2.0}
234
+ ]
235
+ },
236
+ {
237
+ "name": "sos_constraint",
238
+ "type": "sos",
239
+ "sos_type": "SOS1", # or "SOS2"
240
+ "variables": ["var1", "var2", "var3"]
241
+ }
242
+ ]
243
+ ```
244
+
245
+ ## Modification Methods
246
+
247
+ ### Objective Methods
248
+
249
+ - `update_objective_coefficient(obj_name, var_name, coefficient)` - Update or add coefficient
250
+ - `rename_objective(old_name, new_name)` - Rename an objective
251
+ - `remove_objective(obj_name)` - Remove an objective
252
+
253
+ ### Constraint Methods
254
+
255
+ - `update_constraint_coefficient(const_name, var_name, coefficient)` - Update or add coefficient
256
+ - `update_constraint_rhs(const_name, new_rhs)` - Update right-hand side value
257
+ - `rename_constraint(old_name, new_name)` - Rename a constraint
258
+ - `remove_constraint(const_name)` - Remove a constraint
259
+
260
+ ### Variable Methods
261
+
262
+ - `rename_variable(old_name, new_name)` - Rename variable across problem
263
+ - `update_variable_type(var_name, var_type)` - Change variable type
264
+ - `remove_variable(var_name)` - Remove variable from problem
265
+
266
+ ### Problem Methods
267
+
268
+ - `set_problem_name(name)` - Set problem name
269
+ - `set_sense(sense)` - Set optimization sense ("maximize" or "minimize")
270
+
271
+ ### Writing Methods
272
+
273
+ - `to_lp_string()` - Generate LP format string
274
+ - `to_lp_string_with_options(**options)` - Generate with custom formatting
275
+ - `save_to_file(filepath)` - Save to LP file
276
+
277
+ ### Variable Types
278
+
279
+ Supported variable types for `update_variable_type()`:
280
+ - `"binary"` - Binary variables (0 or 1)
281
+ - `"integer"` - General integer variables
282
+ - `"general"` - Continuous variables (default)
283
+ - `"free"` - Free variables (no bounds)
284
+ - `"semicontinuous"` - Semi-continuous variables
285
+
286
+ ## Supported LP Format Features
287
+
288
+ - Multiple objective functions
289
+ - Standard constraints (≤, =, ≥)
290
+ - Variable bounds
291
+ - Variable types (continuous, binary, integer)
292
+ - SOS (Special Ordered Sets) constraints
293
+ - Problem names and comments
294
+ - Scientific notation in coefficients
295
+
296
+ ## License
297
+
298
+ Licensed under either of Apache License, Version 2.0 or MIT license at your option.
299
+
300
+ ## Contributing
301
+
302
+ Issues and pull requests are welcome at: <https://github.com/dandxy89/lp_parser_rs>
303
+
@@ -0,0 +1,284 @@
1
+ # parse_lp
2
+
3
+ [![PyPI version](https://badge.fury.io/py/parse-lp.svg)](https://badge.fury.io/py/parse-lp)
4
+
5
+ A LP file format parser, writer, and modifier for Python, powered by Rust.
6
+
7
+ ## Features
8
+
9
+ - **Complete LP Support**: Handles all standard LP file format features
10
+ - **Problem Modification**: Programmatically modify objectives, constraints, and variables
11
+ - **LP File Writing**: Generate LP files from modified problems with round-trip compatibility
12
+ - **Easy Data Access**: Direct access to problem components (variables, constraints, objectives)
13
+ - **CSV Export**: Export parsed data to CSV files for further analysis
14
+ - **Problem Comparison**: Compare two LP problems to identify differences
15
+ - **Type Safety**: Full type hints for better IDE support and development experience
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ pip install parse_lp
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ```python
26
+ from parse_lp import LpParser
27
+
28
+ # Parse an LP file
29
+ parser = LpParser("path/to/problem.lp")
30
+ parser.parse()
31
+
32
+ # Access problem information
33
+ print(f"Problem: {parser.name}")
34
+ print(f"Sense: {parser.sense}")
35
+ print(f"Variables: {parser.variable_count()}")
36
+ print(f"Constraints: {parser.constraint_count()}")
37
+
38
+ # Modify the problem
39
+ parser.update_objective_coefficient("OBJ", "x1", 5.0)
40
+ parser.rename_variable("x2", "production")
41
+ parser.update_constraint_rhs("C1", 100.0)
42
+
43
+ # Write back to LP format
44
+ modified_lp = parser.to_lp_string()
45
+ parser.save_to_file("modified_problem.lp")
46
+
47
+ # Export to CSV files
48
+ parser.to_csv("output_directory/")
49
+ ```
50
+
51
+ ## Usage Examples
52
+
53
+ ### Basic Parsing and Information
54
+
55
+ ```python
56
+ from parse_lp import LpParser
57
+
58
+ parser = LpParser("optimization_problem.lp")
59
+ parser.parse()
60
+
61
+ # Get problem overview
62
+ print(f"Problem Name: {parser.name}")
63
+ print(f"Optimization Sense: {parser.sense}")
64
+ print(f"Variables: {parser.variable_count()}")
65
+ print(f"Constraints: {parser.constraint_count()}")
66
+ print(f"Objectives: {parser.objective_count()}")
67
+ ```
68
+
69
+ ### Accessing Problem Data
70
+
71
+ ```python
72
+ # Access objectives
73
+ for i, objective in enumerate(parser.objectives):
74
+ print(f"Objective {i+1}: {objective['name']}")
75
+ for coef in objective['coefficients']:
76
+ print(f" {coef['name']}: {coef['value']}")
77
+
78
+ # Access variables
79
+ for var_name, var_info in parser.variables.items():
80
+ print(f"Variable {var_name}:")
81
+ print(f" Type: {var_info['var_type']}")
82
+ if 'bounds' in var_info:
83
+ bounds = var_info['bounds']
84
+ if 'lower' in bounds:
85
+ print(f" Lower bound: {bounds['lower']}")
86
+ if 'upper' in bounds:
87
+ print(f" Upper bound: {bounds['upper']}")
88
+
89
+ # Access constraints
90
+ for constraint in parser.constraints:
91
+ print(f"Constraint {constraint['name']}:")
92
+ print(f" Type: {constraint['type']}")
93
+ if constraint['type'] == 'standard':
94
+ print(f" Sense: {constraint['sense']}")
95
+ print(f" RHS: {constraint['rhs']}")
96
+ print(f" Coefficients: {len(constraint['coefficients'])}")
97
+ ```
98
+
99
+ ### CSV Export
100
+
101
+ ```python
102
+ import os
103
+
104
+ # Create output directory
105
+ os.makedirs("output", exist_ok=True)
106
+
107
+ # Export to CSV files
108
+ parser.to_csv("output/")
109
+
110
+ # Files created:
111
+ # - output/variables.csv
112
+ # - output/constraints.csv
113
+ # - output/objectives.csv
114
+ ```
115
+
116
+ ### Problem Modification
117
+
118
+ ```python
119
+ from parse_lp import LpParser
120
+
121
+ # Parse an existing LP file
122
+ parser = LpParser("optimization_problem.lp")
123
+ parser.parse()
124
+
125
+ # Modify objectives
126
+ parser.update_objective_coefficient("profit", "x1", 5.0)
127
+ parser.rename_objective("profit", "total_profit")
128
+
129
+ # Modify constraints
130
+ parser.update_constraint_coefficient("capacity", "x1", 2.0)
131
+ parser.update_constraint_rhs("capacity", 200.0)
132
+ parser.rename_constraint("capacity", "production_limit")
133
+
134
+ # Modify variables
135
+ parser.rename_variable("x1", "production_a")
136
+ parser.update_variable_type("production_a", "integer")
137
+
138
+ # Set problem properties
139
+ parser.set_problem_name("Modified Optimization Problem")
140
+ parser.set_sense("minimize")
141
+
142
+ # Write back to LP format
143
+ modified_lp_content = parser.to_lp_string()
144
+ parser.save_to_file("modified_problem.lp")
145
+
146
+ # Verify round-trip compatibility
147
+ new_parser = LpParser("modified_problem.lp")
148
+ new_parser.parse()
149
+ print(f"Successfully modified and re-parsed: {new_parser.name}")
150
+ ```
151
+
152
+ ### Problem Comparison
153
+
154
+ ```python
155
+ # Parse two different versions of a problem
156
+ parser1 = LpParser("problem_v1.lp")
157
+ parser1.parse()
158
+
159
+ parser2 = LpParser("problem_v2.lp")
160
+ parser2.parse()
161
+
162
+ # Compare the problems
163
+ diff = parser1.compare(parser2)
164
+
165
+ print("Comparison Results:")
166
+ print(f"Name changed: {diff['name_changed']}")
167
+ print(f"Sense changed: {diff['sense_changed']}")
168
+ print(f"Variable count difference: {diff['variable_count_diff']}")
169
+ print(f"Added variables: {diff['added_variables']}")
170
+ print(f"Removed variables: {diff['removed_variables']}")
171
+ print(f"Modified variables: {diff['modified_variables']}")
172
+ print(f"Added constraints: {diff['added_constraints']}")
173
+ print(f"Removed constraints: {diff['removed_constraints']}")
174
+ ```
175
+
176
+ ### Objectives Structure
177
+
178
+ ```python
179
+ [
180
+ {
181
+ "name": "objective_name",
182
+ "coefficients": [
183
+ {"name": "variable_name", "value": 1.5},
184
+ {"name": "another_var", "value": -2.0}
185
+ ]
186
+ }
187
+ ]
188
+ ```
189
+
190
+ ### Variables Structure
191
+
192
+ ```python
193
+ {
194
+ "variable_name": {
195
+ "name": "variable_name",
196
+ "var_type": "Continuous", # or "Binary", "Integer", etc.
197
+ "bounds": { # Optional
198
+ "lower": 0.0, # Optional
199
+ "upper": 100.0 # Optional
200
+ }
201
+ }
202
+ }
203
+ ```
204
+
205
+ ### Constraints Structure
206
+
207
+ ```python
208
+ [
209
+ {
210
+ "name": "constraint_name",
211
+ "type": "standard", # or "sos"
212
+ "sense": "LessOrEqual", # "Equal", "GreaterOrEqual"
213
+ "rhs": 10.0,
214
+ "coefficients": [
215
+ {"name": "variable_name", "value": 2.0}
216
+ ]
217
+ },
218
+ {
219
+ "name": "sos_constraint",
220
+ "type": "sos",
221
+ "sos_type": "SOS1", # or "SOS2"
222
+ "variables": ["var1", "var2", "var3"]
223
+ }
224
+ ]
225
+ ```
226
+
227
+ ## Modification Methods
228
+
229
+ ### Objective Methods
230
+
231
+ - `update_objective_coefficient(obj_name, var_name, coefficient)` - Update or add coefficient
232
+ - `rename_objective(old_name, new_name)` - Rename an objective
233
+ - `remove_objective(obj_name)` - Remove an objective
234
+
235
+ ### Constraint Methods
236
+
237
+ - `update_constraint_coefficient(const_name, var_name, coefficient)` - Update or add coefficient
238
+ - `update_constraint_rhs(const_name, new_rhs)` - Update right-hand side value
239
+ - `rename_constraint(old_name, new_name)` - Rename a constraint
240
+ - `remove_constraint(const_name)` - Remove a constraint
241
+
242
+ ### Variable Methods
243
+
244
+ - `rename_variable(old_name, new_name)` - Rename variable across problem
245
+ - `update_variable_type(var_name, var_type)` - Change variable type
246
+ - `remove_variable(var_name)` - Remove variable from problem
247
+
248
+ ### Problem Methods
249
+
250
+ - `set_problem_name(name)` - Set problem name
251
+ - `set_sense(sense)` - Set optimization sense ("maximize" or "minimize")
252
+
253
+ ### Writing Methods
254
+
255
+ - `to_lp_string()` - Generate LP format string
256
+ - `to_lp_string_with_options(**options)` - Generate with custom formatting
257
+ - `save_to_file(filepath)` - Save to LP file
258
+
259
+ ### Variable Types
260
+
261
+ Supported variable types for `update_variable_type()`:
262
+ - `"binary"` - Binary variables (0 or 1)
263
+ - `"integer"` - General integer variables
264
+ - `"general"` - Continuous variables (default)
265
+ - `"free"` - Free variables (no bounds)
266
+ - `"semicontinuous"` - Semi-continuous variables
267
+
268
+ ## Supported LP Format Features
269
+
270
+ - Multiple objective functions
271
+ - Standard constraints (≤, =, ≥)
272
+ - Variable bounds
273
+ - Variable types (continuous, binary, integer)
274
+ - SOS (Special Ordered Sets) constraints
275
+ - Problem names and comments
276
+ - Scientific notation in coefficients
277
+
278
+ ## License
279
+
280
+ Licensed under either of Apache License, Version 2.0 or MIT license at your option.
281
+
282
+ ## Contributing
283
+
284
+ Issues and pull requests are welcome at: <https://github.com/dandxy89/lp_parser_rs>
@@ -0,0 +1,73 @@
1
+ """parse_lp - A fast LP file format parser, writer, and modifier 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. It supports parsing, modifying,
5
+ and writing LP files with full round-trip compatibility.
6
+
7
+ Key Features:
8
+ - Fast parsing of LP files of various formats
9
+ - Programmatic modification of LP problems (objectives, constraints, variables)
10
+ - Write LP problems back to standard LP format
11
+ - Export parsed data to CSV files
12
+ - Access to problem components (variables, constraints, objectives)
13
+ - Compare two LP problems to find differences
14
+ - Type hints for better IDE support
15
+
16
+ Example Usage:
17
+ >>> from parse_lp import LpParser
18
+ >>>
19
+ >>> # Parse an LP file
20
+ >>> parser = LpParser("optimization_problem.lp")
21
+ >>> parser.parse()
22
+ >>>
23
+ >>> # Access problem information
24
+ >>> print(f"Problem name: {parser.name}")
25
+ >>> print(f"Variables: {parser.variable_count()}")
26
+ >>> print(f"Constraints: {parser.constraint_count()}")
27
+ >>>
28
+ >>> # Modify the problem
29
+ >>> parser.update_objective_coefficient("profit", "x1", 5.0)
30
+ >>> parser.rename_variable("x2", "production")
31
+ >>> parser.update_constraint_rhs("capacity", 100.0)
32
+ >>> parser.update_variable_type("x1", "integer")
33
+ >>>
34
+ >>> # Write back to LP format
35
+ >>> modified_lp = parser.to_lp_string()
36
+ >>> parser.save_to_file("modified_problem.lp")
37
+ >>>
38
+ >>> # Export to CSV files
39
+ >>> parser.to_csv("output/")
40
+ >>>
41
+ >>> # Compare two problems
42
+ >>> parser2 = LpParser("modified_problem.lp")
43
+ >>> parser2.parse()
44
+ >>> diff = parser.compare(parser2)
45
+ >>> print(f"Added variables: {diff['added_variables']}")
46
+
47
+ Modification Methods:
48
+ Objective modifications:
49
+ - update_objective_coefficient(obj_name, var_name, coefficient)
50
+ - rename_objective(old_name, new_name)
51
+ - remove_objective(obj_name)
52
+
53
+ Constraint modifications:
54
+ - update_constraint_coefficient(const_name, var_name, coefficient)
55
+ - update_constraint_rhs(const_name, new_rhs)
56
+ - rename_constraint(old_name, new_name)
57
+ - remove_constraint(const_name)
58
+
59
+ Variable modifications:
60
+ - rename_variable(old_name, new_name)
61
+ - update_variable_type(var_name, var_type) # binary, integer, general, free, semicontinuous
62
+ - remove_variable(var_name)
63
+
64
+ Problem modifications:
65
+ - set_problem_name(name)
66
+ - set_sense(sense) # maximize, minimize
67
+
68
+ """
69
+
70
+ from .parse_lp import LpParser
71
+
72
+ __version__ = "2.5.0"
73
+ __all__ = ["LpParser"]