bnbpy 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.
- bnbpy-0.1.0/MANIFEST.in +4 -0
- bnbpy-0.1.0/PKG-INFO +344 -0
- bnbpy-0.1.0/README.md +296 -0
- bnbpy-0.1.0/pyproject.toml +55 -0
- bnbpy-0.1.0/setup.cfg +71 -0
- bnbpy-0.1.0/setup.py +181 -0
- bnbpy-0.1.0/src/bnbprob/__init__.py +0 -0
- bnbpy-0.1.0/src/bnbprob/gcol/__init__.py +57 -0
- bnbpy-0.1.0/src/bnbprob/gcol/base.py +63 -0
- bnbpy-0.1.0/src/bnbprob/gcol/colgen.py +337 -0
- bnbpy-0.1.0/src/bnbprob/gcol/coloring.py +154 -0
- bnbpy-0.1.0/src/bnbprob/gcol/dataloader.py +58 -0
- bnbpy-0.1.0/src/bnbprob/gcol/indset.py +209 -0
- bnbpy-0.1.0/src/bnbprob/gcol/plot.py +304 -0
- bnbpy-0.1.0/src/bnbprob/gcol/setcover.py +144 -0
- bnbpy-0.1.0/src/bnbprob/machdeadline/__init__.py +13 -0
- bnbpy-0.1.0/src/bnbprob/machdeadline/bnb.py +17 -0
- bnbpy-0.1.0/src/bnbprob/machdeadline/instance.py +104 -0
- bnbpy-0.1.0/src/bnbprob/machdeadline/job.py +33 -0
- bnbpy-0.1.0/src/bnbprob/machdeadline/lagrangian.py +237 -0
- bnbpy-0.1.0/src/bnbprob/machdeadline/problem.py +152 -0
- bnbpy-0.1.0/src/bnbprob/machdeadline/smith.py +47 -0
- bnbpy-0.1.0/src/bnbprob/milpy/__init__.py +4 -0
- bnbpy-0.1.0/src/bnbprob/milpy/colgen.py +331 -0
- bnbpy-0.1.0/src/bnbprob/milpy/problem.py +241 -0
- bnbpy-0.1.0/src/bnbprob/milpy/utils.py +3 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/__init__.py +21 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/.gitignore +1 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/__init__.pxd +2 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/environ.cpp +4586 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/environ.pxd +320 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/environ.pyx +2 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/iga.cpp +116 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/iga.hpp +38 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/intensify.cpp +25 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/intensify.hpp +18 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/job.cpp +118 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/job.hpp +66 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/job_times.cpp +16 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/job_times.hpp +27 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/local_search.cpp +99 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/local_search.hpp +35 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/mach_graph.hpp +100 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/neh.cpp +139 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/neh.hpp +28 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/permutation.cpp +293 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/permutation.hpp +366 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/quick_constructive.cpp +26 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/quick_constructive.hpp +16 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/randomized_heur.cpp +56 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/randomized_heur.hpp +17 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/sigma.cpp +69 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/sigma.hpp +110 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/single_mach.hpp +92 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/two_mach.cpp +86 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/two_mach.hpp +33 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/utils.cpp +50 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cpp/utils.hpp +19 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/.gitignore +1 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/__init__.cpp +4618 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/__init__.py +0 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/__init__.pyx +2 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/bnb.cpp +21665 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/bnb.pxd +31 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/bnb.pyi +166 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/bnb.pyx +220 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/problem.cpp +21953 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/problem.pxd +117 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/problem.pyi +394 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/problem.pyx +402 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/pyjob.cpp +13531 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/pyjob.pxd +32 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/pyjob.pyi +9 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/pyjob.pyx +160 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/pysigma.cpp +14041 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/pysigma.pxd +29 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/pysigma.pyi +206 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/pysigma.pyx +191 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/utils.cpp +6351 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/utils.pxd +10 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/cython/utils.pyx +82 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/environ.py +21 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/instances.py +120 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/machinegraph.py +78 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/mip/__init__.py +4 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/mip/disjunctive.py +96 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/mip/positional.py +88 -0
- bnbpy-0.1.0/src/bnbprob/pafssp/plot.py +177 -0
- bnbpy-0.1.0/src/bnbprob/py.typed +0 -0
- bnbpy-0.1.0/src/bnbpy/__init__.py +54 -0
- bnbpy-0.1.0/src/bnbpy/colgen.py +208 -0
- bnbpy-0.1.0/src/bnbpy/cython/.gitignore +1 -0
- bnbpy-0.1.0/src/bnbpy/cython/__init__.cpp +7246 -0
- bnbpy-0.1.0/src/bnbpy/cython/__init__.pxd +7 -0
- bnbpy-0.1.0/src/bnbpy/cython/__init__.pyi +1 -0
- bnbpy-0.1.0/src/bnbpy/cython/__init__.pyx +8 -0
- bnbpy-0.1.0/src/bnbpy/cython/counter.cpp +10119 -0
- bnbpy-0.1.0/src/bnbpy/cython/counter.pxd +15 -0
- bnbpy-0.1.0/src/bnbpy/cython/counter.pyi +8 -0
- bnbpy-0.1.0/src/bnbpy/cython/counter.pyx +13 -0
- bnbpy-0.1.0/src/bnbpy/cython/mod_queue.cpp +18419 -0
- bnbpy-0.1.0/src/bnbpy/cython/mod_queue.pxd +54 -0
- bnbpy-0.1.0/src/bnbpy/cython/mod_queue.pyi +43 -0
- bnbpy-0.1.0/src/bnbpy/cython/mod_queue.pyx +194 -0
- bnbpy-0.1.0/src/bnbpy/cython/node.cpp +14302 -0
- bnbpy-0.1.0/src/bnbpy/cython/node.pxd +56 -0
- bnbpy-0.1.0/src/bnbpy/cython/node.pyi +81 -0
- bnbpy-0.1.0/src/bnbpy/cython/node.pyx +172 -0
- bnbpy-0.1.0/src/bnbpy/cython/priqueue.cpp +18858 -0
- bnbpy-0.1.0/src/bnbpy/cython/priqueue.pxd +74 -0
- bnbpy-0.1.0/src/bnbpy/cython/priqueue.pyi +197 -0
- bnbpy-0.1.0/src/bnbpy/cython/priqueue.pyx +193 -0
- bnbpy-0.1.0/src/bnbpy/cython/problem.cpp +13413 -0
- bnbpy-0.1.0/src/bnbpy/cython/problem.pxd +41 -0
- bnbpy-0.1.0/src/bnbpy/cython/problem.pyi +193 -0
- bnbpy-0.1.0/src/bnbpy/cython/problem.pyx +154 -0
- bnbpy-0.1.0/src/bnbpy/cython/search.cpp +28754 -0
- bnbpy-0.1.0/src/bnbpy/cython/search.pxd +103 -0
- bnbpy-0.1.0/src/bnbpy/cython/search.pyi +345 -0
- bnbpy-0.1.0/src/bnbpy/cython/search.pyx +576 -0
- bnbpy-0.1.0/src/bnbpy/cython/solution.cpp +13221 -0
- bnbpy-0.1.0/src/bnbpy/cython/solution.pxd +34 -0
- bnbpy-0.1.0/src/bnbpy/cython/solution.pyi +35 -0
- bnbpy-0.1.0/src/bnbpy/cython/solution.pyx +76 -0
- bnbpy-0.1.0/src/bnbpy/cython/status.cpp +5377 -0
- bnbpy-0.1.0/src/bnbpy/cython/status.pxd +12 -0
- bnbpy-0.1.0/src/bnbpy/cython/status.pyi +11 -0
- bnbpy-0.1.0/src/bnbpy/cython/status.pyx +2 -0
- bnbpy-0.1.0/src/bnbpy/logger.py +38 -0
- bnbpy-0.1.0/src/bnbpy/parallel.py +44 -0
- bnbpy-0.1.0/src/bnbpy/plot.py +120 -0
- bnbpy-0.1.0/src/bnbpy/py.typed +0 -0
- bnbpy-0.1.0/src/bnbpy/pypure/__init__.py +0 -0
- bnbpy-0.1.0/src/bnbpy/pypure/counter.py +9 -0
- bnbpy-0.1.0/src/bnbpy/pypure/node.py +150 -0
- bnbpy-0.1.0/src/bnbpy/pypure/problem.py +101 -0
- bnbpy-0.1.0/src/bnbpy/pypure/search.py +541 -0
- bnbpy-0.1.0/src/bnbpy/pypure/solution.py +62 -0
- bnbpy-0.1.0/src/bnbpy/pypure/status.py +12 -0
- bnbpy-0.1.0/src/bnbpy.egg-info/PKG-INFO +344 -0
- bnbpy-0.1.0/src/bnbpy.egg-info/SOURCES.txt +171 -0
- bnbpy-0.1.0/src/bnbpy.egg-info/dependency_links.txt +1 -0
- bnbpy-0.1.0/src/bnbpy.egg-info/requires.txt +41 -0
- bnbpy-0.1.0/src/bnbpy.egg-info/top_level.txt +2 -0
bnbpy-0.1.0/MANIFEST.in
ADDED
bnbpy-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bnbpy
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python general Branch & Bound framework.
|
|
5
|
+
Home-page: https://github.com/bruscalia/bnbpy
|
|
6
|
+
Author: Bruno Scalia C. F. Leite
|
|
7
|
+
Author-email: bruscalia12@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
Requires-Dist: numpy>=1.21
|
|
11
|
+
Requires-Dist: scipy>=1.9
|
|
12
|
+
Requires-Dist: Cython==3.*
|
|
13
|
+
Requires-Dist: matplotlib==3.*
|
|
14
|
+
Requires-Dist: networkx==3.*
|
|
15
|
+
Requires-Dist: gif==23.*
|
|
16
|
+
Provides-Extra: lint
|
|
17
|
+
Requires-Dist: pytest==7.*; extra == "lint"
|
|
18
|
+
Requires-Dist: pytest-mock==3.14.*; extra == "lint"
|
|
19
|
+
Requires-Dist: pytest-cov==6.2.*; extra == "lint"
|
|
20
|
+
Requires-Dist: ruff==0.13.*; extra == "lint"
|
|
21
|
+
Requires-Dist: mypy==1.*; extra == "lint"
|
|
22
|
+
Requires-Dist: pydantic==2.*; extra == "lint"
|
|
23
|
+
Requires-Dist: pandas==2.*; extra == "lint"
|
|
24
|
+
Provides-Extra: tests
|
|
25
|
+
Requires-Dist: pytest==7.*; extra == "tests"
|
|
26
|
+
Requires-Dist: pytest-mock==3.14.*; extra == "tests"
|
|
27
|
+
Requires-Dist: pytest-cov==6.2.*; extra == "tests"
|
|
28
|
+
Requires-Dist: ruff==0.13.*; extra == "tests"
|
|
29
|
+
Requires-Dist: mypy==1.*; extra == "tests"
|
|
30
|
+
Requires-Dist: pydantic==2.*; extra == "tests"
|
|
31
|
+
Requires-Dist: pandas==2.*; extra == "tests"
|
|
32
|
+
Requires-Dist: pyomo==6.*; extra == "tests"
|
|
33
|
+
Requires-Dist: pandas[excel]==2.*; extra == "tests"
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest==7.*; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-mock==3.14.*; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov==6.2.*; extra == "dev"
|
|
38
|
+
Requires-Dist: ruff==0.13.*; extra == "dev"
|
|
39
|
+
Requires-Dist: mypy==1.*; extra == "dev"
|
|
40
|
+
Requires-Dist: pydantic==2.*; extra == "dev"
|
|
41
|
+
Requires-Dist: pandas==2.*; extra == "dev"
|
|
42
|
+
Requires-Dist: pyomo==6.*; extra == "dev"
|
|
43
|
+
Requires-Dist: pandas[excel]==2.*; extra == "dev"
|
|
44
|
+
Requires-Dist: ipykernel; extra == "dev"
|
|
45
|
+
Requires-Dist: highspy==1.8.*; extra == "dev"
|
|
46
|
+
Requires-Dist: sphinx==9.*; extra == "dev"
|
|
47
|
+
Requires-Dist: sphinx-rtd-theme==3.*; extra == "dev"
|
|
48
|
+
|
|
49
|
+
# bnbpy
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+

|
|
53
|
+

|
|
54
|
+

|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
A generic, configurable Python framework for solving optimization problems
|
|
58
|
+
using Branch & Bound. Also supports Column Generation and Branch & Price.
|
|
59
|
+
|
|
60
|
+
📖 **[Documentation](https://bnbpy.readthedocs.io/en/latest/)**
|
|
61
|
+
|
|
62
|
+
[Configure](#configuration) | [Usage](#usage) | [Base Problems](#base-problems) | [Development](#development) | [Contact](#contact)
|
|
63
|
+
|
|
64
|
+
See more examples in the [notebooks folder](./notebooks/):
|
|
65
|
+
|
|
66
|
+
- [Single Machine Scheduling](./notebooks/single-machine.ipynb)
|
|
67
|
+
- [Permutation Flow Shop](./notebooks/pfssp.ipynb)
|
|
68
|
+
- [Permutation Assembly Flow Shop](./notebooks/pafssp.ipynb)
|
|
69
|
+
- [MILP](./notebooks/milp.ipynb)
|
|
70
|
+
- [Cutting Stock](./notebooks/cutting-stock.ipynb)
|
|
71
|
+
- [Graph Coloring](./notebooks/graph-coloring.ipynb)
|
|
72
|
+
- [Lot Sizing](./notebooks/lot-size.ipynb)
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
### Installation
|
|
77
|
+
|
|
78
|
+
#### PyPI
|
|
79
|
+
|
|
80
|
+
The `bnbpy` package is available in PyPI. So you can install it with a simple.
|
|
81
|
+
|
|
82
|
+
```shell
|
|
83
|
+
pip install bnbpy
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Source Code
|
|
87
|
+
|
|
88
|
+
Alternatively, you can clone the repository and build it locally on your computer. Ensure you have a c++ compiler available due to Cython and c++ core components.
|
|
89
|
+
|
|
90
|
+
To clone the repository, you can run:
|
|
91
|
+
|
|
92
|
+
```shell
|
|
93
|
+
git clone https://github.com/bruscalia/bnbpy.git
|
|
94
|
+
cd bnbpy
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Install the package and its dependencies via pip from the root of the repository:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
python -m pip install .
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
To include development resources for running `bnbprob`, tests, and linters, use the `dev` extra:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
python -m pip install .[dev]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For editable (development) mode, which allows you to track changes in the source files:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
python -m pip install -e .[dev]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
All package dependencies and metadata are specified in [setup.cfg](./setup.cfg). Build requirements and extension settings are in [pyproject.toml](./pyproject.toml).
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
### Building
|
|
119
|
+
|
|
120
|
+
To build Cython extensions, run:
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
python setup.py build_ext --inplace
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Be aware of deprecated commands in `setup.py`. See [here](https://packaging.python.org/en/latest/discussions/setup-py-deprecated/#needs-build) for more information.
|
|
127
|
+
|
|
128
|
+
To build wheels for distribution, run:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
python -m build --wheel
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Usage
|
|
135
|
+
|
|
136
|
+
### Branch & Bound
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from bnbpy import BranchAndBound, Problem
|
|
140
|
+
|
|
141
|
+
class MyProblem(Problem):
|
|
142
|
+
# Define your problem specifications by implementing abstract methods
|
|
143
|
+
|
|
144
|
+
def calc_bound(self):
|
|
145
|
+
# Compute node lower bound
|
|
146
|
+
pass
|
|
147
|
+
|
|
148
|
+
def is_feasible(self):
|
|
149
|
+
# Verify if node is feasible in the complete problem
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
def branch(self):
|
|
153
|
+
# Return a list of subproblems if not fathomed
|
|
154
|
+
pass
|
|
155
|
+
|
|
156
|
+
# Apply Branch & Bound
|
|
157
|
+
problem = MyProblem()
|
|
158
|
+
bnb = BranchAndBound()
|
|
159
|
+
bnb.solve(problem)
|
|
160
|
+
print(bnb.solution)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Branch & Price
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
import bnbpy as bbp
|
|
167
|
+
|
|
168
|
+
class MyMaster(bbp.Master):
|
|
169
|
+
def __init__(self, *args):
|
|
170
|
+
# Implement your master problem
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
def add_col(self, c) -> bool:
|
|
174
|
+
# Include a new column and return True if accepted
|
|
175
|
+
return True
|
|
176
|
+
|
|
177
|
+
def solve(self) -> bbp.MasterSol:
|
|
178
|
+
# cost = ...
|
|
179
|
+
# duals = ...
|
|
180
|
+
# return MasterSol(cost=cost, duals=duals)
|
|
181
|
+
pass
|
|
182
|
+
|
|
183
|
+
class MyPricing(bbp.Pricing):
|
|
184
|
+
def __init__(self, **kwargs):
|
|
185
|
+
super().__init__(**kwargs)
|
|
186
|
+
# Instantiate your pricing problem
|
|
187
|
+
|
|
188
|
+
def set_weights(self, c):
|
|
189
|
+
# Modify the instance by incorporating new weights
|
|
190
|
+
pass
|
|
191
|
+
|
|
192
|
+
def solve(self) -> bbp.PriceSol:
|
|
193
|
+
# red_cost = ...
|
|
194
|
+
# new_col = ...
|
|
195
|
+
# return PriceSol(red_cost=red_cost, new_col=new_col)
|
|
196
|
+
pass
|
|
197
|
+
|
|
198
|
+
class MyCG(bbp.ColumnGenProblem):
|
|
199
|
+
def __init__(self, **kwargs):
|
|
200
|
+
master = MyMaster()
|
|
201
|
+
pricing = MyPricing(**kwargs)
|
|
202
|
+
super().__init__(
|
|
203
|
+
master=master,
|
|
204
|
+
pricing=pricing,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def branch(self) -> list['MyCG'] | None:
|
|
208
|
+
# Create children
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
def is_feasible(self) -> bool:
|
|
212
|
+
# Check for feasibility in the complete formulation
|
|
213
|
+
pass
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Base Problems
|
|
217
|
+
|
|
218
|
+
The `bnbprob` package incorporates elements of `bnbpy` to solve classical examples.
|
|
219
|
+
It is installed alongside `bnbpy`.
|
|
220
|
+
|
|
221
|
+
See examples for [MILP](#milp), [Permutation Flow Shop](#flow-shop), and [Graph Coloring](#graph-coloring) problems below.
|
|
222
|
+
|
|
223
|
+
### MILP
|
|
224
|
+
|
|
225
|
+
The MILP implementation is based on `scipy.optimize.linprog` for solving LPs.
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
import numpy as np
|
|
229
|
+
|
|
230
|
+
from bnbprob.milpy import MILP
|
|
231
|
+
from bnbpy import BranchAndBound
|
|
232
|
+
|
|
233
|
+
# Simple problem
|
|
234
|
+
c = np.array([-5.0, -4.0])
|
|
235
|
+
|
|
236
|
+
A_ub = np.array([
|
|
237
|
+
[2.0, 3.0],
|
|
238
|
+
[2.0, 1.0]
|
|
239
|
+
])
|
|
240
|
+
b_ub = np.array([12.0, 6.0])
|
|
241
|
+
|
|
242
|
+
milp = MILP(c, A_ub=A_ub, b_ub=b_ub)
|
|
243
|
+
bfs = BranchAndBound()
|
|
244
|
+
sol = bfs.solve(milp)
|
|
245
|
+
print(f"Sol: {sol} | x: {sol.x}")
|
|
246
|
+
# >>> Sol: Status: OPTIMAL | Cost: -18.0 | LB: -18.0 | x: [2. 2.]
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Permutation Flow Shop
|
|
250
|
+
|
|
251
|
+
In this example, an instance from the literature with 20 jobs on 10 machines is solved.
|
|
252
|
+
It takes less than 0.1 second, which is an impressive performance even compared to the best commercial MILP solvers.
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
import json
|
|
256
|
+
from bnbprob.pafssp import CallbackBnB, PermFlowShop, plot_gantt
|
|
257
|
+
|
|
258
|
+
with open("./data/flow-shop/reC11.json", mode="r", encoding="utf8") as f:
|
|
259
|
+
p = json.load(f)
|
|
260
|
+
|
|
261
|
+
problem = PermFlowShop.from_p(p, constructive='neh')
|
|
262
|
+
bnb = CallbackBnB()
|
|
263
|
+
|
|
264
|
+
# The commercial solver Gurobi took 600s (timeout) to find the near-optimal
|
|
265
|
+
# solution 1432
|
|
266
|
+
sol = bnb.solve(
|
|
267
|
+
problem, maxiter=1000000, timelimit=600
|
|
268
|
+
)
|
|
269
|
+
print(sol)
|
|
270
|
+
# >>> Status: OPTIMAL | Cost: 1431 | LB: 1431
|
|
271
|
+
|
|
272
|
+
plot_gantt(sol.sequence, figsize=[8, 3])
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+

|
|
276
|
+
|
|
277
|
+
### Graph Coloring
|
|
278
|
+
|
|
279
|
+
To illustrate the usability of the Branch & Price feature, the implementation
|
|
280
|
+
of Graph Coloring outperforms commercial solvers with basic MILP modeling.
|
|
281
|
+
|
|
282
|
+
```python
|
|
283
|
+
from bnbprob import gcol
|
|
284
|
+
from bnbpy import BranchAndBound
|
|
285
|
+
|
|
286
|
+
# Instances are available in the 'data' folder
|
|
287
|
+
instance = gcol.load_instance("./data/gcol/gcol_70_7.txt")
|
|
288
|
+
|
|
289
|
+
# Solve a 70-node instance to optimality in 24s
|
|
290
|
+
# With only heuristics to generate columns, it took only 14s
|
|
291
|
+
# The commercial solver Gurobi took 81s to find the optimal solution
|
|
292
|
+
# but could only prove optimality within 51 min
|
|
293
|
+
bnb = BranchAndBound()
|
|
294
|
+
price_tol = 0.1
|
|
295
|
+
pricing = gcol.ColorHybrPricing(
|
|
296
|
+
instance["edges"],
|
|
297
|
+
heur=gcol.TargetMultiStart(
|
|
298
|
+
12, price_tol + 1, 20, 200
|
|
299
|
+
),
|
|
300
|
+
price_tol=price_tol
|
|
301
|
+
)
|
|
302
|
+
problem = gcol.ColGenColor(
|
|
303
|
+
instance['edges'],
|
|
304
|
+
pricing=pricing,
|
|
305
|
+
max_iter_price=1000,
|
|
306
|
+
)
|
|
307
|
+
sol = bnb.solve(problem, maxiter=1000)
|
|
308
|
+
print(sol)
|
|
309
|
+
# >>> Status: OPTIMAL | Cost: 17 | LB: 17
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## Development
|
|
313
|
+
|
|
314
|
+
### Code Quality
|
|
315
|
+
|
|
316
|
+
This project uses [Ruff](https://docs.astral.sh/ruff/) as a linter and [Mypy](https://mypy-lang.org/) as a static type checker. Both are configured in [pyproject.toml](./pyproject.toml).
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
mypy src/
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
ruff check src/
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Tests
|
|
327
|
+
|
|
328
|
+
Tests are configured in [pyproject.toml](./pyproject.toml). The package `pytest` is used as the main framework. To run tests, execute:
|
|
329
|
+
|
|
330
|
+
```
|
|
331
|
+
pytest
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
To track code coverage of the main package `bnbpy`, run:
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
pytest --cov=bnbpy --cov-report=html
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Most of the package is already cythonized, so the coverage loses its meaning when raw.
|
|
341
|
+
|
|
342
|
+
## Contact
|
|
343
|
+
|
|
344
|
+
Reach out to me at `bruscalia12@gmail.com` if you have any questions.
|
bnbpy-0.1.0/README.md
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
# bnbpy
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
A generic, configurable Python framework for solving optimization problems
|
|
10
|
+
using Branch & Bound. Also supports Column Generation and Branch & Price.
|
|
11
|
+
|
|
12
|
+
📖 **[Documentation](https://bnbpy.readthedocs.io/en/latest/)**
|
|
13
|
+
|
|
14
|
+
[Configure](#configuration) | [Usage](#usage) | [Base Problems](#base-problems) | [Development](#development) | [Contact](#contact)
|
|
15
|
+
|
|
16
|
+
See more examples in the [notebooks folder](./notebooks/):
|
|
17
|
+
|
|
18
|
+
- [Single Machine Scheduling](./notebooks/single-machine.ipynb)
|
|
19
|
+
- [Permutation Flow Shop](./notebooks/pfssp.ipynb)
|
|
20
|
+
- [Permutation Assembly Flow Shop](./notebooks/pafssp.ipynb)
|
|
21
|
+
- [MILP](./notebooks/milp.ipynb)
|
|
22
|
+
- [Cutting Stock](./notebooks/cutting-stock.ipynb)
|
|
23
|
+
- [Graph Coloring](./notebooks/graph-coloring.ipynb)
|
|
24
|
+
- [Lot Sizing](./notebooks/lot-size.ipynb)
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
### Installation
|
|
29
|
+
|
|
30
|
+
#### PyPI
|
|
31
|
+
|
|
32
|
+
The `bnbpy` package is available in PyPI. So you can install it with a simple.
|
|
33
|
+
|
|
34
|
+
```shell
|
|
35
|
+
pip install bnbpy
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
#### Source Code
|
|
39
|
+
|
|
40
|
+
Alternatively, you can clone the repository and build it locally on your computer. Ensure you have a c++ compiler available due to Cython and c++ core components.
|
|
41
|
+
|
|
42
|
+
To clone the repository, you can run:
|
|
43
|
+
|
|
44
|
+
```shell
|
|
45
|
+
git clone https://github.com/bruscalia/bnbpy.git
|
|
46
|
+
cd bnbpy
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Install the package and its dependencies via pip from the root of the repository:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
python -m pip install .
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
To include development resources for running `bnbprob`, tests, and linters, use the `dev` extra:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
python -m pip install .[dev]
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For editable (development) mode, which allows you to track changes in the source files:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
python -m pip install -e .[dev]
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
All package dependencies and metadata are specified in [setup.cfg](./setup.cfg). Build requirements and extension settings are in [pyproject.toml](./pyproject.toml).
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Building
|
|
71
|
+
|
|
72
|
+
To build Cython extensions, run:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
python setup.py build_ext --inplace
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Be aware of deprecated commands in `setup.py`. See [here](https://packaging.python.org/en/latest/discussions/setup-py-deprecated/#needs-build) for more information.
|
|
79
|
+
|
|
80
|
+
To build wheels for distribution, run:
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
python -m build --wheel
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Usage
|
|
87
|
+
|
|
88
|
+
### Branch & Bound
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
from bnbpy import BranchAndBound, Problem
|
|
92
|
+
|
|
93
|
+
class MyProblem(Problem):
|
|
94
|
+
# Define your problem specifications by implementing abstract methods
|
|
95
|
+
|
|
96
|
+
def calc_bound(self):
|
|
97
|
+
# Compute node lower bound
|
|
98
|
+
pass
|
|
99
|
+
|
|
100
|
+
def is_feasible(self):
|
|
101
|
+
# Verify if node is feasible in the complete problem
|
|
102
|
+
pass
|
|
103
|
+
|
|
104
|
+
def branch(self):
|
|
105
|
+
# Return a list of subproblems if not fathomed
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
# Apply Branch & Bound
|
|
109
|
+
problem = MyProblem()
|
|
110
|
+
bnb = BranchAndBound()
|
|
111
|
+
bnb.solve(problem)
|
|
112
|
+
print(bnb.solution)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Branch & Price
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
import bnbpy as bbp
|
|
119
|
+
|
|
120
|
+
class MyMaster(bbp.Master):
|
|
121
|
+
def __init__(self, *args):
|
|
122
|
+
# Implement your master problem
|
|
123
|
+
pass
|
|
124
|
+
|
|
125
|
+
def add_col(self, c) -> bool:
|
|
126
|
+
# Include a new column and return True if accepted
|
|
127
|
+
return True
|
|
128
|
+
|
|
129
|
+
def solve(self) -> bbp.MasterSol:
|
|
130
|
+
# cost = ...
|
|
131
|
+
# duals = ...
|
|
132
|
+
# return MasterSol(cost=cost, duals=duals)
|
|
133
|
+
pass
|
|
134
|
+
|
|
135
|
+
class MyPricing(bbp.Pricing):
|
|
136
|
+
def __init__(self, **kwargs):
|
|
137
|
+
super().__init__(**kwargs)
|
|
138
|
+
# Instantiate your pricing problem
|
|
139
|
+
|
|
140
|
+
def set_weights(self, c):
|
|
141
|
+
# Modify the instance by incorporating new weights
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
def solve(self) -> bbp.PriceSol:
|
|
145
|
+
# red_cost = ...
|
|
146
|
+
# new_col = ...
|
|
147
|
+
# return PriceSol(red_cost=red_cost, new_col=new_col)
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
class MyCG(bbp.ColumnGenProblem):
|
|
151
|
+
def __init__(self, **kwargs):
|
|
152
|
+
master = MyMaster()
|
|
153
|
+
pricing = MyPricing(**kwargs)
|
|
154
|
+
super().__init__(
|
|
155
|
+
master=master,
|
|
156
|
+
pricing=pricing,
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
def branch(self) -> list['MyCG'] | None:
|
|
160
|
+
# Create children
|
|
161
|
+
pass
|
|
162
|
+
|
|
163
|
+
def is_feasible(self) -> bool:
|
|
164
|
+
# Check for feasibility in the complete formulation
|
|
165
|
+
pass
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Base Problems
|
|
169
|
+
|
|
170
|
+
The `bnbprob` package incorporates elements of `bnbpy` to solve classical examples.
|
|
171
|
+
It is installed alongside `bnbpy`.
|
|
172
|
+
|
|
173
|
+
See examples for [MILP](#milp), [Permutation Flow Shop](#flow-shop), and [Graph Coloring](#graph-coloring) problems below.
|
|
174
|
+
|
|
175
|
+
### MILP
|
|
176
|
+
|
|
177
|
+
The MILP implementation is based on `scipy.optimize.linprog` for solving LPs.
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
import numpy as np
|
|
181
|
+
|
|
182
|
+
from bnbprob.milpy import MILP
|
|
183
|
+
from bnbpy import BranchAndBound
|
|
184
|
+
|
|
185
|
+
# Simple problem
|
|
186
|
+
c = np.array([-5.0, -4.0])
|
|
187
|
+
|
|
188
|
+
A_ub = np.array([
|
|
189
|
+
[2.0, 3.0],
|
|
190
|
+
[2.0, 1.0]
|
|
191
|
+
])
|
|
192
|
+
b_ub = np.array([12.0, 6.0])
|
|
193
|
+
|
|
194
|
+
milp = MILP(c, A_ub=A_ub, b_ub=b_ub)
|
|
195
|
+
bfs = BranchAndBound()
|
|
196
|
+
sol = bfs.solve(milp)
|
|
197
|
+
print(f"Sol: {sol} | x: {sol.x}")
|
|
198
|
+
# >>> Sol: Status: OPTIMAL | Cost: -18.0 | LB: -18.0 | x: [2. 2.]
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Permutation Flow Shop
|
|
202
|
+
|
|
203
|
+
In this example, an instance from the literature with 20 jobs on 10 machines is solved.
|
|
204
|
+
It takes less than 0.1 second, which is an impressive performance even compared to the best commercial MILP solvers.
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
import json
|
|
208
|
+
from bnbprob.pafssp import CallbackBnB, PermFlowShop, plot_gantt
|
|
209
|
+
|
|
210
|
+
with open("./data/flow-shop/reC11.json", mode="r", encoding="utf8") as f:
|
|
211
|
+
p = json.load(f)
|
|
212
|
+
|
|
213
|
+
problem = PermFlowShop.from_p(p, constructive='neh')
|
|
214
|
+
bnb = CallbackBnB()
|
|
215
|
+
|
|
216
|
+
# The commercial solver Gurobi took 600s (timeout) to find the near-optimal
|
|
217
|
+
# solution 1432
|
|
218
|
+
sol = bnb.solve(
|
|
219
|
+
problem, maxiter=1000000, timelimit=600
|
|
220
|
+
)
|
|
221
|
+
print(sol)
|
|
222
|
+
# >>> Status: OPTIMAL | Cost: 1431 | LB: 1431
|
|
223
|
+
|
|
224
|
+
plot_gantt(sol.sequence, figsize=[8, 3])
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+

|
|
228
|
+
|
|
229
|
+
### Graph Coloring
|
|
230
|
+
|
|
231
|
+
To illustrate the usability of the Branch & Price feature, the implementation
|
|
232
|
+
of Graph Coloring outperforms commercial solvers with basic MILP modeling.
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
from bnbprob import gcol
|
|
236
|
+
from bnbpy import BranchAndBound
|
|
237
|
+
|
|
238
|
+
# Instances are available in the 'data' folder
|
|
239
|
+
instance = gcol.load_instance("./data/gcol/gcol_70_7.txt")
|
|
240
|
+
|
|
241
|
+
# Solve a 70-node instance to optimality in 24s
|
|
242
|
+
# With only heuristics to generate columns, it took only 14s
|
|
243
|
+
# The commercial solver Gurobi took 81s to find the optimal solution
|
|
244
|
+
# but could only prove optimality within 51 min
|
|
245
|
+
bnb = BranchAndBound()
|
|
246
|
+
price_tol = 0.1
|
|
247
|
+
pricing = gcol.ColorHybrPricing(
|
|
248
|
+
instance["edges"],
|
|
249
|
+
heur=gcol.TargetMultiStart(
|
|
250
|
+
12, price_tol + 1, 20, 200
|
|
251
|
+
),
|
|
252
|
+
price_tol=price_tol
|
|
253
|
+
)
|
|
254
|
+
problem = gcol.ColGenColor(
|
|
255
|
+
instance['edges'],
|
|
256
|
+
pricing=pricing,
|
|
257
|
+
max_iter_price=1000,
|
|
258
|
+
)
|
|
259
|
+
sol = bnb.solve(problem, maxiter=1000)
|
|
260
|
+
print(sol)
|
|
261
|
+
# >>> Status: OPTIMAL | Cost: 17 | LB: 17
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Development
|
|
265
|
+
|
|
266
|
+
### Code Quality
|
|
267
|
+
|
|
268
|
+
This project uses [Ruff](https://docs.astral.sh/ruff/) as a linter and [Mypy](https://mypy-lang.org/) as a static type checker. Both are configured in [pyproject.toml](./pyproject.toml).
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
mypy src/
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
ruff check src/
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Tests
|
|
279
|
+
|
|
280
|
+
Tests are configured in [pyproject.toml](./pyproject.toml). The package `pytest` is used as the main framework. To run tests, execute:
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
pytest
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
To track code coverage of the main package `bnbpy`, run:
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
pytest --cov=bnbpy --cov-report=html
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Most of the package is already cythonized, so the coverage loses its meaning when raw.
|
|
293
|
+
|
|
294
|
+
## Contact
|
|
295
|
+
|
|
296
|
+
Reach out to me at `bruscalia12@gmail.com` if you have any questions.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = [
|
|
3
|
+
"setuptools>=64",
|
|
4
|
+
"wheel",
|
|
5
|
+
"Cython>=3.0",
|
|
6
|
+
"numpy>=1.19.0"
|
|
7
|
+
]
|
|
8
|
+
build-backend = "setuptools.build_meta"
|
|
9
|
+
|
|
10
|
+
[tool.ruff]
|
|
11
|
+
line-length = 79
|
|
12
|
+
|
|
13
|
+
[tool.ruff.lint]
|
|
14
|
+
preview = true
|
|
15
|
+
select = [
|
|
16
|
+
"E", # pycodestyle - code style errors
|
|
17
|
+
"F", # pyflakes - code quality
|
|
18
|
+
"I", # isort - import order
|
|
19
|
+
"W", # pycodestyle - code style warnings
|
|
20
|
+
"PL", # pylint - code quality
|
|
21
|
+
"PT", # flake8-pytest-style - code style for pytest
|
|
22
|
+
"C", # Verifica a complexidade de código (inclui C901)
|
|
23
|
+
"B", # flake8-bugbear - verifica code smells
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[tool.ruff.format]
|
|
27
|
+
preview = true
|
|
28
|
+
quote-style = "single"
|
|
29
|
+
|
|
30
|
+
[tool.mypy]
|
|
31
|
+
python_version = "3.12"
|
|
32
|
+
ignore_missing_imports = true
|
|
33
|
+
strict = true
|
|
34
|
+
disable_error_code = ["unused-ignore"]
|
|
35
|
+
|
|
36
|
+
[tool.pytest.ini_options]
|
|
37
|
+
testpaths = ["tests"]
|
|
38
|
+
pythonpath = ["src"]
|
|
39
|
+
markers = [
|
|
40
|
+
"machdeadline: Mark test related to machine deadline scenarios",
|
|
41
|
+
"pafssp: Mark test related to PAFSSP scenarios",
|
|
42
|
+
"milp: Mark test related to MILP problems",
|
|
43
|
+
"milpnaive: Mark test related to naive MILP implementations",
|
|
44
|
+
"knapsack: Mark test related to knapsack problem implementations",
|
|
45
|
+
"solution: Mark test related to Solution class",
|
|
46
|
+
"problem: Mark test related to Problem class",
|
|
47
|
+
"node: Mark test related to Node class",
|
|
48
|
+
"search: Mark test related to B&B search module",
|
|
49
|
+
"priqueue: Mark test related to priority queue classes",
|
|
50
|
+
"colgen: Mark test related to Column Generation",
|
|
51
|
+
"gcol: Mark test related to the Graph Coloring module",
|
|
52
|
+
"searchlogger: Mark test related to the SearchLogger class",
|
|
53
|
+
"core: Mark test for core functionality (solution, problem, node, search, priqueue)",
|
|
54
|
+
"integration: Mark for integration tests (machdeadline, pfssp, milp, milpnaive, knapsack, gcol)"
|
|
55
|
+
]
|