PuLP 0.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.
- pulp-0.1.0/.coin-or/projDesc.xml +63 -0
- pulp-0.1.0/.cursor/rules/project-conventions.mdc +36 -0
- pulp-0.1.0/.cursor/rules/verify-after-changes.mdc +14 -0
- pulp-0.1.0/.github/CONTRIBUTING.md +37 -0
- pulp-0.1.0/.github/FUNDING.yml +1 -0
- pulp-0.1.0/.github/ISSUE_TEMPLATE/Bug_report.md +58 -0
- pulp-0.1.0/.github/ISSUE_TEMPLATE/Feature_request.md +24 -0
- pulp-0.1.0/.github/ISSUE_TEMPLATE/Question.md +21 -0
- pulp-0.1.0/.github/dependabot.yml +8 -0
- pulp-0.1.0/.github/workflows/CI.yml +195 -0
- pulp-0.1.0/.github/workflows/build_docs.yml +49 -0
- pulp-0.1.0/.github/workflows/pythonpackage.yml +56 -0
- pulp-0.1.0/.gitignore +72 -0
- pulp-0.1.0/.pre-commit-config.yaml +10 -0
- pulp-0.1.0/.vscode/tasks.json +18 -0
- pulp-0.1.0/AUTHORS +5 -0
- pulp-0.1.0/Cargo.lock +156 -0
- pulp-0.1.0/Cargo.toml +16 -0
- pulp-0.1.0/HISTORY +184 -0
- pulp-0.1.0/LICENSE +22 -0
- pulp-0.1.0/PKG-INFO +242 -0
- pulp-0.1.0/README.rst +198 -0
- pulp-0.1.0/doc/KPyCon2009/IEEEtran.bst +2369 -0
- pulp-0.1.0/doc/KPyCon2009/PulpForPythonProgrammers.pdf +0 -0
- pulp-0.1.0/doc/KPyCon2009/PulpForPythonProgrammers.tex +343 -0
- pulp-0.1.0/doc/KPyCon2009/arlims.cls +898 -0
- pulp-0.1.0/doc/KPyCon2009/arlimsTPP.cls +898 -0
- pulp-0.1.0/doc/KPyCon2009/arlimsTPPM.cls +898 -0
- pulp-0.1.0/doc/KPyCon2009/arlimsTPPSC.cls +898 -0
- pulp-0.1.0/doc/KPyCon2009/code/beerdistribution.py +81 -0
- pulp-0.1.0/doc/KPyCon2009/code/wedding.py +51 -0
- pulp-0.1.0/doc/KPyCon2009/code/whiskas.py +36 -0
- pulp-0.1.0/doc/KPyCon2009/images/beerdistribution.png +0 -0
- pulp-0.1.0/doc/KPyCon2009/images/whiskas_blend.jpg +0 -0
- pulp-0.1.0/doc/KPyCon2009/images/whiskas_ingredients.jpg +0 -0
- pulp-0.1.0/doc/KPyCon2009/images/whiskas_label.jpg +0 -0
- pulp-0.1.0/doc/KPyCon2009/images/whiskas_nutrition.jpg +0 -0
- pulp-0.1.0/doc/KPyCon2009/references.bib +97 -0
- pulp-0.1.0/doc/KiwiPycon.odp +0 -0
- pulp-0.1.0/doc/KiwiPycon.pdf +0 -0
- pulp-0.1.0/doc/Makefile +25 -0
- pulp-0.1.0/doc/OpenSourceOptimisation.odp +0 -0
- pulp-0.1.0/doc/OpenSourceOptimisation.pdf +0 -0
- pulp-0.1.0/doc/PulpOptimisation.odp +0 -0
- pulp-0.1.0/doc/PulpOptimisation.pdf +0 -0
- pulp-0.1.0/doc/_OptimisationWithPuLP.pdf +0 -0
- pulp-0.1.0/doc/make.bat +35 -0
- pulp-0.1.0/doc/pulp.pdf +0 -0
- pulp-0.1.0/doc/source/AUTHORS.txt +6 -0
- pulp-0.1.0/doc/source/CaseStudies/a_blending_problem.rst +357 -0
- pulp-0.1.0/doc/source/CaseStudies/a_set_partitioning_problem.rst +61 -0
- pulp-0.1.0/doc/source/CaseStudies/a_sudoku_problem.rst +157 -0
- pulp-0.1.0/doc/source/CaseStudies/a_transportation_problem.rst +340 -0
- pulp-0.1.0/doc/source/CaseStudies/a_two_stage_production_planning_problem.rst +90 -0
- pulp-0.1.0/doc/source/CaseStudies/images/brewery_arcs.jpg +0 -0
- pulp-0.1.0/doc/source/CaseStudies/images/brewery_nodes.jpg +0 -0
- pulp-0.1.0/doc/source/CaseStudies/images/extra_demand.jpg +0 -0
- pulp-0.1.0/doc/source/CaseStudies/images/extra_supply.jpg +0 -0
- pulp-0.1.0/doc/source/CaseStudies/images/wedding_seating.jpg +0 -0
- pulp-0.1.0/doc/source/CaseStudies/images/whiskas_blend.jpg +0 -0
- pulp-0.1.0/doc/source/CaseStudies/images/whiskas_label.jpg +0 -0
- pulp-0.1.0/doc/source/CaseStudies/images/wikisudokuproblem.jpg +0 -0
- pulp-0.1.0/doc/source/CaseStudies/images/wikisudokusolution.jpg +0 -0
- pulp-0.1.0/doc/source/CaseStudies/index.rst +14 -0
- pulp-0.1.0/doc/source/_static/freebound.jpg +0 -0
- pulp-0.1.0/doc/source/_static/freebound.pdf +0 -0
- pulp-0.1.0/doc/source/_static/plotter.py +55 -0
- pulp-0.1.0/doc/source/conf.py +227 -0
- pulp-0.1.0/doc/source/develop/add_solver.rst +174 -0
- pulp-0.1.0/doc/source/develop/contribute.rst +127 -0
- pulp-0.1.0/doc/source/develop/index.rst +8 -0
- pulp-0.1.0/doc/source/guides/how_to_configure_solvers.rst +309 -0
- pulp-0.1.0/doc/source/guides/how_to_debug.rst +87 -0
- pulp-0.1.0/doc/source/guides/how_to_export_models.rst +251 -0
- pulp-0.1.0/doc/source/guides/how_to_mip_start.rst +75 -0
- pulp-0.1.0/doc/source/guides/index.rst +12 -0
- pulp-0.1.0/doc/source/index.rst +56 -0
- pulp-0.1.0/doc/source/main/amply.rst +4 -0
- pulp-0.1.0/doc/source/main/basic_python_coding.rst +395 -0
- pulp-0.1.0/doc/source/main/images/bandb.jpg +0 -0
- pulp-0.1.0/doc/source/main/images/modeling_process.jpg +0 -0
- pulp-0.1.0/doc/source/main/images/or_methodology.jpg +0 -0
- pulp-0.1.0/doc/source/main/images/sensitivity_excel.jpg +0 -0
- pulp-0.1.0/doc/source/main/includeme.rst +1 -0
- pulp-0.1.0/doc/source/main/index.rst +13 -0
- pulp-0.1.0/doc/source/main/installing_pulp_at_home.rst +71 -0
- pulp-0.1.0/doc/source/main/optimisation_concepts.rst +44 -0
- pulp-0.1.0/doc/source/main/the_optimisation_process.rst +116 -0
- pulp-0.1.0/doc/source/plugins/amply.rst +13 -0
- pulp-0.1.0/doc/source/plugins/index.rst +11 -0
- pulp-0.1.0/doc/source/plugins/lparray.rst +26 -0
- pulp-0.1.0/doc/source/plugins/orloge.rst +45 -0
- pulp-0.1.0/doc/source/plugins/pytups.rst +9 -0
- pulp-0.1.0/doc/source/technical/build.rst +29 -0
- pulp-0.1.0/doc/source/technical/constants.rst +119 -0
- pulp-0.1.0/doc/source/technical/index.rst +12 -0
- pulp-0.1.0/doc/source/technical/pulp.rst +100 -0
- pulp-0.1.0/doc/source/technical/solvers.rst +12 -0
- pulp-0.1.0/examples/AmericanSteelProblem.py +108 -0
- pulp-0.1.0/examples/BeerDistributionProblem.py +81 -0
- pulp-0.1.0/examples/BeerDistributionProblemCompetitorExtension.py +80 -0
- pulp-0.1.0/examples/BeerDistributionProblemWarehouseExtension.py +73 -0
- pulp-0.1.0/examples/BeerDistributionProblem_resolve.py +89 -0
- pulp-0.1.0/examples/CG.py +154 -0
- pulp-0.1.0/examples/ComputerPlantProblem.py +95 -0
- pulp-0.1.0/examples/SpongeRollProblem1.py +58 -0
- pulp-0.1.0/examples/SpongeRollProblem2.py +81 -0
- pulp-0.1.0/examples/SpongeRollProblem3.py +156 -0
- pulp-0.1.0/examples/SpongeRollProblem4.py +150 -0
- pulp-0.1.0/examples/SpongeRollProblem5.py +45 -0
- pulp-0.1.0/examples/Sudoku1.py +109 -0
- pulp-0.1.0/examples/Sudoku2.py +127 -0
- pulp-0.1.0/examples/Two_stage_Stochastic_GemstoneTools.py +114 -0
- pulp-0.1.0/examples/WhiskasModel1.py +64 -0
- pulp-0.1.0/examples/WhiskasModel2.py +121 -0
- pulp-0.1.0/examples/__init__.py +0 -0
- pulp-0.1.0/examples/furniture.py +33 -0
- pulp-0.1.0/examples/test1.py +52 -0
- pulp-0.1.0/examples/test2.py +58 -0
- pulp-0.1.0/examples/test3.py +132 -0
- pulp-0.1.0/examples/test4.py +60 -0
- pulp-0.1.0/examples/test5.py +53 -0
- pulp-0.1.0/examples/test7.py +33 -0
- pulp-0.1.0/examples/wedding.py +70 -0
- pulp-0.1.0/examples/wedding_initial.py +78 -0
- pulp-0.1.0/pulp/__init__.py +62 -0
- pulp-0.1.0/pulp/_rustcore.pyi +150 -0
- pulp-0.1.0/pulp/apis/__init__.py +168 -0
- pulp-0.1.0/pulp/apis/choco_api.py +159 -0
- pulp-0.1.0/pulp/apis/coin_api.py +1048 -0
- pulp-0.1.0/pulp/apis/copt_api.py +1074 -0
- pulp-0.1.0/pulp/apis/core.py +427 -0
- pulp-0.1.0/pulp/apis/cplex_api.py +639 -0
- pulp-0.1.0/pulp/apis/cuopt_api.py +260 -0
- pulp-0.1.0/pulp/apis/glpk_api.py +456 -0
- pulp-0.1.0/pulp/apis/gurobi_api.py +574 -0
- pulp-0.1.0/pulp/apis/highs_api.py +530 -0
- pulp-0.1.0/pulp/apis/mipcl_api.py +155 -0
- pulp-0.1.0/pulp/apis/mosek_api.py +337 -0
- pulp-0.1.0/pulp/apis/sas_api.py +747 -0
- pulp-0.1.0/pulp/apis/scip_api.py +718 -0
- pulp-0.1.0/pulp/apis/xpress_api.py +814 -0
- pulp-0.1.0/pulp/constants.py +96 -0
- pulp-0.1.0/pulp/mps_lp.py +256 -0
- pulp-0.1.0/pulp/pulp.py +2169 -0
- pulp-0.1.0/pulp/py.typed +0 -0
- pulp-0.1.0/pulp/solverdir/CoinMP.dll +0 -0
- pulp-0.1.0/pulp/solverdir/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/arm64/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/arm64/cbc +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/arm64/coin-license.txt +239 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/i32/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/i32/cbc +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/i32/coin-license.txt +239 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/i64/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/i64/cbc +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/linux/i64/coin-license.txt +239 -0
- pulp-0.1.0/pulp/solverdir/cbc/osx/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/osx/i64/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/osx/i64/cbc +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/osx/i64/coin-license.txt +239 -0
- pulp-0.1.0/pulp/solverdir/cbc/win/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/win/i32/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/win/i32/cbc.exe +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/win/i32/coin-license.txt +239 -0
- pulp-0.1.0/pulp/solverdir/cbc/win/i64/__init__.py +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/win/i64/cbc.exe +0 -0
- pulp-0.1.0/pulp/solverdir/cbc/win/i64/coin-license.txt +239 -0
- pulp-0.1.0/pulp/sparse.py +96 -0
- pulp-0.1.0/pulp/tests/__init__.py +3 -0
- pulp-0.1.0/pulp/tests/bin_packing_problem.py +53 -0
- pulp-0.1.0/pulp/tests/run_tests.py +33 -0
- pulp-0.1.0/pulp/tests/test_examples.py +40 -0
- pulp-0.1.0/pulp/tests/test_gurobipy_env.py +145 -0
- pulp-0.1.0/pulp/tests/test_lpdot.py +24 -0
- pulp-0.1.0/pulp/tests/test_pulp.py +2627 -0
- pulp-0.1.0/pulp/tests/test_rust_core.py +26 -0
- pulp-0.1.0/pulp/tests/test_sparse.py +55 -0
- pulp-0.1.0/pulp/utilities.py +198 -0
- pulp-0.1.0/pyproject.toml +140 -0
- pulp-0.1.0/src/affine_expr.rs +457 -0
- pulp-0.1.0/src/constraint.rs +205 -0
- pulp-0.1.0/src/format.rs +354 -0
- pulp-0.1.0/src/io.rs +1090 -0
- pulp-0.1.0/src/lib.rs +41 -0
- pulp-0.1.0/src/model.rs +420 -0
- pulp-0.1.0/src/types.rs +231 -0
- pulp-0.1.0/src/variable.rs +263 -0
- pulp-0.1.0/uv.lock +1608 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<?xml-stylesheet type = "text/xsl" href = "http://www.coin-or.org/projects/autoGen.xsl"?>
|
|
3
|
+
<projectData xmlns="coin-or.org" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="coin-or.org http://www.coin-or.org/projects/autoGen.xsd">
|
|
4
|
+
<projectBasics>
|
|
5
|
+
<projectName>PuLP</projectName>
|
|
6
|
+
<projectDescription>
|
|
7
|
+
PuLP is an LP modeler written in python. PuLP can generate
|
|
8
|
+
MPS or LP files and call GLPK, COIN CLP/CBC, CPLEX, GUROBI
|
|
9
|
+
to solve linear problems.
|
|
10
|
+
</projectDescription>
|
|
11
|
+
<projectShortDescription>A Python library for modeling linear and integer programs.</projectShortDescription>
|
|
12
|
+
<projectManager>Stuart Mitchell </projectManager>
|
|
13
|
+
<projectHomePage>https://github.com/coin-or/Pulp</projectHomePage>
|
|
14
|
+
<projectLicense>MIT License</projectLicense>
|
|
15
|
+
<projectLicenseURL>http://www.opensource.org/licenses/mit-license.php</projectLicenseURL>
|
|
16
|
+
<coinLinkedProjects/>
|
|
17
|
+
<otherLinkedPackages>
|
|
18
|
+
<otherPackage>
|
|
19
|
+
<packageName>GLPK</packageName>
|
|
20
|
+
<packageURL>http://www.gnu.org/software/glpk/</packageURL>
|
|
21
|
+
<requiredOrOptional>Optional</requiredOrOptional>
|
|
22
|
+
</otherPackage>
|
|
23
|
+
</otherLinkedPackages>
|
|
24
|
+
<projectLanguage>python</projectLanguage>
|
|
25
|
+
<developmentStatus>
|
|
26
|
+
<activityStatus>Active</activityStatus>
|
|
27
|
+
<maturityLevel>3</maturityLevel>
|
|
28
|
+
</developmentStatus>
|
|
29
|
+
<testedPlatforms>
|
|
30
|
+
<platform>
|
|
31
|
+
<operatingSystem>Microsoft Windows</operatingSystem>
|
|
32
|
+
<compiler>python 2.5</compiler>
|
|
33
|
+
</platform>
|
|
34
|
+
<platform>
|
|
35
|
+
<operatingSystem>Microsoft Windows</operatingSystem>
|
|
36
|
+
<compiler>python 2.4</compiler>
|
|
37
|
+
</platform>
|
|
38
|
+
<platform>
|
|
39
|
+
<operatingSystem>Linux</operatingSystem>
|
|
40
|
+
<compiler>python 2.6</compiler>
|
|
41
|
+
</platform>
|
|
42
|
+
<platform>
|
|
43
|
+
<operatingSystem>Linux</operatingSystem>
|
|
44
|
+
<compiler>python 2.5</compiler>
|
|
45
|
+
</platform>
|
|
46
|
+
<platform>
|
|
47
|
+
<operatingSystem>Linux</operatingSystem>
|
|
48
|
+
<compiler>python 2.4</compiler>
|
|
49
|
+
</platform>
|
|
50
|
+
</testedPlatforms>
|
|
51
|
+
<projectCategories>
|
|
52
|
+
<category>Modeling systems</category>
|
|
53
|
+
<category>Optimization deterministic linear continuous</category>
|
|
54
|
+
<category>Optimization deterministic linear discrete</category>
|
|
55
|
+
</projectCategories>
|
|
56
|
+
</projectBasics>
|
|
57
|
+
<leftMenuLinks>
|
|
58
|
+
<documentation>https://coin-or.github.io/pulp/</documentation>
|
|
59
|
+
<sourceCodeDownload>https://github.com/coin-or/pulp</sourceCodeDownload>
|
|
60
|
+
<binaryDownload/>
|
|
61
|
+
<mailingList>https://github.com/coin-or/pulp/discussions</mailingList>
|
|
62
|
+
</leftMenuLinks>
|
|
63
|
+
</projectData>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Core project conventions for PuLP development
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Project Conventions
|
|
7
|
+
|
|
8
|
+
## Testing
|
|
9
|
+
|
|
10
|
+
- Use `unittest` (not pytest) for writing and running unit tests.
|
|
11
|
+
- Run tests via: `uv run python -m unittest discover -s pulp/tests`
|
|
12
|
+
|
|
13
|
+
## Package Manager
|
|
14
|
+
|
|
15
|
+
- Always use `uv` for dependency management, package installation, and running tools.
|
|
16
|
+
- Do **not** manually activate the virtual environment; `uv run` handles it automatically.
|
|
17
|
+
- Install packages: `uv pip install <package>`
|
|
18
|
+
- Sync dependencies: `uv sync`
|
|
19
|
+
- Build the project: `uv run maturin develop`
|
|
20
|
+
|
|
21
|
+
## Linting and formatting
|
|
22
|
+
|
|
23
|
+
- Use **ruff** for linting and formatting (not black).
|
|
24
|
+
- Run: `uv run ruff check pulp` and `uv run ruff format pulp` (or `ruff format pulp --check` to only check).
|
|
25
|
+
|
|
26
|
+
## Type checking
|
|
27
|
+
|
|
28
|
+
- Use **ty** for type checking (not mypy or pyright).
|
|
29
|
+
- Run type checks via: `uv run ty check pulp`
|
|
30
|
+
|
|
31
|
+
## Rust / Cargo
|
|
32
|
+
|
|
33
|
+
- Always run Cargo through **uv** (do not invoke `cargo` directly).
|
|
34
|
+
- Check Rust code: `uv run cargo check`
|
|
35
|
+
- Build: `uv run cargo build`
|
|
36
|
+
- Other subcommands: `uv run cargo <subcommand>`
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Run unit tests, ty, and ruff checks after every code change
|
|
3
|
+
alwaysApply: true
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Verify After Every Change
|
|
7
|
+
|
|
8
|
+
After making any code change to the repo, run all three checks before considering the task done:
|
|
9
|
+
|
|
10
|
+
1. **Unit tests**: `uv run python -m unittest discover -s pulp/tests`
|
|
11
|
+
2. **Type checking**: `uv run ty check pulp`
|
|
12
|
+
3. **Linting and formatting**: `uv run ruff check pulp` and `uv run ruff format pulp --check`
|
|
13
|
+
|
|
14
|
+
If any check fails, fix the issues before proceeding. If Rust source files (`src/`) were modified, run `uv run cargo check` and rebuild with `uv run maturin develop`.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
When contributing to this repository, please first discuss the change you wish to make with the owners of this repository by creating an issue before making a change.
|
|
4
|
+
|
|
5
|
+
## Contributor License Agreement
|
|
6
|
+
|
|
7
|
+
This project belongs to the [COIN-OR](coinor) community and thus follows its guidelines, listed [here](coinor_guidelines).
|
|
8
|
+
In order to sign the contribution agreement, we use [cla-assistant](_cla_assistant). When a new PR is created, a link will appear that asks the submitter to sign it virtually, in case the github user has not done so already. The only requisite is to have a github account. The link to pulp's CLA is [here](cla).
|
|
9
|
+
|
|
10
|
+
## Pull Request Process
|
|
11
|
+
|
|
12
|
+
1. Create a Fork of the project to your own repository.
|
|
13
|
+
1. Create a Branch in your Fork.
|
|
14
|
+
3. Do the changes in your Branch.
|
|
15
|
+
3. Add a Test that checks the change you did. This is done by adding a test function to the test file: `pulp/tests/test_pulp.py` (the function needs to start with `test_`).
|
|
16
|
+
4. If you have added a new solver API, please provide instructions on how to obtain the solver and, in case it's a commercial solver, also how to get a test or academic license to test the API ourselves.
|
|
17
|
+
5. Create some bigger problems in a separate file where you can time the solution process to see if you are making changes that are more efficient, also use CProfile can help.
|
|
18
|
+
6. Create a Pull Request (PR) when you're done so we can review it.
|
|
19
|
+
6. In case your contribution consists on new functionality, an update on the docs would also be appropriate.
|
|
20
|
+
7. You will be kindly asked to sign a Contributor License Agreement by a COIN-OR sponsored bot before merging your changes.
|
|
21
|
+
|
|
22
|
+
## Want to contribute but do not know where to start?
|
|
23
|
+
|
|
24
|
+
Check the [Roadmap][roadmap] for the project to see what you can help with. We're always looking for more examples and better documentation. Or check the issues that have the "help wanted" or "bug" tag.
|
|
25
|
+
|
|
26
|
+
### Attribution
|
|
27
|
+
|
|
28
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
|
29
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
|
30
|
+
|
|
31
|
+
[homepage]: http://contributor-covenant.org
|
|
32
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
|
33
|
+
[roadmap]: https://github.com/coin-or/pulp/projects/1
|
|
34
|
+
[coinor]: https://www.coin-or.org/
|
|
35
|
+
[coinor_guidelines]: https://www.coin-or.org/contributing/code/
|
|
36
|
+
[cla]: https://cla-assistant.io/coin-or/pulp
|
|
37
|
+
[_cla_assistant]: https://github.com/cla-assistant/cla-assistant
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
github: pchtsp
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug Report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
title: ''
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<!--
|
|
11
|
+
Thanks for coming here to report a bug. :)
|
|
12
|
+
|
|
13
|
+
Please describe it in the sections below, fill out the correct check boxes with an "x", replacing the space inside [ ], then click the "Submit new issue" button at the bottom
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
Details for the issue
|
|
17
|
+
--------------------
|
|
18
|
+
|
|
19
|
+
#### What did you do?
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
#### What did you expect to see?
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
#### What did you see instead?
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Useful extra information
|
|
29
|
+
-------------------------
|
|
30
|
+
|
|
31
|
+
The info below often helps, please fill it out if you're able to. :)
|
|
32
|
+
|
|
33
|
+
#### What operating system are you using?
|
|
34
|
+
|
|
35
|
+
- [ ] Windows: ( _version:_ ___ )
|
|
36
|
+
- [ ] Linux: ( _distro:_ ___ )
|
|
37
|
+
- [ ] Mac OS: ( _version:_ ___ )
|
|
38
|
+
- [ ] Other: ___
|
|
39
|
+
|
|
40
|
+
#### I'm using python version:
|
|
41
|
+
|
|
42
|
+
- [ ] 3.7
|
|
43
|
+
- [ ] 3.8
|
|
44
|
+
- [ ] 3.9
|
|
45
|
+
- [ ] 3.10
|
|
46
|
+
- [ ] 3.11
|
|
47
|
+
- [ ] Other: ___
|
|
48
|
+
|
|
49
|
+
#### I installed PuLP via:
|
|
50
|
+
|
|
51
|
+
- [ ] pypi (python -m pip install pulp)
|
|
52
|
+
- [ ] github (python -m pip install -U git+https://github.com/coin-or/pulp)
|
|
53
|
+
- [ ] Other: ___ (conda?)
|
|
54
|
+
|
|
55
|
+
#### Did you also
|
|
56
|
+
|
|
57
|
+
- [ ] Tried out the latest github version: https://github.com/coin-or/pulp
|
|
58
|
+
- [ ] Searched for an existing similar issue: https://github.com/coin-or/pulp/issues?utf8=%E2%9C%93&q=is%3Aissue%20
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature Request
|
|
3
|
+
about: Suggest an idea or request a new feature
|
|
4
|
+
title: ''
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<!-- Thanks for coming here to suggest a new feature. :) -->
|
|
11
|
+
|
|
12
|
+
Describe the new feature
|
|
13
|
+
--------------------------
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
Additional info
|
|
17
|
+
---------------
|
|
18
|
+
Please answer these questions before submitting your feature request.
|
|
19
|
+
|
|
20
|
+
#### Is your feature request related to an issue? Please include the issue number.
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
#### Does this feature exist in another product or project? Please provide a link.
|
|
24
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Question / help
|
|
3
|
+
about: Ask a question related to this project or get support
|
|
4
|
+
title: ''
|
|
5
|
+
labels: ''
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<!--
|
|
11
|
+
Thanks for coming here to ask a question. :)
|
|
12
|
+
|
|
13
|
+
Before asking your question, please make sure you have:
|
|
14
|
+
|
|
15
|
+
1. Visited the discussions page (https://github.com/coin-or/pulp/discussions). This is the official way of asking for help.
|
|
16
|
+
2. Visited the pulp's google group archive (https://groups.google.com/forum/#!forum/pulp-or-discuss).
|
|
17
|
+
|
|
18
|
+
-->
|
|
19
|
+
|
|
20
|
+
What is your question
|
|
21
|
+
-----------------------
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Build wheels with maturin and publish to PyPI on tag push.
|
|
2
|
+
# Generated from maturin generate-ci github, merged with Test PyPI + PyPI publish.
|
|
3
|
+
# To refresh the build matrix, run: maturin generate-ci github
|
|
4
|
+
name: CI
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
- master
|
|
11
|
+
tags:
|
|
12
|
+
- '*'
|
|
13
|
+
pull_request:
|
|
14
|
+
workflow_dispatch:
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
linux:
|
|
21
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
22
|
+
strategy:
|
|
23
|
+
matrix:
|
|
24
|
+
platform:
|
|
25
|
+
- runner: ubuntu-22.04
|
|
26
|
+
target: x86_64
|
|
27
|
+
- runner: ubuntu-22.04
|
|
28
|
+
target: x86
|
|
29
|
+
- runner: ubuntu-22.04
|
|
30
|
+
target: aarch64
|
|
31
|
+
- runner: ubuntu-22.04
|
|
32
|
+
target: armv7
|
|
33
|
+
- runner: ubuntu-22.04
|
|
34
|
+
target: s390x
|
|
35
|
+
- runner: ubuntu-22.04
|
|
36
|
+
target: ppc64le
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@v6
|
|
39
|
+
- uses: actions/setup-python@v6
|
|
40
|
+
with:
|
|
41
|
+
python-version: 3.x
|
|
42
|
+
- name: Build wheels
|
|
43
|
+
uses: PyO3/maturin-action@v1
|
|
44
|
+
with:
|
|
45
|
+
target: ${{ matrix.platform.target }}
|
|
46
|
+
args: --release --out dist --find-interpreter
|
|
47
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
48
|
+
manylinux: auto
|
|
49
|
+
- name: Upload wheels
|
|
50
|
+
uses: actions/upload-artifact@v6
|
|
51
|
+
with:
|
|
52
|
+
name: wheels-linux-${{ matrix.platform.target }}
|
|
53
|
+
path: dist
|
|
54
|
+
|
|
55
|
+
musllinux:
|
|
56
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
57
|
+
strategy:
|
|
58
|
+
matrix:
|
|
59
|
+
platform:
|
|
60
|
+
- runner: ubuntu-22.04
|
|
61
|
+
target: x86_64
|
|
62
|
+
- runner: ubuntu-22.04
|
|
63
|
+
target: x86
|
|
64
|
+
- runner: ubuntu-22.04
|
|
65
|
+
target: aarch64
|
|
66
|
+
- runner: ubuntu-22.04
|
|
67
|
+
target: armv7
|
|
68
|
+
steps:
|
|
69
|
+
- uses: actions/checkout@v6
|
|
70
|
+
- uses: actions/setup-python@v6
|
|
71
|
+
with:
|
|
72
|
+
python-version: 3.x
|
|
73
|
+
- name: Build wheels
|
|
74
|
+
uses: PyO3/maturin-action@v1
|
|
75
|
+
with:
|
|
76
|
+
target: ${{ matrix.platform.target }}
|
|
77
|
+
args: --release --out dist --find-interpreter
|
|
78
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
79
|
+
manylinux: musllinux_1_2
|
|
80
|
+
- name: Upload wheels
|
|
81
|
+
uses: actions/upload-artifact@v6
|
|
82
|
+
with:
|
|
83
|
+
name: wheels-musllinux-${{ matrix.platform.target }}
|
|
84
|
+
path: dist
|
|
85
|
+
|
|
86
|
+
windows:
|
|
87
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
88
|
+
strategy:
|
|
89
|
+
matrix:
|
|
90
|
+
platform:
|
|
91
|
+
- runner: windows-latest
|
|
92
|
+
target: x64
|
|
93
|
+
python_arch: x64
|
|
94
|
+
- runner: windows-latest
|
|
95
|
+
target: x86
|
|
96
|
+
python_arch: x86
|
|
97
|
+
- runner: windows-11-arm
|
|
98
|
+
target: aarch64
|
|
99
|
+
python_arch: arm64
|
|
100
|
+
steps:
|
|
101
|
+
- uses: actions/checkout@v6
|
|
102
|
+
- uses: actions/setup-python@v6
|
|
103
|
+
with:
|
|
104
|
+
python-version: 3.13
|
|
105
|
+
architecture: ${{ matrix.platform.python_arch }}
|
|
106
|
+
- name: Build wheels
|
|
107
|
+
uses: PyO3/maturin-action@v1
|
|
108
|
+
with:
|
|
109
|
+
target: ${{ matrix.platform.target }}
|
|
110
|
+
args: --release --out dist --find-interpreter
|
|
111
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
112
|
+
- name: Upload wheels
|
|
113
|
+
uses: actions/upload-artifact@v6
|
|
114
|
+
with:
|
|
115
|
+
name: wheels-windows-${{ matrix.platform.target }}
|
|
116
|
+
path: dist
|
|
117
|
+
|
|
118
|
+
macos:
|
|
119
|
+
runs-on: ${{ matrix.platform.runner }}
|
|
120
|
+
strategy:
|
|
121
|
+
matrix:
|
|
122
|
+
platform:
|
|
123
|
+
- runner: macos-15-intel
|
|
124
|
+
target: x86_64
|
|
125
|
+
- runner: macos-latest
|
|
126
|
+
target: aarch64
|
|
127
|
+
steps:
|
|
128
|
+
- uses: actions/checkout@v6
|
|
129
|
+
- uses: actions/setup-python@v6
|
|
130
|
+
with:
|
|
131
|
+
python-version: 3.x
|
|
132
|
+
- name: Build wheels
|
|
133
|
+
uses: PyO3/maturin-action@v1
|
|
134
|
+
with:
|
|
135
|
+
target: ${{ matrix.platform.target }}
|
|
136
|
+
args: --release --out dist --find-interpreter
|
|
137
|
+
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
|
|
138
|
+
- name: Upload wheels
|
|
139
|
+
uses: actions/upload-artifact@v6
|
|
140
|
+
with:
|
|
141
|
+
name: wheels-macos-${{ matrix.platform.target }}
|
|
142
|
+
path: dist
|
|
143
|
+
|
|
144
|
+
sdist:
|
|
145
|
+
runs-on: ubuntu-latest
|
|
146
|
+
steps:
|
|
147
|
+
- uses: actions/checkout@v6
|
|
148
|
+
- name: Build sdist
|
|
149
|
+
uses: PyO3/maturin-action@v1
|
|
150
|
+
with:
|
|
151
|
+
command: sdist
|
|
152
|
+
args: --out dist
|
|
153
|
+
- name: Upload sdist
|
|
154
|
+
uses: actions/upload-artifact@v6
|
|
155
|
+
with:
|
|
156
|
+
name: wheels-sdist
|
|
157
|
+
path: dist
|
|
158
|
+
|
|
159
|
+
release:
|
|
160
|
+
name: Publish to PyPI
|
|
161
|
+
runs-on: ubuntu-latest
|
|
162
|
+
if: startsWith(github.ref, 'refs/tags/') || github.event_name == 'workflow_dispatch'
|
|
163
|
+
needs: [linux, musllinux, windows, macos, sdist]
|
|
164
|
+
permissions:
|
|
165
|
+
contents: read
|
|
166
|
+
steps:
|
|
167
|
+
- name: Download all artifacts
|
|
168
|
+
uses: actions/download-artifact@v4
|
|
169
|
+
with:
|
|
170
|
+
pattern: wheels-*
|
|
171
|
+
merge-multiple: true
|
|
172
|
+
- name: Prepare dist directory
|
|
173
|
+
run: |
|
|
174
|
+
mkdir -p dist_all
|
|
175
|
+
if ls wheels-*/ 1>/dev/null 2>&1; then
|
|
176
|
+
for d in wheels-*/; do cp -a "$d"/* dist_all/ 2>/dev/null || true; done
|
|
177
|
+
else
|
|
178
|
+
cp -a *.whl *.tar.gz dist_all/ 2>/dev/null || true
|
|
179
|
+
fi
|
|
180
|
+
ls -la dist_all
|
|
181
|
+
- name: Publish to Test PyPI
|
|
182
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
183
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
184
|
+
with:
|
|
185
|
+
password: ${{ secrets.test_pypi_password }}
|
|
186
|
+
repository-url: https://test.pypi.org/legacy/
|
|
187
|
+
skip-existing: true
|
|
188
|
+
packages-dir: dist_all
|
|
189
|
+
- name: Publish to PyPI
|
|
190
|
+
if: startsWith(github.ref, 'refs/tags/')
|
|
191
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
192
|
+
with:
|
|
193
|
+
password: ${{ secrets.pypi_password }}
|
|
194
|
+
skip-existing: true
|
|
195
|
+
packages-dir: dist_all
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
name: docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v5
|
|
13
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
14
|
+
uses: actions/setup-python@v6
|
|
15
|
+
with:
|
|
16
|
+
python-version: ${{ matrix.python-version }}
|
|
17
|
+
- name: Install uv and set the python version
|
|
18
|
+
uses: astral-sh/setup-uv@v7
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ matrix.python-version }}
|
|
21
|
+
- name: Install Rust
|
|
22
|
+
uses: dtolnay/rust-toolchain@stable
|
|
23
|
+
- name: Install dependencies
|
|
24
|
+
run: uv sync --dev --all-extras
|
|
25
|
+
- name: Building docs
|
|
26
|
+
run: cd doc && uv run make html && cd ..
|
|
27
|
+
# Great extra actions to compose with:
|
|
28
|
+
# Publish built docs to gh-pages branch.
|
|
29
|
+
# ===============================
|
|
30
|
+
- name: Commit documentation changes
|
|
31
|
+
run: |
|
|
32
|
+
git clone https://github.com/coin-or/pulp.git --branch gh-pages --single-branch gh-pages
|
|
33
|
+
rm -rf gh-pages/*
|
|
34
|
+
cp -r doc/build/html/* gh-pages/
|
|
35
|
+
cd gh-pages
|
|
36
|
+
touch .nojekyll
|
|
37
|
+
git config --local user.email "action@github.com"
|
|
38
|
+
git config --local user.name "GitHub Action"
|
|
39
|
+
git add .
|
|
40
|
+
git commit -m "Update documentation" -a || true
|
|
41
|
+
# The above command will fail if no changes were present, so we ignore
|
|
42
|
+
# that.
|
|
43
|
+
- name: Push changes
|
|
44
|
+
uses: ad-m/github-push-action@master
|
|
45
|
+
with:
|
|
46
|
+
branch: gh-pages
|
|
47
|
+
directory: gh-pages
|
|
48
|
+
github_token: ${{ secrets.GH_TOKEN }}
|
|
49
|
+
# ===============================
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: Python package
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request, workflow_dispatch]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ${{ matrix.os }}
|
|
8
|
+
strategy:
|
|
9
|
+
max-parallel: 21
|
|
10
|
+
matrix:
|
|
11
|
+
python-version: ['3.9', '3.10', '3.11', '3.12']
|
|
12
|
+
os: [ubuntu-latest, macOS-latest, windows-latest]
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v5
|
|
16
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
17
|
+
uses: actions/setup-python@v6
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
- name: Install uv and set the python version
|
|
21
|
+
uses: astral-sh/setup-uv@v7
|
|
22
|
+
with:
|
|
23
|
+
python-version: ${{ matrix.python-version }}
|
|
24
|
+
- name: Install Rust
|
|
25
|
+
uses: dtolnay/rust-toolchain@stable
|
|
26
|
+
- name: Lint and format
|
|
27
|
+
run: uv run ruff check pulp && uv run ruff format pulp --check
|
|
28
|
+
- name: Type Check
|
|
29
|
+
run: uv run ty check pulp
|
|
30
|
+
- name: install ubuntu-only solvers
|
|
31
|
+
if: matrix.os == 'ubuntu-latest'
|
|
32
|
+
run: |
|
|
33
|
+
sudo apt update -qq
|
|
34
|
+
sudo apt install -qq glpk-utils
|
|
35
|
+
- name: Install highspy cmd
|
|
36
|
+
if: matrix.os == 'ubuntu-latest'
|
|
37
|
+
uses: supplypike/setup-bin@v5
|
|
38
|
+
with:
|
|
39
|
+
uri: 'https://github.com/JuliaBinaryWrappers/HiGHSstatic_jll.jl/releases/download/HiGHSstatic-v1.7.1%2B0/HiGHSstatic.v1.7.1.x86_64-linux-gnu-cxx11.tar.gz'
|
|
40
|
+
subPath: 'bin'
|
|
41
|
+
name: 'highs'
|
|
42
|
+
version: '1.7.1'
|
|
43
|
+
- name: Install SCIP_CMD
|
|
44
|
+
if: matrix.os == 'ubuntu-latest'
|
|
45
|
+
uses: supplypike/setup-bin@v5
|
|
46
|
+
with:
|
|
47
|
+
uri: 'https://www.scipopt.org/download/release/SCIPOptSuite-9.2.1-Linux-ubuntu24.deb'
|
|
48
|
+
name: 'SCIPOptSuite-9.2.1-Linux-ubuntu24.deb'
|
|
49
|
+
version: '9.2.1'
|
|
50
|
+
command: "sudo apt install -qq ./SCIPOptSuite-9.2.1-Linux-ubuntu24.deb"
|
|
51
|
+
- name: Install package
|
|
52
|
+
run: uv pip install -e .
|
|
53
|
+
- name: Test with pulptest
|
|
54
|
+
env:
|
|
55
|
+
PYTHONPATH: .
|
|
56
|
+
run: uv run --all-extras --no-extra mosek pulp/tests/run_tests.py
|
pulp-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
|
|
5
|
+
# C extensions
|
|
6
|
+
*.so
|
|
7
|
+
|
|
8
|
+
# Distribution / packaging
|
|
9
|
+
.Python
|
|
10
|
+
env/
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
*.egg-info/
|
|
23
|
+
.installed.cfg
|
|
24
|
+
*.egg
|
|
25
|
+
|
|
26
|
+
# PyInstaller
|
|
27
|
+
# Usually these files are written by a python script from a template
|
|
28
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
29
|
+
*.manifest
|
|
30
|
+
*.spec
|
|
31
|
+
|
|
32
|
+
# Installer logs
|
|
33
|
+
pip-log.txt
|
|
34
|
+
pip-delete-this-directory.txt
|
|
35
|
+
|
|
36
|
+
# Unit test / coverage reports
|
|
37
|
+
htmlcov/
|
|
38
|
+
.tox/
|
|
39
|
+
.coverage
|
|
40
|
+
.coverage.*
|
|
41
|
+
.cache
|
|
42
|
+
nosetests.xml
|
|
43
|
+
coverage.xml
|
|
44
|
+
|
|
45
|
+
# Translations
|
|
46
|
+
*.mo
|
|
47
|
+
*.pot
|
|
48
|
+
|
|
49
|
+
# Django stuff:
|
|
50
|
+
*.log
|
|
51
|
+
|
|
52
|
+
# Sphinx documentation
|
|
53
|
+
docs/_build/
|
|
54
|
+
|
|
55
|
+
# PyBuilder
|
|
56
|
+
target/
|
|
57
|
+
|
|
58
|
+
# virtualenv
|
|
59
|
+
py-ve*
|
|
60
|
+
|
|
61
|
+
#cloud9
|
|
62
|
+
.c9
|
|
63
|
+
|
|
64
|
+
#pycharm
|
|
65
|
+
.idea/
|
|
66
|
+
venv/
|
|
67
|
+
|
|
68
|
+
# OR files
|
|
69
|
+
*.lp
|
|
70
|
+
*.mps
|
|
71
|
+
*.mst
|
|
72
|
+
*.sol
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "2.0.0",
|
|
3
|
+
"tasks": [
|
|
4
|
+
{
|
|
5
|
+
"label": "Run unit tests",
|
|
6
|
+
"type": "shell",
|
|
7
|
+
"command": "uv run python -m unittest discover -s pulp/tests -v",
|
|
8
|
+
"group": {
|
|
9
|
+
"kind": "test",
|
|
10
|
+
"isDefault": true
|
|
11
|
+
},
|
|
12
|
+
"presentation": {
|
|
13
|
+
"reveal": "always",
|
|
14
|
+
"panel": "shared"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|