Your first Scipy optimization with Blop#
In this tutorial, you will learn the three core concepts of Blop: DOFs (the parameters you can adjust), objectives (what you want to optimize), and the Agent (which coordinates the optimization). We’ll optimize a simple mathematical function using simulated devices—the same patterns apply to real hardware.
Setup#
First, let’s import what we need and start the data infrastructure:
import logging
import time
from typing import Any
from bluesky.protocols import HasHints, HasParent, Hints, NamedMovable, Readable, Status
from bluesky.run_engine import RunEngine
from bluesky_tiled_plugins import TiledWriter
from tiled.client import from_uri
from tiled.client.container import Container
from tiled.server import SimpleTiledServer
from blop.scipy import SCP, ScipyCFG, Objective, RangeDOF, Scipy
# Suppress noisy logs from httpx
logging.getLogger("httpx").setLevel(logging.WARNING)
# Start a local Tiled server for data storage
tiled_server = SimpleTiledServer()
# Set up the Bluesky RunEngine and connect it to Tiled
RE = RunEngine({})
tiled_client = from_uri(tiled_server.uri)
tiled_writer = TiledWriter(tiled_client)
RE.subscribe(tiled_writer)
Tiled version 0.2.15
0
Creating simulated devices#
Bluesky controls devices through protocols. For this tutorial, we create simple simulated “movable” devices. In real experiments, you would use Ophyd devices or similar—the code below is just boilerplate to simulate hardware:
class AlwaysSuccessfulStatus(Status):
def add_callback(self, callback) -> None:
callback(self)
def exception(self, timeout=0.0):
return None
@property
def done(self) -> bool:
return True
@property
def success(self) -> bool:
return True
class ReadableSignal(Readable, HasHints, HasParent):
def __init__(self, name: str) -> None:
self._name = name
self._value = 0.0
@property
def name(self) -> str:
return self._name
@property
def hints(self) -> Hints:
return {"fields": [self._name], "dimensions": [], "gridding": "rectilinear"}
@property
def parent(self) -> Any | None:
return None
def read(self):
return {self._name: {"value": self._value, "timestamp": time.time()}}
def describe(self):
return {self._name: {"source": self._name, "dtype": "number", "shape": []}}
class MovableSignal(ReadableSignal, NamedMovable):
def __init__(self, name: str, initial_value: float = 0.0) -> None:
super().__init__(name)
self._value: float = initial_value
def set(self, value: float) -> Status:
self._value = value
return AlwaysSuccessfulStatus()
Defining DOFs and objectives#
DOFs (degrees of freedom) are the parameters the optimizer can adjust. Objectives are what you want to optimize. Here we define two DOFs (x1 and x2) that can range from -5 to 5, and one objective (the Himmelblau function) that we want to minimize:
x1 = MovableSignal("x1", initial_value=0.1)
x2 = MovableSignal("x2", initial_value=0.23)
dofs = [
RangeDOF(actuator=x1, bounds=(-5, 5), parameter_type="float"),
RangeDOF(actuator=x2, bounds=(-5, 5), parameter_type="float"),
]
objectives = [
Objective(name="himmelblau_2d", minimize=True),
]
sensors = []
Writing the evaluation function#
The evaluation function computes objective values from experimental data. After each run, Blop calls this function with the run’s unique ID and the suggestions that were tried. It returns the computed objective values:
class Himmelblau2DEvaluation:
def __init__(self, tiled_client: Container):
self.tiled_client = tiled_client
def __call__(self, uid: str, suggestions: list[dict]) -> list[dict]:
run = self.tiled_client[uid]
outcomes = []
reordered_suggestions = run.start["blop_suggestions"]
x1_data = run["primary/x1"].read()
x2_data = run["primary/x2"].read()
print(
"[Himmelblau] evaluating suggestions: ",
[s["_id"] for s in suggestions],
" reordered to: ",
[s["_id"] for s in reordered_suggestions],
)
for index, suggestion in enumerate(reordered_suggestions):
# Special key to identify a suggestion
suggestion_id = suggestion["_id"]
x1 = x1_data[index]
x2 = x2_data[index]
# Himmelblau function: has four global minima where value = 0
outcomes.append({"himmelblau_2d": (x1**2 + x2 - 11) ** 2 + (x1 + x2**2 - 7) ** 2, "_id": suggestion_id})
return outcomes
Running the optimization#
The Agent brings everything together. Create one with your DOFs, objectives, and evaluation function, then run the optimization:
agent = Scipy.Agent(
sensors=sensors,
dofs=dofs,
objectives=objectives,
evaluation_function=Himmelblau2DEvaluation(tiled_client=tiled_client),
name="simple-experiment",
description="A simple experiment optimizing the Himmelblau function",
)
RE(agent.optimize(10))
╭───────────────────────────────────────────────── Optimization ──────────────────────────────────────────────────╮ │ Optimizer InteractiveOptimizer │ │ Actuators x1, x2 │ │ Sensors N/A │ │ Iterations 10 │ │ Run UID afb6261d-8c36-476d-bdf1-64a7401f3b7a │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
[Himmelblau] evaluating suggestions:
[0]
reordered to:
[0]
[Himmelblau] evaluating suggestions:
[1]
reordered to:
[1]
[Himmelblau] evaluating suggestions:
[2]
reordered to:
[2]
[Himmelblau] evaluating suggestions:
[3]
reordered to:
[3]
[Himmelblau] evaluating suggestions:
[4]
reordered to:
[4]
[Himmelblau] evaluating suggestions:
[5]
reordered to:
[5]
[Himmelblau] evaluating suggestions:
[6]
reordered to:
[6]
[Himmelblau] evaluating suggestions:
[7]
reordered to:
[7]
[Himmelblau] evaluating suggestions:
[8]
reordered to:
[8]
[Himmelblau] evaluating suggestions:
[9]
reordered to:
[9]
──────────────────────────────────────────────── Iteration 1 / 10 ─────────────────────────────────────────────────
Acquire UID fb5af019-9918-4c36-b903-61f227768dc8
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━┳━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━╇━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 0 │ 0 │ 0 │ 170 │ └───────┴───────────────┴────┴────┴───────────────┘
himmelblau_2d min: 170 max: 170 mean: 170 (1 pts sampled)
──────────────────────────────────────────────── Iteration 2 / 10 ─────────────────────────────────────────────────
Acquire UID a0eafc42-52eb-4294-9f77-509d37ccda1a
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 1 │ 1e-08 │ 0 │ 170 │ └───────┴───────────────┴───────┴────┴───────────────┘
himmelblau_2d min: 170 max: 170 mean: 170 (2 pts sampled)
──────────────────────────────────────────────── Iteration 3 / 10 ─────────────────────────────────────────────────
Acquire UID e791f3bb-3d4c-4638-8869-0c586cd55e0d
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 2 │ 0 │ 1e-08 │ 170 │ └───────┴───────────────┴────┴───────┴───────────────┘
himmelblau_2d min: 170 max: 170 mean: 170 (3 pts sampled)
──────────────────────────────────────────────── Iteration 4 / 10 ─────────────────────────────────────────────────
Acquire UID 0d67c43d-1380-4fa2-ab93-efa73762ea15
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━┳━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━╇━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 3 │ 5 │ 5 │ 890 │ └───────┴───────────────┴────┴────┴───────────────┘
himmelblau_2d min: 170 max: 890 mean: 350 (4 pts sampled)
──────────────────────────────────────────────── Iteration 5 / 10 ─────────────────────────────────────────────────
Acquire UID eff94fae-a1ac-48a4-9f12-524c2fce1872
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━┳━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━╇━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 4 │ 5 │ 5 │ 890 │ └───────┴───────────────┴────┴────┴───────────────┘
himmelblau_2d min: 170 max: 890 mean: 458 (5 pts sampled)
──────────────────────────────────────────────── Iteration 6 / 10 ─────────────────────────────────────────────────
Acquire UID 038e33d0-f141-4a4f-bc5b-3248c9d88347
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━┳━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━╇━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 5 │ 5 │ 5 │ 890 │ └───────┴───────────────┴────┴────┴───────────────┘
himmelblau_2d min: 170 max: 890 mean: 530 (6 pts sampled)
──────────────────────────────────────────────── Iteration 7 / 10 ─────────────────────────────────────────────────
Acquire UID d92a02f0-8300-4491-b01e-123b24419665
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 6 │ 1.51545 │ 1.51545 │ 61.8302 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 61.8302 max: 890 mean: 463.119 (7 pts sampled)
──────────────────────────────────────────────── Iteration 8 / 10 ─────────────────────────────────────────────────
Acquire UID 285f5a14-5bd7-490e-8468-7913a5f0a5c0
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 7 │ 1.51545 │ 1.51545 │ 61.8302 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 61.8302 max: 890 mean: 412.958 (8 pts sampled)
──────────────────────────────────────────────── Iteration 9 / 10 ─────────────────────────────────────────────────
Acquire UID d964e31f-d99c-4a24-981a-e035e1cecebd
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 8 │ 1.51545 │ 1.51545 │ 61.8302 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 61.8302 max: 890 mean: 373.943 (9 pts sampled)
──────────────────────────────────────────────── Iteration 10 / 10 ────────────────────────────────────────────────
Acquire UID 027d2d0f-60bb-4d9e-854b-db07d101562b
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 9 │ 3.25772 │ 3.25772 │ 55.4432 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 55.4432 max: 890 mean: 342.093 (10 pts sampled)
Summary Statistics ┏━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━┓ ┃ Name ┃ Type ┃ Min ┃ Max ┃ Mean ┃ Std ┃ Count ┃ ┡━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━┩ │ x1 │ param │ 0 │ 5 │ 2.28041 │ 2.12132 │ 10 │ │ x2 │ param │ 0 │ 5 │ 2.28041 │ 2.12132 │ 10 │ │ himmelblau_2d │ outcome │ 55.4432 │ 890 │ 342.093 │ 381.119 │ 10 │ └───────────────┴─────────┴─────────┴─────┴─────────┴─────────┴───────┘
────────────────────────────────────────────── Optimization Complete ──────────────────────────────────────────────
('afb6261d-8c36-476d-bdf1-64a7401f3b7a',
'fb5af019-9918-4c36-b903-61f227768dc8',
'a0eafc42-52eb-4294-9f77-509d37ccda1a',
'e791f3bb-3d4c-4638-8869-0c586cd55e0d',
'0d67c43d-1380-4fa2-ab93-efa73762ea15',
'eff94fae-a1ac-48a4-9f12-524c2fce1872',
'038e33d0-f141-4a4f-bc5b-3248c9d88347',
'd92a02f0-8300-4491-b01e-123b24419665',
'285f5a14-5bd7-490e-8468-7913a5f0a5c0',
'd964e31f-d99c-4a24-981a-e035e1cecebd',
'027d2d0f-60bb-4d9e-854b-db07d101562b')
Configuring the optimization#
Sometimes a default Agent optimization may not do all that you’d like. We expose a configuration object called ScipyCFG and a pure scipy interface so that the classic parameters of scipy minimize can be tweaked (and some multipoint sampling can be used).
config = ScipyCFG(dofs=dofs, objective=objectives[0], optimizer=SCP.DUAL_ANNEALING, threads=4, max_iter=2, eps=0.1)
agent = Scipy(
sensors=sensors,
config=config,
evaluation_function=Himmelblau2DEvaluation(tiled_client=tiled_client),
name="test_experiment",
)
res_uid = RE(agent.optimize(20, n_points=2))
╭───────────────────────────────────────────────── Optimization ──────────────────────────────────────────────────╮ │ Optimizer InteractiveOptimizer │ │ Actuators x1, x2 │ │ Sensors N/A │ │ Iterations 20 Points/iter 2 │ │ Run UID 0ae83a41-10c8-4f8f-bb42-f25c1cf81107 │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
[Himmelblau] evaluating suggestions:
[0]
reordered to:
[0]
[Himmelblau] evaluating suggestions:
[1]
reordered to:
[1]
[Himmelblau] evaluating suggestions:
[2]
reordered to:
[2]
[Himmelblau] evaluating suggestions:
[3]
reordered to:
[3]
[Himmelblau] evaluating suggestions:
[4]
reordered to:
[4]
[Himmelblau] evaluating suggestions:
[5]
reordered to:
[5]
[Himmelblau] evaluating suggestions:
[6, 7]
reordered to:
[6, 7]
[Himmelblau] evaluating suggestions:
[8]
reordered to:
[8]
[Himmelblau] evaluating suggestions:
[9, 10]
reordered to:
[9, 10]
[Himmelblau] evaluating suggestions:
[11]
reordered to:
[11]
[Himmelblau] evaluating suggestions:
[12, 13]
reordered to:
[13, 12]
[Himmelblau] evaluating suggestions:
[14]
reordered to:
[14]
[Himmelblau] evaluating suggestions:
[15, 16]
reordered to:
[15, 16]
[Himmelblau] evaluating suggestions:
[17]
reordered to:
[17]
[Himmelblau] evaluating suggestions:
[18, 19]
reordered to:
[18, 19]
[Himmelblau] evaluating suggestions:
[20]
reordered to:
[20]
[Himmelblau] evaluating suggestions:
[21, 22]
reordered to:
[21, 22]
[Himmelblau] evaluating suggestions:
[23]
reordered to:
[23]
[Himmelblau] evaluating suggestions:
[24, 25]
reordered to:
[25, 24]
[Himmelblau] evaluating suggestions:
[26]
reordered to:
[26]
──────────────────────────────────────────────── Iteration 1 / 20 ─────────────────────────────────────────────────
Acquire UID 90c16f39-1638-47c3-81a7-74d4a56382d8
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━┳━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━╇━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 0 │ 0 │ 0 │ 170 │ └───────┴───────────────┴────┴────┴───────────────┘
himmelblau_2d min: 170 max: 170 mean: 170 (1 pts sampled)
──────────────────────────────────────────────── Iteration 2 / 20 ─────────────────────────────────────────────────
Acquire UID df3976e0-284a-4fec-8406-a4d974aea060
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 1 │ 2.53419 │ 2.53419 │ 8.00382 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 8.00382 max: 170 mean: 89.0019 (2 pts sampled)
──────────────────────────────────────────────── Iteration 3 / 20 ─────────────────────────────────────────────────
Acquire UID 04f90002-c3a3-4bba-a3a6-ab483a5b2f6d
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 2 │ -3.85909 │ -1.68838 │ 68.9938 │ └───────┴───────────────┴──────────┴──────────┴───────────────┘
himmelblau_2d min: 8.00382 max: 170 mean: 82.3325 (3 pts sampled)
──────────────────────────────────────────────── Iteration 4 / 20 ─────────────────────────────────────────────────
Acquire UID f6f17f27-7518-40cd-8776-9103bb9fb100
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 3 │ 2.35455 │ -1.68838 │ 54.2647 │ └───────┴───────────────┴─────────┴──────────┴───────────────┘
himmelblau_2d min: 8.00382 max: 170 mean: 75.3156 (4 pts sampled)
/home/runner/work/blop/blop/.pixi/envs/docs/lib/python3.13/site-packages/scipy/optimize/_dual_annealing.py:434: OptimizeWarning: Unknown solver options: max_iter
mres = self.minimizer(self.func_wrapper.fun, x, **self.kwargs)
──────────────────────────────────────────────── Iteration 5 / 20 ─────────────────────────────────────────────────
Acquire UID b553f3c6-eb99-455e-9d95-d2582f5696ea
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 4 │ 2.35455 │ 0.277822 │ 47.6834 │ └───────┴───────────────┴─────────┴──────────┴───────────────┘
himmelblau_2d min: 8.00382 max: 170 mean: 69.7891 (5 pts sampled)
──────────────────────────────────────────────── Iteration 6 / 20 ─────────────────────────────────────────────────
Acquire UID 57fac794-95e1-491f-a103-b81493b04b7b
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 5 │ 2.53419 │ 2.53419 │ 8.00382 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 8.00382 max: 170 mean: 59.4916 (6 pts sampled)
────────────────────────────────────────── Iteration 7 / 20 (2 points) ───────────────────────────────────────────
Acquire UID 0641c89d-740f-4fa0-87d4-d9f62981240c
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 6 │ 2.63419 │ 2.53419 │ 6.55967 │ │ 1 │ 7 │ 2.53419 │ 2.63419 │ 9.89436 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 6.55967 max: 170 mean: 46.6754 (8 pts sampled)
──────────────────────────────────────────────── Iteration 8 / 20 ─────────────────────────────────────────────────
Acquire UID afd72c0d-8ef2-478c-aa4b-8f4519f30934
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━┳━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━╇━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 8 │ 5 │ -5 │ 610 │ └───────┴───────────────┴────┴────┴───────────────┘
himmelblau_2d min: 6.55967 max: 610 mean: 109.267 (9 pts sampled)
────────────────────────────────────────── Iteration 9 / 20 (2 points) ───────────────────────────────────────────
Acquire UID 3db999c2-4b7f-4814-b728-2ff3ec6cf4eb
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━╇━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 10 │ 4.9 │ -5 │ 588.57 │ │ 1 │ 9 │ 5 │ -4.9 │ 567.25 │ └───────┴───────────────┴─────┴──────┴───────────────┘
himmelblau_2d min: 6.55967 max: 610 mean: 194.475 (11 pts sampled)
──────────────────────────────────────────────── Iteration 10 / 20 ────────────────────────────────────────────────
Acquire UID 534fc451-f846-4bb3-97dc-5bc42b38d5d8
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 11 │ 3.28813 │ 0.230532 │ 13.388 │ └───────┴───────────────┴─────────┴──────────┴───────────────┘
himmelblau_2d min: 6.55967 max: 610 mean: 179.384 (12 pts sampled)
────────────────────────────────────────── Iteration 11 / 20 (2 points) ──────────────────────────────────────────
Acquire UID 4d08a73d-32fa-4797-8b90-1ff5ffb3a463
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 12 │ 3.28813 │ 0.330532 │ 12.9991 │ │ 1 │ 13 │ 3.38813 │ 0.230532 │ 13.1686 │ └───────┴───────────────┴─────────┴──────────┴───────────────┘
himmelblau_2d min: 6.55967 max: 610 mean: 155.627 (14 pts sampled)
──────────────────────────────────────────────── Iteration 12 / 20 ────────────────────────────────────────────────
Acquire UID ee73acd1-9c6b-43e4-8450-82c41c296b87
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 14 │ 2.75716 │ 1.85291 │ 3.04297 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 3.04297 max: 610 mean: 145.455 (15 pts sampled)
────────────────────────────────────────── Iteration 13 / 20 (2 points) ──────────────────────────────────────────
Acquire UID ec1140a7-0146-42d1-b0bf-914addcf8af3
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 15 │ 2.75716 │ 1.95291 │ 2.27256 │ │ 1 │ 16 │ 2.85716 │ 1.85291 │ 1.47124 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 1.47124 max: 610 mean: 128.563 (17 pts sampled)
──────────────────────────────────────────────── Iteration 14 / 20 ────────────────────────────────────────────────
Acquire UID dc268829-bcdb-4cf4-ae79-11b65f91ebb4
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 17 │ 3.17632 │ 1.89836 │ 1.02331 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 1.02331 max: 610 mean: 121.477 (18 pts sampled)
────────────────────────────────────────── Iteration 15 / 20 (2 points) ──────────────────────────────────────────
Acquire UID a630f2d2-d886-4642-983b-fc9699675752
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 18 │ 3.27632 │ 1.89836 │ 2.67996 │ │ 1 │ 19 │ 3.17632 │ 1.99836 │ 1.21125 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 1.02331 max: 610 mean: 109.524 (20 pts sampled)
──────────────────────────────────────────────── Iteration 16 / 20 ────────────────────────────────────────────────
Acquire UID bd5c6fcc-3b0b-498b-a9e6-501f656519cf
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 20 │ 2.96537 │ 1.87549 │ 0.377091 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 0.377091 max: 610 mean: 104.327 (21 pts sampled)
────────────────────────────────────────── Iteration 17 / 20 (2 points) ──────────────────────────────────────────
Acquire UID 89446ba6-f7aa-4e4e-87b0-8df503d62033
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 21 │ 2.96537 │ 1.97549 │ 0.070846 │ │ 1 │ 22 │ 3.06537 │ 1.87549 │ 0.248015 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 0.070846 max: 610 mean: 95.2686 (23 pts sampled)
──────────────────────────────────────────────── Iteration 18 / 20 ────────────────────────────────────────────────
Acquire UID aa919146-f17e-4579-be8d-c3f9dcecde38
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 23 │ 2.96552 │ 1.94781 │ 0.124337 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 0.070846 max: 610 mean: 91.3042 (24 pts sampled)
────────────────────────────────────────── Iteration 19 / 20 (2 points) ──────────────────────────────────────────
Acquire UID f1aa60fb-f851-459d-a366-6af2c7421fcf
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 24 │ 2.96552 │ 2.04781 │ 0.0502168 │ │ 1 │ 25 │ 3.06552 │ 1.94781 │ 0.138937 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 0.0502168 max: 610 mean: 84.2881 (26 pts sampled)
──────────────────────────────────────────────── Iteration 20 / 20 ────────────────────────────────────────────────
Acquire UID 0ebbea11-fba4-4308-87b3-60d6eb4a8800
┏━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Event ┃ Suggestion ID ┃ x1 ┃ x2 ┃ himmelblau_2d ┃ ┡━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ 0 │ 26 │ 2.95548 │ 1.97711 │ 0.101337 │ └───────┴───────────────┴─────────┴─────────┴───────────────┘
himmelblau_2d min: 0.0502168 max: 610 mean: 81.1701 (27 pts sampled)
Summary Statistics ┏━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━┳━━━━━━━┓ ┃ Name ┃ Type ┃ Min ┃ Max ┃ Mean ┃ Std ┃ Count ┃ ┡━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━╇━━━━━━━┩ │ x1 │ param │ -3.85909 │ 5 │ 2.77407 │ 1.62322 │ 27 │ │ x2 │ param │ -5 │ 2.63419 │ 0.67149 │ 2.34147 │ 27 │ │ himmelblau_2d │ outcome │ 0.0502168 │ 610 │ 81.1701 │ 186.268 │ 27 │ └───────────────┴─────────┴───────────┴─────────┴─────────┴─────────┴───────┘
────────────────────────────────────────────── Optimization Complete ──────────────────────────────────────────────
Viewing the results#
Scipy is a local optimizer so it doesn’t have internal point tracking, but we can to grab it from our datastore.
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
res_client = tiled_client[res_uid[0]]
data = res_client["primary/internal"].read()
cols = ["suggestion_ids", "x1", "x2", "himmelblau_2d"]
vec = data[cols]
res = []
for _, row in vec.iterrows():
vic = [row.suggestion_ids, row.x1, row.x2, row.himmelblau_2d]
vic = [x.strip("[]").split() for x in vic]
for id, x, y, obj in zip(*vic, strict=True):
if id != "''":
res.append([int(id.strip("'")), float(x), float(y), float(obj)])
res = np.array(res)
fig, ax = plt.subplots(figsize=(12, 8))
xb, yb = np.random.uniform(-5, 5, (2, 1000))
ax.tripcolor(xb, yb, (xb**2 + yb - 11) ** 2 + (xb + yb**2 - 7) ** 2, shading="gouraud")
i, x, y, z = res.T
ps = ax.scatter(x, y, c=range(len(x)), cmap="plasma", s=50)
plt.colorbar(ps).set_label("sample index")
plt.title("Visualizing Scipy's traversal of Himmelblau")
Seeing the sample history
pd.DataFrame(data=res, columns=cols)
| suggestion_ids | x1 | x2 | himmelblau_2d | |
|---|---|---|---|---|
| 0 | 0.0 | 0.000000 | 0.000000 | 170.000000 |
| 1 | 1.0 | 2.534186 | 2.534186 | 8.003822 |
| 2 | 2.0 | -3.859086 | -1.688380 | 68.993793 |
| 3 | 3.0 | 2.354553 | -1.688380 | 54.264720 |
| 4 | 4.0 | 2.354553 | 0.277822 | 47.683403 |
| 5 | 5.0 | 2.534186 | 2.534186 | 8.003822 |
| 6 | 6.0 | 2.634186 | 2.534186 | 6.559665 |
| 7 | 7.0 | 2.534186 | 2.634186 | 9.894364 |
| 8 | 8.0 | 5.000000 | -5.000000 | 610.000000 |
| 9 | 10.0 | 4.900000 | -5.000000 | 588.570100 |
| 10 | 9.0 | 5.000000 | -4.900000 | 567.250100 |
| 11 | 11.0 | 3.288134 | 0.230532 | 13.388033 |
| 12 | 12.0 | 3.288134 | 0.330532 | 12.999098 |
| 13 | 13.0 | 3.388134 | 0.230532 | 13.168573 |
| 14 | 14.0 | 2.757156 | 1.852911 | 3.042967 |
| 15 | 15.0 | 2.757156 | 1.952911 | 2.272564 |
| 16 | 16.0 | 2.857156 | 1.852911 | 1.471237 |
| 17 | 17.0 | 3.176324 | 1.898359 | 1.023310 |
| 18 | 18.0 | 3.276324 | 1.898359 | 2.679958 |
| 19 | 19.0 | 3.176324 | 1.998359 | 1.211248 |
| 20 | 20.0 | 2.965371 | 1.875487 | 0.377091 |
| 21 | 21.0 | 2.965371 | 1.975487 | 0.070846 |
| 22 | 22.0 | 3.065371 | 1.875487 | 0.248015 |
| 23 | 23.0 | 2.965524 | 1.947810 | 0.124337 |
| 24 | 24.0 | 2.965524 | 2.047810 | 0.050217 |
| 25 | 25.0 | 3.065524 | 1.947810 | 0.138937 |
| 26 | 26.0 | 2.955479 | 1.977112 | 0.101337 |
print(agent.get_best_points())
[25, {'x1': np.float64(2.955478799181076), 'x2': np.float64(1.9771119825989758)}, {'himmelblau_2d': np.float64(0.12433745597668064)}]
The Himmelblau function has four global minima (all with value 0). The summarize output shows which one(s) the optimizer found.
What you learned#
You now understand the three core concepts of Blop:
DOFs: The parameters the optimizer adjusts (here,
x1andx2with bounds)Objectives: What you’re optimizing (here, minimizing the Himmelblau function)
Agent: Coordinates the optimization loop between Bluesky and the evaluation function
Next steps#
For a more comprehensive tutorial with multiple objectives and diagnostic tools, see Optimizing KB Mirrors.