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.
- pyoframe-1.1.0/.github/dependabot.yml +11 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/ci.yml +2 -1
- {pyoframe-1.0.1 → pyoframe-1.1.0}/PKG-INFO +5 -5
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/.nav.yml +1 -1
- pyoframe-1.1.0/docs/contribute/index.md +65 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/facility_location.md +4 -4
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/internals.md +8 -3
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/concepts/.nav.yml +0 -1
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/concepts/addition.md +9 -13
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/concepts/solver-access.md +4 -0
- pyoframe-1.1.0/docs/learn/concepts/special-functions.md +12 -0
- pyoframe-1.1.0/docs/learn/get-started/.nav.yml +5 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/example-with-dimensions.md +18 -21
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/example.md +4 -4
- pyoframe-1.1.0/docs/learn/get-started/basics.md +347 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/.nav.yml +0 -1
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/index.md +1 -5
- {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/PKG-INFO +5 -5
- {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/SOURCES.txt +3 -5
- {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/requires.txt +4 -4
- {pyoframe-1.0.1 → pyoframe-1.1.0}/pyproject.toml +4 -4
- {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/__init__.py +2 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_arithmetic.py +3 -3
- {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_constants.py +9 -10
- {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_core.py +84 -57
- {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_model.py +3 -3
- {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_model_element.py +2 -0
- pyoframe-1.1.0/src/pyoframe/_monkey_patch.py +38 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_objective.py +2 -2
- pyoframe-1.1.0/src/pyoframe/_param.py +99 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_utils.py +2 -2
- {pyoframe-1.0.1 → pyoframe-1.1.0}/src/pyoframe/_version.py +3 -3
- pyoframe-1.1.0/tests/examples/cutting_stock_problem/results/problem-highs-machine.lp +183 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/model.py +3 -3
- pyoframe-1.1.0/tests/examples/diet_problem/results/problem-highs-machine.lp +21 -0
- pyoframe-1.1.0/tests/examples/diet_problem/results/solution-highs-machine.sol +69 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/model.py +4 -6
- pyoframe-1.1.0/tests/examples/facility_problem/results/problem-highs-machine.lp +29 -0
- pyoframe-1.1.0/tests/examples/facility_problem/results/solution-highs-machine.sol +50 -0
- pyoframe-1.1.0/tests/examples/portfolio_optim/results/problem-highs-machine.lp +14 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-highs-machine.sol +14 -14
- pyoframe-1.1.0/tests/examples/production_planning/results/problem-highs-machine.lp +9 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-highs-machine.sol +10 -10
- pyoframe-1.1.0/tests/examples/pumped_storage/results/problem-highs-machine.lp +8860 -0
- pyoframe-1.1.0/tests/examples/pumped_storage/results/solution-highs-machine.sol +7317 -0
- pyoframe-1.1.0/tests/examples/sudoku/results/problem-highs-machine.lp +1813 -0
- pyoframe-1.1.0/tests/examples/sudoku/results/solution-highs-machine.sol +1090 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_addition.py +9 -11
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_arithmetic.py +102 -7
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_examples.py +10 -4
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_io.py +1 -1
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_names.py +2 -2
- pyoframe-1.1.0/tests/test_param.py +29 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_variable.py +11 -1
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/util.py +4 -2
- pyoframe-1.0.1/.github/dependabot.yml +0 -16
- pyoframe-1.0.1/docs/contribute/index.md +0 -51
- pyoframe-1.0.1/docs/learn/concepts/building-blocks.md +0 -17
- pyoframe-1.0.1/docs/learn/concepts/special-functions.md +0 -112
- pyoframe-1.0.1/docs/learn/get-started/.nav.yml +0 -4
- pyoframe-1.0.1/docs/reference/external/.nav.yml +0 -4
- pyoframe-1.0.1/docs/reference/external/pandas.DataFrame.to_expr.md +0 -3
- pyoframe-1.0.1/docs/reference/external/pandas.Series.to_expr.md +0 -3
- pyoframe-1.0.1/docs/reference/external/polars.DataFrame.to_expr.md +0 -3
- pyoframe-1.0.1/src/pyoframe/_monkey_patch.py +0 -82
- pyoframe-1.0.1/tests/examples/cutting_stock_problem/results/problem-highs-machine.lp +0 -183
- pyoframe-1.0.1/tests/examples/diet_problem/results/problem-highs-machine.lp +0 -21
- pyoframe-1.0.1/tests/examples/diet_problem/results/solution-highs-machine.sol +0 -69
- pyoframe-1.0.1/tests/examples/facility_problem/results/problem-highs-machine.lp +0 -29
- pyoframe-1.0.1/tests/examples/facility_problem/results/solution-highs-machine.sol +0 -50
- pyoframe-1.0.1/tests/examples/portfolio_optim/results/problem-highs-machine.lp +0 -14
- pyoframe-1.0.1/tests/examples/production_planning/results/problem-highs-machine.lp +0 -9
- pyoframe-1.0.1/tests/examples/pumped_storage/results/problem-highs-machine.lp +0 -8876
- pyoframe-1.0.1/tests/examples/pumped_storage/results/solution-highs-machine.sol +0 -7317
- pyoframe-1.0.1/tests/examples/sudoku/results/problem-highs-machine.lp +0 -1813
- pyoframe-1.0.1/tests/examples/sudoku/results/solution-highs-machine.sol +0 -1090
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.gitattributes +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/CODEOWNERS +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/actions/setup_optimizers_linux/action.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/actions/setup_optimizers_macos/action.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/actions/setup_optimizers_windows/action.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/format.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/lines_changed_counter.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/lint.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/publish_doc.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/publish_doc_dev.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/publish_to_pypi.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.github/workflows/test_doc.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.gitignore +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.pre-commit-config.yaml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.vscode/launch.json +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/.vscode/settings.json +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/CHANGELOG.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/LICENSE +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/README.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/conftest.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/.nav.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/diet.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/index.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/portfolio_optimization.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/examples/production.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/index.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/javascripts/feedback.js +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/.nav.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/datastructure.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/performance.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/quadratics.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/advanced-concepts/troubleshooting.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/food_data.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/foods.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/foods_to_nutrients.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/nutrients.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/results.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/installation.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/power_grid_example.ipynb +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/three-bus.png +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/migrate/v1.0.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/overrides/main.html +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/overrides/partials/actions.html +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/overrides/partials/comments.html +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/overrides/partials/integrations/analytics/custom.html +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/bases/.nav.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/bases/BaseBlock.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/bases/BaseOperableBlock.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/public/.nav.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/public/Config.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/types/.nav.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/reference/types/Operable.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/stylesheets/extra.css +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/data_py.parquet +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/gen_py.parquet +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/index.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/pyoframe-performance.ipynb +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/docs/why-pyoframe/three-bus-four-gen.png +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/giscus.json +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/mkdocs.yml +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/dependency_links.txt +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/pyoframe.egg-info/top_level.txt +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/archive/benchmark_assign_ids_constraints.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/archive/benchmark_assign_ids_constraints_2.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/archive/benchmark_assign_ids_variables.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/archive/benchmark_attr_performance.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/generate_api_reference.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/scripts/griffe_extensions.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/setup.cfg +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/__init__.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/conftest.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/README.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/__init__.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/__init__.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/input_data/orders.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/input_data/parameters.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/model.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/objective.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-copt-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-copt-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-gurobi-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-gurobi-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/cutting_stock_problem/results/problem-highs-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/README.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/__init__.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/input_data/foods.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/input_data/foods_to_nutrients.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/input_data/nutrients.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/model_gurobipy.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/Buy.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/Buy_ub.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/max_nutrients.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/min_nutrients.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/objective.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-copt-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-copt-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-gurobi-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-gurobi-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/problem-highs-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-copt-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-copt-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-gurobi-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-gurobi-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/diet_problem/results/solution-highs-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/__init__.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/results/objective.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/results/problem-gurobi-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_location/results/problem-gurobi-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/__init__.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/input_data/plants.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/input_data/transport_costs.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/input_data/wharehouses.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/model.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/model_gurobipy.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/objective.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/open.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-copt-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-copt-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-gurobi-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-gurobi-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/problem-highs-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-copt-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-copt-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-gurobi-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-gurobi-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/solution-highs-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/facility_problem/results/transport.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/input_data/assets.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/input_data/covariance.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/input_data/portfolio_params.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/model.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/con_min_return.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/con_weights_sum.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/objective.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-copt-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-copt-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-gurobi-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-gurobi-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/problem-highs-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-copt-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-copt-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-gurobi-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-gurobi-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/solution-highs-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/portfolio_optim/results/weight.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/__init__.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/input_data/machines_availability.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/input_data/processing_times.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/input_data/products_profit.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/model.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/objective.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-copt-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-copt-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-gurobi-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-gurobi-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/problem-highs-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-copt-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-copt-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-gurobi-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-gurobi-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution-highs-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/production_planning/results/solution.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/README.md +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/__init__.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/input_data/elspot-prices_2021_hourly_eur.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/model.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/Pump.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/Storage_level.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/Turb.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/objective.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-copt-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-copt-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-gurobi-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-gurobi-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/problem-highs-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-copt-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-copt-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-gurobi-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-gurobi-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/pumped_storage/results/solution-highs-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/__init__.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/input_data/initial_numbers.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/model.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-copt-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-copt-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-gurobi-machine.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-gurobi-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/problem-highs-pretty.lp +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-copt-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-copt-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-gurobi-machine.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-gurobi-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution-highs-pretty.sol +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/examples/sudoku/results/solution.csv +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_constraint.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_model.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_objective.py +0 -0
- {pyoframe-1.0.1 → pyoframe-1.1.0}/tests/test_solver.py +0 -0
|
@@ -55,7 +55,8 @@ jobs:
|
|
|
55
55
|
exit 1
|
|
56
56
|
run:
|
|
57
57
|
if: |
|
|
58
|
-
(github.event_name == '
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
@@ -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 =
|
|
29
|
+
model.customer_position_x = pf.Param(
|
|
30
30
|
{"x": range(G), "x_pos": [step / (G - 1) for step in range(G)]}
|
|
31
|
-
)
|
|
32
|
-
model.customer_position_y =
|
|
31
|
+
)
|
|
32
|
+
model.customer_position_y = pf.Param(
|
|
33
33
|
{"y": range(G), "y_pos": [step / (G - 1) for step in range(G)]}
|
|
34
|
-
)
|
|
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).
|
|
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__`).
|
|
@@ -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 =
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
+
|
{pyoframe-1.0.1 → pyoframe-1.1.0}/docs/learn/get-started/basic-example/example-with-dimensions.md
RENAMED
|
@@ -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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
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
|
|
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
|
|
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
|
|
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!
|