pyoframe 1.0.1__tar.gz → 1.1.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 (274) hide show
  1. pyoframe-1.1.0/.github/dependabot.yml +11 -0
  2. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/ci.yml +2 -1
  3. {pyoframe-1.0.1 → pyoframe-1.1.0}/PKG-INFO +5 -5
  4. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/.nav.yml +1 -1
  5. pyoframe-1.1.0/docs/contribute/index.md +65 -0
  6. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/facility_location.md +4 -4
  7. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/internals.md +8 -3
  8. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/concepts/.nav.yml +0 -1
  9. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/concepts/addition.md +9 -13
  10. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/concepts/solver-access.md +4 -0
  11. pyoframe-1.1.0/docs/learn/concepts/special-functions.md +12 -0
  12. pyoframe-1.1.0/docs/learn/get-started/.nav.yml +5 -0
  13. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/example-with-dimensions.md +18 -21
  14. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/example.md +4 -4
  15. pyoframe-1.1.0/docs/learn/get-started/basics.md +347 -0
  16. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/.nav.yml +0 -1
  17. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/index.md +1 -5
  18. {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/PKG-INFO +5 -5
  19. {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/SOURCES.txt +3 -5
  20. {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/requires.txt +4 -4
  21. {pyoframe-1.0.1 → pyoframe-1.1.0}/pyproject.toml +4 -4
  22. {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/__init__.py +2 -0
  23. {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_arithmetic.py +3 -3
  24. {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_constants.py +9 -10
  25. {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_core.py +84 -57
  26. {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_model.py +3 -3
  27. {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_model_element.py +2 -0
  28. pyoframe-1.1.0/src/pyoframe/_monkey_patch.py +38 -0
  29. {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_objective.py +2 -2
  30. pyoframe-1.1.0/src/pyoframe/_param.py +99 -0
  31. {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_utils.py +2 -2
  32. {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_version.py +3 -3
  33. pyoframe-1.1.0/tests/examples/cutting_stock_problem/results/problem-highs-machine.lp +183 -0
  34. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/model.py +3 -3
  35. pyoframe-1.1.0/tests/examples/diet_problem/results/problem-highs-machine.lp +21 -0
  36. pyoframe-1.1.0/tests/examples/diet_problem/results/solution-highs-machine.sol +69 -0
  37. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/model.py +4 -6
  38. pyoframe-1.1.0/tests/examples/facility_problem/results/problem-highs-machine.lp +29 -0
  39. pyoframe-1.1.0/tests/examples/facility_problem/results/solution-highs-machine.sol +50 -0
  40. pyoframe-1.1.0/tests/examples/portfolio_optim/results/problem-highs-machine.lp +14 -0
  41. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-highs-machine.sol +14 -14
  42. pyoframe-1.1.0/tests/examples/production_planning/results/problem-highs-machine.lp +9 -0
  43. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-highs-machine.sol +10 -10
  44. pyoframe-1.1.0/tests/examples/pumped_storage/results/problem-highs-machine.lp +8860 -0
  45. pyoframe-1.1.0/tests/examples/pumped_storage/results/solution-highs-machine.sol +7317 -0
  46. pyoframe-1.1.0/tests/examples/sudoku/results/problem-highs-machine.lp +1813 -0
  47. pyoframe-1.1.0/tests/examples/sudoku/results/solution-highs-machine.sol +1090 -0
  48. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_addition.py +9 -11
  49. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_arithmetic.py +102 -7
  50. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_examples.py +10 -4
  51. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_io.py +1 -1
  52. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_names.py +2 -2
  53. pyoframe-1.1.0/tests/test_param.py +29 -0
  54. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_variable.py +11 -1
  55. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/util.py +4 -2
  56. pyoframe-1.0.1/.github/dependabot.yml +0 -16
  57. pyoframe-1.0.1/docs/contribute/index.md +0 -51
  58. pyoframe-1.0.1/docs/learn/concepts/building-blocks.md +0 -17
  59. pyoframe-1.0.1/docs/learn/concepts/special-functions.md +0 -112
  60. pyoframe-1.0.1/docs/learn/get-started/.nav.yml +0 -4
  61. pyoframe-1.0.1/docs/reference/external/.nav.yml +0 -4
  62. pyoframe-1.0.1/docs/reference/external/pandas.DataFrame.to_expr.md +0 -3
  63. pyoframe-1.0.1/docs/reference/external/pandas.Series.to_expr.md +0 -3
  64. pyoframe-1.0.1/docs/reference/external/polars.DataFrame.to_expr.md +0 -3
  65. pyoframe-1.0.1/src/pyoframe/_monkey_patch.py +0 -82
  66. pyoframe-1.0.1/tests/examples/cutting_stock_problem/results/problem-highs-machine.lp +0 -183
  67. pyoframe-1.0.1/tests/examples/diet_problem/results/problem-highs-machine.lp +0 -21
  68. pyoframe-1.0.1/tests/examples/diet_problem/results/solution-highs-machine.sol +0 -69
  69. pyoframe-1.0.1/tests/examples/facility_problem/results/problem-highs-machine.lp +0 -29
  70. pyoframe-1.0.1/tests/examples/facility_problem/results/solution-highs-machine.sol +0 -50
  71. pyoframe-1.0.1/tests/examples/portfolio_optim/results/problem-highs-machine.lp +0 -14
  72. pyoframe-1.0.1/tests/examples/production_planning/results/problem-highs-machine.lp +0 -9
  73. pyoframe-1.0.1/tests/examples/pumped_storage/results/problem-highs-machine.lp +0 -8876
  74. pyoframe-1.0.1/tests/examples/pumped_storage/results/solution-highs-machine.sol +0 -7317
  75. pyoframe-1.0.1/tests/examples/sudoku/results/problem-highs-machine.lp +0 -1813
  76. pyoframe-1.0.1/tests/examples/sudoku/results/solution-highs-machine.sol +0 -1090
  77. {pyoframe-1.0.1 → pyoframe-1.1.0}/.gitattributes +0 -0
  78. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/CODEOWNERS +0 -0
  79. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/actions/setup_optimizers_linux/action.yml +0 -0
  80. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/actions/setup_optimizers_macos/action.yml +0 -0
  81. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/actions/setup_optimizers_windows/action.yml +0 -0
  82. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/format.yml +0 -0
  83. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/lines_changed_counter.yml +0 -0
  84. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/lint.yml +0 -0
  85. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/publish_doc.yml +0 -0
  86. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/publish_doc_dev.yml +0 -0
  87. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/publish_to_pypi.yml +0 -0
  88. {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/test_doc.yml +0 -0
  89. {pyoframe-1.0.1 → pyoframe-1.1.0}/.gitignore +0 -0
  90. {pyoframe-1.0.1 → pyoframe-1.1.0}/.pre-commit-config.yaml +0 -0
  91. {pyoframe-1.0.1 → pyoframe-1.1.0}/.vscode/launch.json +0 -0
  92. {pyoframe-1.0.1 → pyoframe-1.1.0}/.vscode/settings.json +0 -0
  93. {pyoframe-1.0.1 → pyoframe-1.1.0}/CHANGELOG.md +0 -0
  94. {pyoframe-1.0.1 → pyoframe-1.1.0}/LICENSE +0 -0
  95. {pyoframe-1.0.1 → pyoframe-1.1.0}/README.md +0 -0
  96. {pyoframe-1.0.1 → pyoframe-1.1.0}/conftest.py +0 -0
  97. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/.nav.yml +0 -0
  98. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/diet.md +0 -0
  99. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/index.md +0 -0
  100. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/portfolio_optimization.md +0 -0
  101. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/production.md +0 -0
  102. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/index.md +0 -0
  103. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/javascripts/feedback.js +0 -0
  104. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/.nav.yml +0 -0
  105. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/datastructure.md +0 -0
  106. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/performance.md +0 -0
  107. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/quadratics.md +0 -0
  108. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/troubleshooting.md +0 -0
  109. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/food_data.csv +0 -0
  110. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/foods.csv +0 -0
  111. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/foods_to_nutrients.csv +0 -0
  112. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/nutrients.csv +0 -0
  113. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/results.csv +0 -0
  114. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/installation.md +0 -0
  115. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/power_grid_example.ipynb +0 -0
  116. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/three-bus.png +0 -0
  117. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/migrate/v1.0.md +0 -0
  118. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/overrides/main.html +0 -0
  119. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/overrides/partials/actions.html +0 -0
  120. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/overrides/partials/comments.html +0 -0
  121. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/overrides/partials/integrations/analytics/custom.html +0 -0
  122. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/bases/.nav.yml +0 -0
  123. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/bases/BaseBlock.md +0 -0
  124. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/bases/BaseOperableBlock.md +0 -0
  125. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/public/.nav.yml +0 -0
  126. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/public/Config.md +0 -0
  127. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/types/.nav.yml +0 -0
  128. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/types/Operable.md +0 -0
  129. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/stylesheets/extra.css +0 -0
  130. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/data_py.parquet +0 -0
  131. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/gen_py.parquet +0 -0
  132. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/index.md +0 -0
  133. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/pyoframe-performance.ipynb +0 -0
  134. {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/three-bus-four-gen.png +0 -0
  135. {pyoframe-1.0.1 → pyoframe-1.1.0}/giscus.json +0 -0
  136. {pyoframe-1.0.1 → pyoframe-1.1.0}/mkdocs.yml +0 -0
  137. {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/dependency_links.txt +0 -0
  138. {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/top_level.txt +0 -0
  139. {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/archive/benchmark_assign_ids_constraints.py +0 -0
  140. {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/archive/benchmark_assign_ids_constraints_2.py +0 -0
  141. {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/archive/benchmark_assign_ids_variables.py +0 -0
  142. {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/archive/benchmark_attr_performance.py +0 -0
  143. {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/generate_api_reference.py +0 -0
  144. {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/griffe_extensions.py +0 -0
  145. {pyoframe-1.0.1 → pyoframe-1.1.0}/setup.cfg +0 -0
  146. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/__init__.py +0 -0
  147. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/conftest.py +0 -0
  148. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/README.md +0 -0
  149. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/__init__.py +0 -0
  150. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/__init__.py +0 -0
  151. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/input_data/orders.csv +0 -0
  152. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/input_data/parameters.csv +0 -0
  153. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/model.py +0 -0
  154. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/objective.csv +0 -0
  155. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-copt-machine.lp +0 -0
  156. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-copt-pretty.lp +0 -0
  157. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-gurobi-machine.lp +0 -0
  158. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-gurobi-pretty.lp +0 -0
  159. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-highs-pretty.lp +0 -0
  160. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/README.md +0 -0
  161. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/__init__.py +0 -0
  162. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/input_data/foods.csv +0 -0
  163. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/input_data/foods_to_nutrients.csv +0 -0
  164. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/input_data/nutrients.csv +0 -0
  165. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/model_gurobipy.py +0 -0
  166. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/Buy.csv +0 -0
  167. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/Buy_ub.csv +0 -0
  168. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/max_nutrients.csv +0 -0
  169. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/min_nutrients.csv +0 -0
  170. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/objective.csv +0 -0
  171. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-copt-machine.lp +0 -0
  172. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-copt-pretty.lp +0 -0
  173. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-gurobi-machine.lp +0 -0
  174. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-gurobi-pretty.lp +0 -0
  175. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-highs-pretty.lp +0 -0
  176. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-copt-machine.sol +0 -0
  177. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-copt-pretty.sol +0 -0
  178. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-gurobi-machine.sol +0 -0
  179. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-gurobi-pretty.sol +0 -0
  180. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-highs-pretty.sol +0 -0
  181. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/__init__.py +0 -0
  182. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/results/objective.csv +0 -0
  183. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/results/problem-gurobi-machine.lp +0 -0
  184. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/results/problem-gurobi-pretty.lp +0 -0
  185. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/__init__.py +0 -0
  186. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/input_data/plants.csv +0 -0
  187. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/input_data/transport_costs.csv +0 -0
  188. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/input_data/wharehouses.csv +0 -0
  189. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/model.py +0 -0
  190. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/model_gurobipy.py +0 -0
  191. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/objective.csv +0 -0
  192. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/open.csv +0 -0
  193. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-copt-machine.lp +0 -0
  194. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-copt-pretty.lp +0 -0
  195. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-gurobi-machine.lp +0 -0
  196. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-gurobi-pretty.lp +0 -0
  197. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-highs-pretty.lp +0 -0
  198. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-copt-machine.sol +0 -0
  199. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-copt-pretty.sol +0 -0
  200. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-gurobi-machine.sol +0 -0
  201. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-gurobi-pretty.sol +0 -0
  202. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-highs-pretty.sol +0 -0
  203. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/transport.csv +0 -0
  204. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/input_data/assets.csv +0 -0
  205. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/input_data/covariance.csv +0 -0
  206. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/input_data/portfolio_params.csv +0 -0
  207. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/model.py +0 -0
  208. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/con_min_return.csv +0 -0
  209. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/con_weights_sum.csv +0 -0
  210. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/objective.csv +0 -0
  211. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-copt-machine.lp +0 -0
  212. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-copt-pretty.lp +0 -0
  213. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-gurobi-machine.lp +0 -0
  214. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-gurobi-pretty.lp +0 -0
  215. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-highs-pretty.lp +0 -0
  216. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-copt-machine.sol +0 -0
  217. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-copt-pretty.sol +0 -0
  218. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-gurobi-machine.sol +0 -0
  219. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-gurobi-pretty.sol +0 -0
  220. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-highs-pretty.sol +0 -0
  221. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/weight.csv +0 -0
  222. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/__init__.py +0 -0
  223. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/input_data/machines_availability.csv +0 -0
  224. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/input_data/processing_times.csv +0 -0
  225. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/input_data/products_profit.csv +0 -0
  226. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/model.py +0 -0
  227. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/objective.csv +0 -0
  228. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-copt-machine.lp +0 -0
  229. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-copt-pretty.lp +0 -0
  230. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-gurobi-machine.lp +0 -0
  231. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-gurobi-pretty.lp +0 -0
  232. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-highs-pretty.lp +0 -0
  233. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-copt-machine.sol +0 -0
  234. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-copt-pretty.sol +0 -0
  235. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-gurobi-machine.sol +0 -0
  236. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-gurobi-pretty.sol +0 -0
  237. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-highs-pretty.sol +0 -0
  238. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution.csv +0 -0
  239. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/README.md +0 -0
  240. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/__init__.py +0 -0
  241. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/input_data/elspot-prices_2021_hourly_eur.csv +0 -0
  242. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/model.py +0 -0
  243. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/Pump.csv +0 -0
  244. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/Storage_level.csv +0 -0
  245. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/Turb.csv +0 -0
  246. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/objective.csv +0 -0
  247. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-copt-machine.lp +0 -0
  248. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-copt-pretty.lp +0 -0
  249. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-gurobi-machine.lp +0 -0
  250. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-gurobi-pretty.lp +0 -0
  251. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-highs-pretty.lp +0 -0
  252. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-copt-machine.sol +0 -0
  253. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-copt-pretty.sol +0 -0
  254. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-gurobi-machine.sol +0 -0
  255. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-gurobi-pretty.sol +0 -0
  256. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-highs-pretty.sol +0 -0
  257. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/__init__.py +0 -0
  258. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/input_data/initial_numbers.csv +0 -0
  259. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/model.py +0 -0
  260. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-copt-machine.lp +0 -0
  261. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-copt-pretty.lp +0 -0
  262. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-gurobi-machine.lp +0 -0
  263. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-gurobi-pretty.lp +0 -0
  264. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-highs-pretty.lp +0 -0
  265. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-copt-machine.sol +0 -0
  266. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-copt-pretty.sol +0 -0
  267. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-gurobi-machine.sol +0 -0
  268. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-gurobi-pretty.sol +0 -0
  269. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-highs-pretty.sol +0 -0
  270. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution.csv +0 -0
  271. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_constraint.py +0 -0
  272. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_model.py +0 -0
  273. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_objective.py +0 -0
  274. {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_solver.py +0 -0
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: pip
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "17:00"
8
+ allow:
9
+ - dependency-type: production
10
+ - dependency-name: highsbox
11
+ - dependency-name: llvmlite
@@ -55,7 +55,8 @@ jobs:
55
55
  exit 1
56
56
  run:
57
57
  if: |
58
- (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) ||
58
+ (github.event_name == 'pull_request_target' && github.actor == 'dependabot[bot]') ||
59
+ (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]') ||
59
60
  (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) ||
60
61
  (github.event_name != 'pull_request_target' && github.event_name != 'pull_request')
61
62
  runs-on: ubuntu-latest
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyoframe
3
- Version: 1.0.1
3
+ Version: 1.1.0
4
4
  Summary: Blazing fast linear program interface
5
5
  Author-email: Bravos Power <dev@bravospower.com>
6
6
  License-Expression: MIT
@@ -20,21 +20,21 @@ Requires-Dist: pyarrow
20
20
  Requires-Dist: pandas<3
21
21
  Requires-Dist: pyoptinterface==0.5.1
22
22
  Provides-Extra: highs
23
- Requires-Dist: highsbox<=1.11.0; extra == "highs"
23
+ Requires-Dist: highsbox<=1.12.0; extra == "highs"
24
24
  Provides-Extra: ipopt
25
25
  Requires-Dist: pyoptinterface[nlp]; extra == "ipopt"
26
- Requires-Dist: llvmlite<=0.44.0; extra == "ipopt"
26
+ Requires-Dist: llvmlite<=0.46.0; extra == "ipopt"
27
27
  Provides-Extra: dev
28
28
  Requires-Dist: ruff==0.12.11; extra == "dev"
29
29
  Requires-Dist: polars>=1.32.3; extra == "dev"
30
30
  Requires-Dist: pytest==8.4.1; extra == "dev"
31
31
  Requires-Dist: pytest-cov==6.2.1; extra == "dev"
32
- Requires-Dist: sybil[pytest]==9.2.0; extra == "dev"
32
+ Requires-Dist: sybil[pytest]==9.3.0; extra == "dev"
33
33
  Requires-Dist: pre-commit==4.3.0; extra == "dev"
34
34
  Requires-Dist: gurobipy==12.0.3; extra == "dev"
35
35
  Requires-Dist: coverage==7.10.6; extra == "dev"
36
36
  Requires-Dist: ipykernel==6.30.1; extra == "dev"
37
- Requires-Dist: highsbox<=1.11.0; extra == "dev"
37
+ Requires-Dist: highsbox<=1.12.0; extra == "dev"
38
38
  Requires-Dist: pyoptinterface[nlp]; extra == "dev"
39
39
  Requires-Dist: numpy; extra == "dev"
40
40
  Provides-Extra: docs
@@ -8,6 +8,6 @@ nav:
8
8
  - learn/advanced-concepts
9
9
  - learn/migrate
10
10
  - examples
11
- - reference
11
+ - Reference API: reference
12
12
  - why-pyoframe/index.md
13
13
  - contribute
@@ -0,0 +1,65 @@
1
+ ---
2
+ hide:
3
+ - navigation
4
+ ---
5
+ # Contribute
6
+
7
+ Contributions are more than welcome! Submit a pull request, or [open an issue](https://github.com/Bravos-Power/pyoframe/issues/new) and I (Martin) will gladly answer your questions on how to contribute.
8
+
9
+ ## Setup a development environment
10
+
11
+ 1. Clone this repository.
12
+ ```console
13
+ git clone https://github.com/Bravos-Power/pyoframe
14
+ ```
15
+
16
+ 2. Install the dependencies.
17
+ ```console
18
+ pip install --editable .[dev,docs]
19
+ ```
20
+
21
+ 3. Install the pre-commit hooks.
22
+ ```console
23
+ pre-commit install
24
+ ```
25
+
26
+ ## Running the test suite
27
+
28
+ Run `pytest` to execute the test suite. (If you'd like to view coverage information add the flag `--cov` and then run `coverage html`.)
29
+
30
+ The only errors you should see when running the test suite are those related to a solver not being installed.
31
+
32
+ Pyoframe has several types of tests.
33
+
34
+ 1. Your typical unit tests under the `tests/` folder.
35
+
36
+ 2. Integration tests in `tests/test_examples.py`. These tests will run all the models in `tests/examples` and make sure that your changes haven't altered the model results (stored under `tests/examples/<model>/results`). In the rare cases where you _want_ the model results to change (e.g. if you've changed the model), you can regenerate the results using `python -m tests.test_examples`.
37
+
38
+ 3. Doctests in the docstrings of the source code (`src/`).
39
+
40
+ 4. Documentation tests (in `docs/`). All Python code blocks in the documentation are run to ensure the documentation doesn't become outdated. This is done using Sybil. Refer to the [Sybil documentation](https://sybil.readthedocs.io/en/latest/markdown.html#code-blocks) to learn how to create setup code or skip code blocks you don't wish to test.
41
+
42
+ !!! warning "Non-breaking spaces"
43
+ Be aware that Pyoframe uses non-breaking spaces to improve the formatting of expressions. If your Sybil tests are unexpectedly failing, make sure that the expected output contains all the needed non-breaking spaces.
44
+
45
+ ## Writing documentation
46
+
47
+ You can preview the documentation website by running `mkdocs serve` and navigating to [`http://127.0.0.1:8000/pyoframe/`](http://127.0.0.1:8000/pyoframe/).
48
+
49
+ We use [Material Docs](https://squidfunk.github.io/mkdocs-material/) for documentation with several plugins to enable features like automatically compiling the docstrings into the reference API. Please follow the [Google docstring style](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) and the [Google style guide](https://developers.google.com/style). We use Mike to allow readers to view the documentation for previous releases (preview available via `mike serve`).
50
+
51
+ ## Linting and formatting
52
+
53
+ We use Ruff for linting and formatting. The pre-commit hooks will run `ruff format` on commit. You should also make sure `ruff check` returns no errors before submitting a PR. To format code blocks in the documentation run: `doccmd --language=python --no-pad-file --command="ruff format" docs/`.
54
+
55
+ ## Additional tips
56
+
57
+ I recommend skimming or reading the [Internal Details](../learn/advanced-concepts/internals.md) page for some background on how Pyoframe works.
58
+
59
+ For core developers:
60
+
61
+ - If you use `.unique`, `.join`, `.sort`, or `.group_by` on a Polars dataframe, make sure to set the `maintain_order` parameter appropriately (typically, `maintain_order=Config.maintain_order`).
62
+
63
+ For repository maintainers:
64
+
65
+ - Our CI pipeline on Github Actions requires a Gurobi and COPT license to run. If the Gurobi license expires, generate a new one and copy the contents of the `guorbi.lic` file into the `GUROBI_WLS` Github secret (Settings -> Secrets and variables -> actions). Similarly, if the COPT license expires, request a new academic license (or email COPT sales for a free one) and copy the contents of both license files to the matching Github secrets.
@@ -26,12 +26,12 @@ model.customers = model.x_axis * model.y_axis # (1)!
26
26
 
27
27
 
28
28
  model.facility_position = pf.Variable(model.facilities, model.axis, lb=0, ub=1)
29
- model.customer_position_x = pd.DataFrame(
29
+ model.customer_position_x = pf.Param(
30
30
  {"x": range(G), "x_pos": [step / (G - 1) for step in range(G)]}
31
- ).to_expr()
32
- model.customer_position_y = pd.DataFrame(
31
+ )
32
+ model.customer_position_y = pf.Param(
33
33
  {"y": range(G), "y_pos": [step / (G - 1) for step in range(G)]}
34
- ).to_expr()
34
+ )
35
35
 
36
36
  model.max_distance = pf.Variable(lb=0)
37
37
 
@@ -1,7 +1,6 @@
1
1
  # Internal details
2
2
 
3
- Pyoframe's inner workings involve a few tricks that you should be aware of
4
- if you wish to modify Pyoframe's internal code.
3
+ Pyoframe's inner workings involve a few tricks that you should be aware of if you wish to contribute to Pyoframe's code base.
5
4
 
6
5
  ## The zero variable
7
6
 
@@ -16,4 +15,10 @@ constant terms and also simplifies the [handling of quadratics](#quadratics).
16
15
 
17
16
  Internally, [Expression][pyoframe.Expression] is used to represent both linear and quadratic mathematical expressions. When a quadratic expression is formed, column `__quadratic_variable_id` is added to [Expression.data][pyoframe.Expression.data]. If an expression's quadratic terms happen to cancel out (e.g. `(ab + c) - ab`), this column is automatically removed.
18
17
 
19
- Column `__quadratic_variable_id` records the ID of the _second_ variable in a quadratic term (the `b` in `3ab`). For linear terms, which have no second variable, this column contains the [Zero Variable](#the-zero-variable). Quadratic terms are always stored such that the first term's variable ID (in column `__variable_id`) is greater or equal to the second term's variable id (in column `__quadratic_variable_id`). For example, `var_7 * var_8` would be rearranged and stored as `var_8 * var_7`. This helps simplify expressions and provides a useful guarantee: If the variable in the first column (`__variable_id`) is the Zero Variable (`var_0`) we know the variable in the second column must also be the Zero Variable and, thus, the term must be a constant.
18
+ Column `__quadratic_variable_id` records the ID of the _second_ variable in a quadratic term (the `b` in `3ab`). For linear terms, which have no second variable, this column contains the [Zero Variable](#the-zero-variable).
19
+
20
+ Quadratic terms are always stored such that the first term's variable ID (in column `__variable_id`) is greater or equal to the second term's variable id (in column `__quadratic_variable_id`). For example, `var_7 * var_8` would be rearranged and stored as `var_8 * var_7`. This helps simplify expressions and provides a useful guarantee: If the variable in the first column (`__variable_id`) is the Zero Variable (`var_0`) we know the variable in the second column must also be the Zero Variable and, thus, the term must be a constant.
21
+
22
+ ## Division
23
+
24
+ Divisions are rearranged into multiplications when possible. Specifically, `a / b` is computed as `a * (1 / b)` (see `BaseOperableBlock.__truediv__`) except for the special case where `a` is a `float` or `int`. In that case, a Polars operation is used to compute the division (see `Expression.__rtruediv__`).
@@ -1,5 +1,4 @@
1
1
  nav:
2
- - building-blocks.md
3
2
  - addition.md
4
3
  - special-functions.md
5
4
  - solver-access.md
@@ -31,14 +31,13 @@ import pyoframe as pf
31
31
  import polars as pl
32
32
 
33
33
  air_data = pl.DataFrame({"flight_no": ["A4543", "K937"], "emissions": [1.4, 2.4]})
34
- ground_data = pl.DataFrame(
35
- {"flight_number": ["A4543", "K937"], "emissions": [0.02, 0.05]}
36
- )
37
34
 
38
35
  model = pf.Model()
39
36
  model.Fly = pf.Variable(air_data["flight_no"], vtype="binary")
40
37
  model.air_emissions = model.Fly * air_data
41
- model.ground_emissions = ground_data.to_expr()
38
+ model.ground_emissions = pf.Param(
39
+ {"flight_number": ["A4543", "K937"], "emissions": [0.02, 0.05]}
40
+ )
42
41
  -->
43
42
 
44
43
  ```pycon
@@ -90,7 +89,7 @@ What we'd like to do is effectively 'copy' (aka. 'broadcast') `E_max` _over_ eve
90
89
 
91
90
  ```pycon
92
91
  >>> model.E_max.over("flight_no")
93
- <Expression terms=1 type=linear>
92
+ <Expression (linear) terms=1>
94
93
  ┌───────────┬────────────┐
95
94
  │ flight_no ┆ expression │
96
95
  ╞═══════════╪════════════╡
@@ -104,7 +103,7 @@ Notice how applying `.over("flight_no")` added a dimension `flight_no` with valu
104
103
  ```pycon
105
104
  >>> model.emission_constraint = model.E_max.over("flight_no") >= model.flight_emissions
106
105
  >>> model.emission_constraint
107
- <Constraint 'emission_constraint' height=2 terms=6 type=linear>
106
+ <Constraint 'emission_constraint' (linear) height=2 terms=6>
108
107
  ┌───────────┬───────────────────────────────┐
109
108
  │ flight_no ┆ constraint │
110
109
  │ (2) ┆ │
@@ -127,19 +126,16 @@ If one of the two expressions in an addition has extras labels not present in th
127
126
  import pyoframe as pf
128
127
  import polars as pl
129
128
 
130
- air_data = pl.DataFrame(
129
+ model = pf.Model()
130
+ model.air_emissions = pf.Param(
131
131
  {
132
132
  "flight_no": ["A4543", "K937", "D2082", "D8432", "D1206"],
133
133
  "emissions": [1.4, 2.4, 4, 7.6, 4],
134
134
  }
135
135
  )
136
- ground_data = pl.DataFrame(
136
+ model.ground_emissions = pf.Param(
137
137
  {"flight_no": ["A4543", "K937", "B3420"], "emissions": [0.02, 0.05, 0.001]}
138
138
  )
139
-
140
- model = pf.Model()
141
- model.air_emissions = air_data.to_expr()
142
- model.ground_emissions = ground_data.to_expr()
143
139
  -->
144
140
 
145
141
  Consider again [example 1](#example-1-catching-a-mistake) where we added air emissions and ground emissions.
@@ -205,7 +201,7 @@ Option 2 hardly seems reasonable this time considering that air emissions make u
205
201
 
206
202
  ```pycon
207
203
  >>> model.air_emissions.keep_extras() + model.ground_emissions.drop_extras()
208
- <Expression height=5 terms=5 type=constant>
204
+ <Expression (parameter) height=5 terms=5>
209
205
  ┌───────────┬────────────┐
210
206
  │ flight_no ┆ expression │
211
207
  │ (5) ┆ │
@@ -27,6 +27,7 @@ Pyoframe supports a set of [standard attributes](https://metab0t.github.io/PyOpt
27
27
  Every solver has a set of parameters that you can read or set using `model.params.<your-param>`.
28
28
 
29
29
  === "Gurobi"
30
+
30
31
  Refer to the list of [Gurobi parameters](https://docs.gurobi.com/projects/optimizer/en/current/reference/parameters.html).
31
32
 
32
33
  ```python
@@ -36,6 +37,7 @@ Every solver has a set of parameters that you can read or set using `model.param
36
37
  ```
37
38
 
38
39
  === "COPT"
40
+
39
41
  Refer to the list of [COPT parameters](https://guide.coap.online/copt/en-doc/parameter.html).
40
42
 
41
43
  ```python
@@ -45,6 +47,7 @@ Every solver has a set of parameters that you can read or set using `model.param
45
47
  ```
46
48
 
47
49
  === "HiGHS"
50
+
48
51
  Refer to the list of [HiGHS options](https://ergo-code.github.io/HiGHS/stable/options/definitions/).
49
52
 
50
53
  ```python
@@ -54,6 +57,7 @@ Every solver has a set of parameters that you can read or set using `model.param
54
57
  ```
55
58
 
56
59
  === "Ipopt"
60
+
57
61
  Refer to the list of [Ipopt options](https://coin-or.github.io/Ipopt/OPTIONS.html).
58
62
 
59
63
  ```python
@@ -0,0 +1,12 @@
1
+ # Transforms
2
+
3
+ !!! info "Work in progress"
4
+
5
+ This documentation could use some help. [Learn how you can contribute](../../contribute/index.md).
6
+
7
+ Pyoframe has a few special functions that make working with dataframes easy and intuitive. Here they are:
8
+
9
+ ## `sum` and `sum_by`
10
+
11
+ ## `Expression.map()`
12
+
@@ -0,0 +1,5 @@
1
+ nav:
2
+ - installation.md
3
+ - basic-example/example.md
4
+ - basic-example/example-with-dimensions.md
5
+ - basics.md
@@ -6,14 +6,18 @@ import os
6
6
  os.chdir(os.path.join(os.getcwd(), "docs/learn/get-started/basic-example"))
7
7
  -->
8
8
 
9
+ You are going to re-build the [previous example](./example.md) using a dataset, `food_data.csv`, instead of hard-coded values. This way, you can add as many vegetarian proteins as you like without needing to write more code. If you're impatient, [skip to the end](#put-it-all-together) to see the final result.
10
+
9
11
  !!! tip "Pyoframe is built on DataFrames"
10
12
 
11
13
  Most other optimization libraries require you to convert your data from its `DataFrame` format to another format.[^1] Not Pyoframe! DataFrames form the core of Pyoframe making it easy to seamlessly — and efficiently — integrate large datasets into your models.
12
14
 
13
15
  [^1]: For example, Pyomo converts your DataFrames to individual Python objects, Linopy uses multi-dimensional matrices via xarray, and gurobipy requires Python lists, dictionaries and tuples. While gurobipy-pandas uses dataframes, it only works with Gurobi!
14
16
 
15
- You are going to re-build the [previous example](./example.md) using a dataset, `food_data.csv`, instead of hard-coded values. This way, you can add as many vegetarian proteins as you like without needing to write more code. If you're impatient, [skip to the end](#put-it-all-together) to see the final result.
16
17
 
18
+ ## The data
19
+
20
+ You can download the CSV file from [here](https://github.com/Bravos-Power/pyoframe/blob/7af213c52ad33b9c01c9a14baa4cffca1ded1046/docs/learn/get-started/basic-example/food_data.csv) or create it yourself with the following content:
17
21
 
18
22
  > `food_data.csv`
19
23
  >
@@ -22,9 +26,7 @@ You are going to re-build the [previous example](./example.md) using a dataset,
22
26
  > | tofu_block | 18 | 4 |
23
27
  > | chickpea_can | 15 | 3 |
24
28
 
25
-
26
-
27
- ### Step 1: Load the data
29
+ ## Step 1: Load the data
28
30
 
29
31
  Load `food_data.csv` using [Polars](https://pola.rs/) or [Pandas](https://pandas.pydata.org/).
30
32
 
@@ -48,9 +50,9 @@ Load `food_data.csv` using [Polars](https://pola.rs/) or [Pandas](https://pandas
48
50
 
49
51
  Pyoframe works the same whether you're using [Polars](https://pola.rs/) or [Pandas](https://pandas.pydata.org/), two similar libraries for manipulating data with DataFrames. We prefer using Polars because it is much faster (and generally better), but you can use whichever library you're most comfortable with.
50
52
 
51
- Note that, internally, Pyoframe always uses Polars during computations to ensure the best performance. If you're using Pandas, your DataFrames will automatically be converted to Polars prior to computations. If needed, you can convert a Polars DataFrame back to Pandas using [`polars.DataFrame.to_pandas()`](https://docs.pola.rs/api/python/stable/reference/dataframe/api/polars.DataFrame.to_pandas.html#polars.DataFrame.to_pandas).
53
+ Note that, internally, Pyoframe always uses Polars during computations to ensure the best performance. If you're using Pandas, your DataFrames will automatically be converted to Polars prior to computations.
52
54
 
53
- ### Step 2: Create the model
55
+ ## Step 2: Create the model
54
56
 
55
57
  ```python
56
58
  import pyoframe as pf
@@ -60,7 +62,7 @@ m = pf.Model()
60
62
 
61
63
  A [`pyoframe.Model`][pyoframe.Model] instance sets the foundation of your optimization model onto which you can add optimization variables, constraints, and an objective.
62
64
 
63
- ### Step 3: Create a dimensioned variable
65
+ ## Step 3: Create a dimensioned variable
64
66
 
65
67
  Previously, you created two variables: `m.tofu_blocks` and `m.chickpea_cans`. Instead, create a single variable **dimensioned over the column `food`**.
66
68
 
@@ -83,11 +85,7 @@ Printing the variable shows that it contains a `food` dimension with labels `tof
83
85
 
84
86
  ```
85
87
 
86
- !!! tip "Capitalize model variables"
87
-
88
- We suggest capitalizing model variables (i.e. `m.Buy`, not `m.buy`) to make distinguishing what is and isn't a variable easy.
89
-
90
- ### Step 3: Create the objective with `.sum()`
88
+ ## Step 3: Create the objective with `.sum()`
91
89
 
92
90
  Previously you had:
93
91
 
@@ -103,7 +101,7 @@ First, multiply the variable by the protein amount.
103
101
 
104
102
  ```pycon
105
103
  >>> data[["food", "cost"]] * m.Buy
106
- <Expression height=2 terms=2 type=linear>
104
+ <Expression (linear) height=2 terms=2>
107
105
  ┌──────────────┬─────────────────────┐
108
106
  │ food ┆ expression │
109
107
  │ (2) ┆ │
@@ -122,7 +120,7 @@ Second, notice that the `Expression` still has the `food` dimension—it really
122
120
 
123
121
  ```pycon
124
122
  >>> (data[["food", "cost"]] * m.Buy).sum("food")
125
- <Expression terms=2 type=linear>
123
+ <Expression (linear) terms=2>
126
124
  4 Buy[tofu_block] +3 Buy[chickpea_can]
127
125
 
128
126
  ```
@@ -133,7 +131,7 @@ This works and since `food` is the only dimensions you don't even need to specif
133
131
  m.minimize = (data[["food", "cost"]] * m.Buy).sum()
134
132
  ```
135
133
 
136
- ### Step 4: Add the constraint
134
+ ## Step 4: Add the constraint
137
135
 
138
136
  This is similar to how you created the objective, except now you're using `protein` and you turn the `Expression` into a `Constraint` with the `>=` operation.
139
137
 
@@ -146,7 +144,9 @@ m.optimize()
146
144
  assert m.Buy.solution["solution"].to_list() == [2, 1]
147
145
  -->
148
146
 
149
- ### Put it all together
147
+ ## Put it all together
148
+
149
+ If you've followed the steps above your code should look like:
150
150
 
151
151
  <!-- clear-namespace -->
152
152
 
@@ -164,7 +164,7 @@ m.protein_constraint = (data[["food", "protein"]] * m.Buy).sum() >= 50
164
164
  m.optimize()
165
165
  ```
166
166
 
167
- So you should buy:
167
+ And you can retrieve the problem's solution as follows:
168
168
 
169
169
  ```pycon
170
170
  >>> m.Buy.solution
@@ -179,9 +179,6 @@ So you should buy:
179
179
 
180
180
  ```
181
181
 
182
- Notice that since `m.Buy` is dimensioned, `m.Buy.solution` returned a DataFrame with the solution for each of the labels.
183
-
184
- !!! info "Returning Pandas DataFrames"
182
+ Since `m.Buy` is dimensioned, `m.Buy.solution` returned a DataFrame with the solution for each of the labels!
185
183
 
186
- Pyoframe currently always returns Polars DataFrames but you can easily convert them to Pandas using [`.to_pandas()`](https://docs.pola.rs/api/python/stable/reference/dataframe/api/polars.DataFrame.to_pandas.html#polars.DataFrame.to_pandas). In the future, we plan to add support for automatically returning Pandas DataFrames. [Upvote the issue](https://github.com/Bravos-Power/pyoframe/issues/47) if you'd like this feature.
187
184
  <!-- -->
@@ -1,4 +1,4 @@
1
- # Build a simple model
1
+ # Solve a simple problem
2
2
 
3
3
  <!-- invisible-code-block: python
4
4
  import os
@@ -6,13 +6,13 @@ import os
6
6
  os.chdir(os.path.join(os.getcwd(), "docs/learn/get-started/basic-example"))
7
7
  -->
8
8
 
9
- To start, you'll solve a simple optimization problem with Pyoframe.
9
+ To start, you will solve a simple optimization problem with Pyoframe.
10
10
 
11
11
  !!! quote "Problem statement"
12
12
 
13
13
  Imagine you're a vegetarian hesitating between tofu and chickpeas as
14
14
  a source of protein for tomorrow's dinner. You'd like to spend as little money as
15
- possible while still consuming at least 50 grams of protein. How many blocks
15
+ possible while still consuming at least 50g of protein. How many blocks
16
16
  of tofu ($4 each, 18g of protein) and cans of chickpeas ($3 each, 15g of protein) should you buy?
17
17
 
18
18
  Click on the :material-plus-circle: buttons below to understand the code, and then run it on your computer.
@@ -58,4 +58,4 @@ Tofu blocks: 2
58
58
  Chickpea cans: 1
59
59
  ```
60
60
 
61
- On the next page, you'll [integrate DataFrames](./example-with-dimensions.md) into your solution.
61
+ On the [next page](./example-with-dimensions.md), you'll resolve this problem but instead of hard-coded values, you'll use DataFrames, Pyoframe's secret sauce!