Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streamlit to Dash #50

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.DS_Store
__pycache__
cache
assets/__generated_theme.css
14 changes: 0 additions & 14 deletions .gitpod.yml

This file was deleted.

6 changes: 0 additions & 6 deletions .streamlit/config.toml

This file was deleted.

143 changes: 84 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,60 +7,76 @@

# 3D Bin Packing

Three-dimensional bin packing [[1]](#Martello) is an
Three-dimensional bin packing [[1]](#Martello) is an
optimization problem where the goal is to use the minimum number of bins to pack items with
different dimensions, weights and properties. Examples of bins are containers,
pallets or aircraft ULDs (Unit Load Device).
3d binpacking problems may include various objectives and requirements. Basic
requirements are boundary and geometric constraints, which require that items be
packed within bin boundaries and without overlapping, respectively. There may be
additional requirements on the stability of the packing, flatness of top or bottom layers,
fragility and weight distribution, etc., which are not modeled in this formulation.
In this example, both items and bins are cuboids, and the sides of the items must be packed parallel
to the sides of bins.
3D binpacking problems may include various objectives and requirements. Basic
requirements are boundary and geometric constraints, which require that items be
packed within bin boundaries and without overlapping, respectively. There may be
additional requirements on the stability of the packing, flatness of top or bottom layers,
fragility and weight distribution, etc., which are not modeled in this formulation.
In this example, both items and bins are cuboids, and the sides of the items must be packed parallel
to the sides of bins.

This example demonstrates a formulation and optimization of a three-dimensional multi bin packing problem
using a [constrained quadratic model](
https://docs.ocean.dwavesys.com/en/stable/concepts/cqm.html#cqm-sdk) (CQM) that
can be solved using a Leap hybrid CQM solver.

![Demo Example](static/demo.png)

Below is an example output of the program:
<a id="plot"></a>
![Example Solution](_static/sample_solution_plot.png)

## Installation
You can run this example without installation in cloud-based IDEs that support the
[Development Containers specification](https://containers.dev/supporting) (aka "devcontainers")
such as GitHub Codespaces.

You can run this example without installation in cloud-based IDEs that support
the [Development Containers specification](https://containers.dev/supporting)
(aka "devcontainers").

For development environments that do not support ``devcontainers``, install
requirements:
For development environments that do not support `devcontainers`, install requirements:

pip install -r requirements.txt
```bash
pip install -r requirements.txt
```

If you are cloning the repo to your local system, working in a
[virtual environment](https://docs.python.org/3/library/venv.html) is
recommended.
If you are cloning the repo to your local system, working in a
[virtual environment](https://docs.python.org/3/library/venv.html) is recommended.

## Usage
Your development environment should be configured to access the
[Leap&trade; quantum cloud service](https://docs.ocean.dwavesys.com/en/stable/overview/sapi.html).
You can see information about supported IDEs and authorizing access to your Leap account
[here](https://docs.dwavesys.com/docs/latest/doc_leap_dev_env.html).

Run the following terminal command to start the Dash application:

To run the demo, type:
```bash
python app.py
```

Access the user interface with your browser at http://127.0.0.1:8050/.

streamlit run bin_packing_app.py
The demo program opens an interface where you can configure problems and submit these problems to
a solver.

The demo program opens an interface where you can instantiate a 3d bin packing problem by either importing a file
or configuring a random problem. The user interface also allows you to submit the problems and view results.
Configuration options can be found in the [demo_configs.py](demo_configs.py) file.

> [!NOTE]\
> If you plan on editing any files while the application is running, please run the application
with the `--debug` command-line argument for live reloads and easier debugging:
`python app.py --debug`

Alternatively, one can solve an instance of a problem through the terminal by typing:

python packing3d.py --data_filepath <path to your problem file>

There are several examples of problem instances under the `input` folder.
There are several examples of problem instances under the `input` folder.

### Inputs

This is an example of a 3d bin packing input instance file with 1 bin and 35 cases.
This is an example of a 3D bin packing input instance file with 1 bin and 35 cases.

```
# Max num of bins : 1
Expand All @@ -78,9 +94,11 @@ This is an example of a 3d bin packing input instance file with 1 bin and 35 cas

Note that:
- all bins are the same size.
- there are several cases of each size (`quantity` sets the number of cases of identity `case id` with all having the dimensions defined in that row).
- there are several cases of each size (`quantity` sets the number of cases of identity `case id`
with all having the dimensions defined in that row).

Run `python packing3d.py --help` in the terminal for a description of the demo program's input parameters.
Run `python packing3d.py --help` in the terminal for a description of the demo program's input
parameters.

### Outputs
The program produces a solution like this:
Expand All @@ -90,7 +108,7 @@ The program produces a solution like this:
# Number of cases packed: 35
# Objective value: 104.457

case_id bin-location orientation x y z x' y' z'
case_id bin_location orientation x y z x' y' z'
--------- -------------- ------------- --- --- --- ---- ---- ----
0 1 3 15 0 0 3 5 8
0 1 3 9 0 0 3 5 8
Expand All @@ -100,39 +118,40 @@ The program produces a solution like this:
0 1 2 20 0 0 5 8 3
...
```
Note that only a portion of the solution is shown above. Also, there are multiple rows with same `case_id` as
there are several items of the same size.
The number under the `orientation` column shows the rotation of a case inside a bin as shown in the following figure.

![Orientations](_static/orientations.png)
Note that only a portion of the solution is shown above. Also, there are multiple rows with same
`case_id` as there are several items of the same size.
The number under the `orientation` column shows the rotation of a case inside a bin as shown in the
following figure.

![Orientations](_static/orientations.png)

The [graphic](#plot) at the top of the README is a visualization of this solution.

Note that in this example, we do not model support or load-bearing constraints for cases.
Therefore, it is possible that larger cases are packed over smaller cases without having full support.

## Problem Description
The goal of the 3D-bin packing problem is to ensure that the cases are securely packed within the fewest
bins possible. The model sets the following objectives and constraints to achieve this goal:
The goal of the 3D bin packing problem is to ensure that the cases are securely packed within the
fewest bins possible. The model sets the following objectives and constraints to achieve this goal:

**Objectives:** minimize the height of the packed cases and number of bins used.
**Objectives:** minimize the height of the packed cases and number of bins used.

**Constraints:** the constraints for this problem fall into multiple categories. Orientation constraints focus on restricting
cases to a single orientation. Case and bin assignment constraints ensure that each case is placed in exactly
one bin, that the chosen bin is in use, and that there are no gaps between bins. Geometric constraints
are used to make sure cases aren't assigned to positions that would cause an overlap with another case. Bin
boundary constraints enforce that cases are placed completely inside their designated bin.
**Constraints:** the constraints for this problem fall into multiple categories. Orientation
constraints focus on restricting cases to a single orientation. Case and bin assignment constraints
ensure that each case is placed in exactly one bin, that the chosen bin is in use, and that there
are no gaps between bins. Geometric constraints are used to make sure cases aren't assigned to
positions that would cause an overlap with another case. Bin boundary constraints enforce that cases
are placed completely inside their designated bin.

## Model Overview

In this example, to model multiple bins we assume that bins are located back-to-back
In this example, to model multiple bins we assume that bins are located back-to-back
next to each other along x-axis of the coordinate system. This way we only need to use one coordinate system
with width of `W`, height of `H` and length of `n * L` to model all bins,(see [below](#problem-parameters)
for definition of these parameters).
for definition of these parameters).
That means that the first bin is located at `0 <= x <= L`, second at `L < x <= 2 * L`,
and last bin is located at `(n - 1) * L < x <= n * L`.
We apply necessary constraints to ensure that cases are not placed between two bins.
and last bin is located at `(n - 1) * L < x <= n * L`.
We apply necessary constraints to ensure that cases are not placed between two bins.

### Problem Parameters

Expand Down Expand Up @@ -160,8 +179,9 @@ These are the parameters of the problem:
- `r_(i,k)`: binary variable defining `k` orientations for case `i`
- `x_i`,`y_i`,`z_i`: continuous variable defining location of the back lower left corner of case `i` along `x`, `y`, and `z` axes of the bin

Note that we can determine some variables before the optimization. For example, without loss of generality we can assign the first case to
the first bin. Therefore `u_{0,0} = 1` and `u_{0,j} = 0` for any `j\ne 0`.
Note that we can determine some variables before the optimization. For example, without loss of
generality we can assign the first case to
the first bin. Therefore `u_{0,0} = 1` and `u_{0,j} = 0` for any `j\ne 0`.

We can also estimate a lower bound on the number of occupied bins:

Expand All @@ -171,10 +191,10 @@ The first `jmin` bin variables `v_j` can therefore be set equal to 1 without
loss of generality. In what follows, the set of bins `J` is `{jmin, ..., n}`.

### Expressions
Expressions are linear or quadratic combinations of variables used for easier representations of the models.
- `x'_i`,`y'_i`,`z'_i`: effective length, width and height of case `i`, considering orientation,
Expressions are linear or quadratic combinations of variables used for easier representations of the models.
- `x'_i`,`y'_i`,`z'_i`: effective length, width and height of case `i`, considering orientation,
along `x`, `y`, and `z` axes of the bin
- `o_1`, `o_2`, `o_3`: terms of the objective
- `o_1`, `o_2`, `o_3`: terms of the objective

### Objective
Our objective contains three terms:
Expand All @@ -184,7 +204,7 @@ that cases are packed down.

![eq1](_static/eq1.png)

The second term in the objective ensures that the height of the topmost case in each bin is minimized. This
The second term in the objective ensures that the height of the topmost case in each bin is minimized. This
objective is weakly considered in the first objective term, but here is given more importance.

![eq2](_static/eq2.png)
Expand All @@ -193,9 +213,9 @@ Our third objective function minimizes the total number of the bins.

![eq3](_static/eq3.png)

Note that we multiplied this term by the height of the bins so its contribution to the objective has same weights as the
first and second objective terms.
The total objective value is the summation of all these terms.
Note that we multiplied this term by the height of the bins so its contribution to the objective has
same weights as the first and second objective terms.
The total objective value is the summation of all these terms.

### Constraints
#### Orientation Constraints
Expand Down Expand Up @@ -226,10 +246,12 @@ before bin `j + 1`.
![eq10](_static/eq10.png)

#### Geometric Constraints
Geometric constraints, required only for three-dimensional problems, are applied to prevent overlaps between cases.
In the following constraints, "left" and "right" refer to the position of the case along the `x` axis of a bin,
"behind" and "in front of" to the `y` axis, and "above" and "below" to the `z` axis.
To avoid overlaps between each pair of cases we only need to ensure that at least one of these situations occur:
Geometric constraints, required only for three-dimensional problems, are applied to prevent overlaps
between cases.
In the following constraints, "left" and "right" refer to the position of the case along the `x`
axis of a bin, "behind" and "in front of" to the `y` axis, and "above" and "below" to the `z` axis.
To avoid overlaps between each pair of cases we only need to ensure that at least one of these
situations occur:

- case `i` is on the left of case `k` (`q = 0`):

Expand Down Expand Up @@ -272,12 +294,15 @@ These sets of constraints ensure that case `i` is not placed outside the bins.

When `u_{i,j}` is 0 these constraints are relaxed.

Note that the width constraints do not involve the variables `u_{i,j}`. This is because the bins are virtually placed along the x-axis and all the cases have to satisfy the width constraints in a similar manner. Similar considerations apply for the height constraints, however, here we want to track the bin height `s_j`.
Note that the width constraints do not involve the variables `u_{i,j}`. This is because the bins are
virtually placed along the x-axis and all the cases have to satisfy the width constraints in a
similar manner. Similar considerations apply for the height constraints, however, here we want to
track the bin height `s_j`.

## References

<a id="Martello"></a>
[1] Martello, Silvano, David Pisinger, and Daniele Vigo.
[1] Martello, Silvano, David Pisinger, and Daniele Vigo.
"The three-dimensional bin packing problem."
Operations research 48.2 (2000): 256-267.
## License
Expand Down
Binary file modified _static/sample_solution_plot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 90 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright 2024 D-Wave
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import annotations

import argparse

import dash
import diskcache
from dash import DiskcacheManager

from demo_configs import APP_TITLE, THEME_COLOR, THEME_COLOR_SECONDARY
from demo_interface import create_interface

# Essential for initializing callbacks. Do not remove.
import demo_callbacks

# Fix Dash long callbacks crashing on macOS 10.13+ (also potentially not working
# on other POSIX systems), caused by https://bugs.python.org/issue33725
# (aka "beware of multithreaded process forking").
#
# Note: default start method has already been changed to "spawn" on darwin in
# the `multiprocessing` library, but its fork, `multiprocess` still hasn't caught up.
# (see docs: https://docs.python.org/3/library/multiprocessing.html#contexts-and-start-methods)
import multiprocess

if multiprocess.get_start_method(allow_none=True) is None:
multiprocess.set_start_method("spawn")

cache = diskcache.Cache("./cache")
background_callback_manager = DiskcacheManager(cache)

app = dash.Dash(
__name__,
meta_tags=[{"name": "viewport", "content": "width=device-width, initial-scale=1"}],
prevent_initial_callbacks="initial_duplicate",
background_callback_manager=background_callback_manager,
)
app.title = APP_TITLE

app.config.suppress_callback_exceptions = True

# Parse debug argument
parser = argparse.ArgumentParser(description="Dash debug setting.")
parser.add_argument(
"--debug",
action="store_true",
help="Add argument to see Dash debug menu and get live reload updates while developing.",
)

args = parser.parse_args()
DEBUG = args.debug

print(f"\nDebug has been set to: {DEBUG}")
if not DEBUG:
print(
"The app will not show live code updates and the Dash debug menu will be hidden.",
"If editting code while the app is running, run the app with `python app.py --debug`.\n",
sep="\n",
)

# Generates css file and variable using THEME_COLOR and THEME_COLOR_SECONDARY settings
css = f"""/* Automatically generated theme settings css file, see app.py */
:root {{
--theme: {THEME_COLOR};
--theme-secondary: {THEME_COLOR_SECONDARY};
}}
"""
with open("assets/__generated_theme.css", "w") as f:
f.write(css)


if __name__ == "__main__":
# Imports the Dash HTML code and sets it in the app.
# Creates the visual layout and app (see `demo_interface.py`)
app.layout = create_interface()

# Run the server
app.run_server(debug=DEBUG)
Loading