Skip to content

Commit

Permalink
Merge pull request #51 from dwave-examples/feature/add-scenarios
Browse files Browse the repository at this point in the history
Default Scenarios
  • Loading branch information
k8culver authored Jan 2, 2025
2 parents b8ea8e5 + 79a30b7 commit 6923126
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 16 deletions.
65 changes: 61 additions & 4 deletions demo_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from __future__ import annotations

import base64
import json
from typing import NamedTuple, Union

import dash
Expand Down Expand Up @@ -68,6 +69,7 @@ def toggle_left_column(collapse_trigger: int, to_collapse_class: str) -> str:
@dash.callback(
Output({"type": "generated-settings", "index": ALL}, "className"),
Output("uploaded-settings", "className"),
Output("scenario-settings", "className"),
inputs=[
Input("problem-type", "value"),
State({"type": "generated-settings", "index": ALL}, "children"),
Expand All @@ -88,9 +90,12 @@ def update_problem_type(
str: The class name for the `Uploaded` ProblemType.
"""
if problem_type is ProblemType.FILE.value:
return ["display-none"] * len(gen_settings), ""
return ["display-none"] * len(gen_settings), "", "display-none"

return [""] * len(gen_settings), "display-none"
if problem_type is ProblemType.SCENARIO.value:
return ["display-none"] * len(gen_settings), "display-none", ""

return [""] * len(gen_settings), "display-none", "display-none"


@dash.callback(
Expand Down Expand Up @@ -137,7 +142,7 @@ def generate_data(
problem-data-store: The data that was generated for the table.
saved: The class name for the `Saved!` feedback.
"""
if ProblemType(problem_type) is ProblemType.FILE:
if ProblemType(problem_type) is not ProblemType.GENERATED:
raise PreventUpdate

rng = np.random.default_rng(RANDOM_SEED)
Expand Down Expand Up @@ -173,6 +178,53 @@ def generate_data(
)


@dash.callback(
Output("input", "children", allow_duplicate=True),
Output("max-bins", "children", allow_duplicate=True),
Output("bin-dims", "children", allow_duplicate=True),
Output("problem-data-store", "data", allow_duplicate=True),
Output("saved", "className", allow_duplicate=True),
inputs=[
Input("problem-type", "value"),
Input("scenario-select", "value"),
],
prevent_initial_call=True,
)
def load_scenario(
problem_type: Union[ProblemType, int],
scenario: int,
) -> tuple[list, int, str, dict, str]:
"""Updates the input table when ProblemType is `Scenario` has changed.
Args:
problem_type: The input problem type. Either Generated or Uploaded.
scenario_select: The current value of the scenario dropdown.
Returns:
input: The input table.
max-bins: The maximum bins to display in the input UI.
bin-dimensions: The bin dimension string to display in the UI.
problem-data-store: The data that was generated for the table.
saved: The class name for the `Saved!` feedback.
"""
if ProblemType(problem_type) is not ProblemType.SCENARIO:
raise PreventUpdate

scenarios = json.load(open("./src/data/scenarios.json", "r"))

scenario_data = scenarios[str(scenario)]

bin_length, bin_width, bin_height = scenario_data["bin_dimensions"]

return (
generate_table(scenario_data),
scenario_data["num_bins"],
f"{bin_length} * {bin_width} * {bin_height}",
scenario_data,
"display-none"
)


class ReadInputFileReturn(NamedTuple):
"""Return type for the ``read_input_file`` callback function."""

Expand Down Expand Up @@ -216,7 +268,7 @@ def read_input_file(
filename: The name of the file that was uploaded to display in the UI.
problem_data_store: The value to update the table data store.
"""
if ProblemType(problem_type) is ProblemType.GENERATED:
if ProblemType(problem_type) is not ProblemType.FILE:
raise PreventUpdate

if file_contents is not None:
Expand Down Expand Up @@ -330,6 +382,11 @@ def update_graph_colors(
(Output("bin-length", "disabled"), True, False),
(Output("bin-width", "disabled"), True, False),
(Output("bin-height", "disabled"), True, False),
(Output("solver-type-select", "disabled"), True, False),
(Output("solver-time-limit", "disabled"), True, False),
(Output("scenario-select", "disabled"), True, False),
(Output("input-file", "disabled"), True, False),
(Output("save-solution", "disabled"), True, False),
],
cancel=[Input("cancel-button", "n_clicks")],
prevent_initial_call=True,
Expand Down
28 changes: 21 additions & 7 deletions demo_configs.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
are cuboids, and the sides of the items must be packed parallel to the sides of bins.
"""

RANDOM_SEED = 4
RANDOM_SEED = 42

#######################################
# Sliders, buttons and option entries #
Expand All @@ -47,30 +47,44 @@
"min": 1,
"max": 75,
"step": 1,
"value": 20,
"value": 30,
}

CASE_DIM = {
"min": 1,
"max": 30,
"step": 1,
"value": [2, 15],
"value": [1, 5],
}

BIN_LENGTH = {
"min": 1,
"max": 200,
"step": 1,
"value": 20,
}

BIN_WIDTH = {
"min": 1,
"max": 200,
"step": 1,
"value": 8,
}

BIN_DIM = {
BIN_HEIGHT = {
"min": 1,
"max": 200,
"step": 1,
"value": 50,
"value": 8,
}

# checklist to color by case id or color each case separately
COLOR_BY_CASE = ["Color by Case ID"]

# solver time limits in seconds (value means default)
SOLVER_TIME = {
"min": 10,
"min": 5,
"max": 300,
"step": 5,
"value": 10,
"value": 5,
}
27 changes: 22 additions & 5 deletions demo_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

from demo_configs import (
COLOR_BY_CASE,
BIN_DIM,
BIN_HEIGHT,
BIN_LENGTH,
BIN_WIDTH,
CASE_DIM,
DESCRIPTION,
MAIN_HEADER,
Expand All @@ -29,7 +31,7 @@
THEME_COLOR_SECONDARY,
THUMBNAIL,
)
from src.demo_enums import ProblemType, SolverType
from src.demo_enums import ProblemType, ScenarioType, SolverType
from utils import TABLE_HEADERS


Expand Down Expand Up @@ -176,6 +178,10 @@ def generate_settings_form() -> html.Div:
{"label": solver_type.label, "value": solver_type.value} for solver_type in SolverType
]

scenario_options = [
{"label": scenario_type.label, "value": scenario_type.value} for scenario_type in ScenarioType
]

return html.Div(
className="settings",
children=[
Expand Down Expand Up @@ -213,7 +219,7 @@ def generate_settings_form() -> html.Div:
dcc.Input(
id="bin-length",
type="number",
**BIN_DIM,
**BIN_LENGTH,
),
]
),
Expand All @@ -223,7 +229,7 @@ def generate_settings_form() -> html.Div:
dcc.Input(
id="bin-width",
type="number",
**BIN_DIM,
**BIN_WIDTH,
),
]
),
Expand All @@ -233,7 +239,7 @@ def generate_settings_form() -> html.Div:
dcc.Input(
id="bin-height",
type="number",
**BIN_DIM,
**BIN_HEIGHT,
),
]
),
Expand All @@ -253,6 +259,17 @@ def generate_settings_form() -> html.Div:
],
id={"type": "generated-settings", "index": 0},
),
html.Div(
[
dropdown(
"Scenario",
"scenario-select",
sorted(scenario_options, key=lambda op: op["value"]),
),
],
className="display-none",
id="scenario-settings",
),
dropdown(
"Solver",
"solver-type-select",
Expand Down
38 changes: 38 additions & 0 deletions src/data/scenarios.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"0": {
"Case ID": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
"Quantity": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"Length": [1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 5, 5],
"Width": [2, 4, 5, 3, 1, 3, 4, 3, 4, 4, 1, 5],
"Height": [3, 4, 3, 1, 5, 3, 5, 2, 3, 4, 3, 1],
"num_bins": 1,
"bin_dimensions": [20, 8, 8]
},
"1": {
"Case ID": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
"Quantity": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1],
"Length": [1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5],
"Width": [2, 4, 4, 5, 3, 4, 5, 1, 1, 3, 3, 5, 3, 3],
"Height": [5, 3, 4, 2, 5, 1, 3, 1, 5, 1, 2, 4, 1, 4],
"num_bins": 1,
"bin_dimensions": [20, 8, 8]
},
"2": {
"Case ID": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
"Quantity": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1],
"Length": [1, 1, 1, 2, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5],
"Width": [2, 4, 4, 5, 3, 4, 5, 1, 1, 3, 3, 5, 3, 3],
"Height": [5, 3, 4, 2, 5, 1, 3, 1, 5, 1, 2, 4, 1, 4],
"num_bins": 2,
"bin_dimensions": [20, 8, 8]
},
"3": {
"Case ID": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28],
"Quantity": [2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 2, 1],
"Length": [1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5],
"Width": [1, 1, 2, 2, 4, 2, 3, 5, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 4, 4, 4, 5, 5, 5, 1, 2, 3, 3, 4],
"Height": [4, 5, 2, 5, 2, 3, 5, 1, 1, 3, 1, 5, 1, 5, 2, 4, 4, 5, 2, 4, 5, 1, 2, 3, 3, 4, 3, 4, 2],
"num_bins": 2,
"bin_dimensions": [20, 8, 8]
}
}
18 changes: 18 additions & 0 deletions src/demo_enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,28 @@ def label(self):
class ProblemType(Enum):
GENERATED = 0
FILE = 1
SCENARIO = 2

@property
def label(self):
return {
ProblemType.GENERATED: "Generated",
ProblemType.FILE: "Uploaded",
ProblemType.SCENARIO: "Default Scenarios",
}[self]


class ScenarioType(Enum):
ONE_FEW = 0
ONE_MANY = 1
TWO_FEW = 2
TWO_MANY = 3

@property
def label(self):
return {
ScenarioType.ONE_FEW: "One Bin - Few Cases",
ScenarioType.ONE_MANY: "One Bin - Many Cases",
ScenarioType.TWO_FEW: "Two Bins - Few Cases",
ScenarioType.TWO_MANY: "Two Bins - Many Cases",
}[self]

0 comments on commit 6923126

Please sign in to comment.