Feasibility modeling#

A more complicated example involves minimizing in two dimensions, where some parts of the parameter space are off-limits. Let’s minimize Himmelblau’s function, subject to the constraint that \(x_1^2 + x_2^2 < 50\)

[1]:
import numpy as np
import matplotlib as mpl
from matplotlib import pyplot as plt
from bloptools import test_functions

x1 = x2 = np.linspace(-8, 8, 256)
X1, X2 = np.meshgrid(x1, x2)
from bloptools.tasks import Task

task = Task(key="himmelblau", kind="min")
F = test_functions.constrained_himmelblau(X1, X2)

plt.pcolormesh(x1, x2, F, norm=mpl.colors.LogNorm(), shading="auto")
plt.colorbar()
plt.xlabel("x1")
plt.ylabel("x2")
[1]:
Text(0, 0.5, 'x2')
../_images/tutorials_constrained-himmelblau_2_1.png

where everything outside our constraint is undefined. In our digestion function, we return a NaN when we violate the constraint:

[2]:
def digestion(db, uid):
    products = db[uid].table()

    for index, entry in products.iterrows():
        products.loc[index, "himmelblau"] = test_functions.constrained_himmelblau(entry.x1, entry.x2)

    return products

and create the agent in the usual way:

[3]:
%run -i ../../../examples/prepare_bluesky.py # prepare the bluesky environment

from bloptools import devices
from bloptools.bayesian import Agent

dofs = [
    {"device": devices.DOF(name="x1"), "limits": (-8, 8), "kind": "active"},
    {"device": devices.DOF(name="x2"), "limits": (-8, 8), "kind": "active"},
]

tasks = [
    {"key": "himmelblau", "kind": "minimize"},
]

agent = Agent(
    dofs=dofs,
    tasks=tasks,
    digestion=digestion,
    db=db,
)

RE(agent.initialize("qr", n_init=64))

agent.plot_tasks()


Transient Scan ID: 1     Time: 2023-08-11 05:54:12
Persistent Unique Scan ID: '28a13d88-cb29-4b2f-9d50-8bcfab116275'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:12.7 |      4.615 |     -6.168 |
|         2 | 05:54:12.7 |     -4.988 |      3.077 |
|         3 | 05:54:12.7 |     -3.109 |     -0.170 |
|         4 | 05:54:12.7 |      3.490 |      5.077 |
|         5 | 05:54:12.7 |      1.262 |     -3.447 |
|         6 | 05:54:12.7 |     -1.134 |      6.292 |
|         7 | 05:54:12.7 |     -6.761 |     -5.446 |
|         8 | 05:54:12.7 |      6.640 |      0.292 |
|         9 | 05:54:12.8 |      7.733 |     -1.903 |
|        10 | 05:54:12.8 |     -7.855 |      4.874 |
|        11 | 05:54:12.8 |     -0.227 |     -7.904 |
|        12 | 05:54:12.8 |      0.356 |      2.874 |
|        13 | 05:54:12.8 |      2.395 |     -4.744 |
|        14 | 05:54:12.8 |     -2.017 |      1.526 |
|        15 | 05:54:12.8 |     -5.893 |     -2.743 |
|        16 | 05:54:12.8 |      5.523 |      7.527 |
|        17 | 05:54:12.8 |      5.045 |     -2.382 |
|        18 | 05:54:12.8 |     -5.418 |      7.349 |
|        19 | 05:54:12.8 |     -2.539 |     -4.382 |
|        20 | 05:54:12.8 |      2.919 |      1.348 |
|        21 | 05:54:12.8 |      0.833 |     -7.222 |
|        22 | 05:54:12.8 |     -0.704 |      2.000 |
|        23 | 05:54:12.8 |     -7.331 |     -1.222 |
|        24 | 05:54:12.8 |      7.210 |      4.002 |
|        25 | 05:54:12.8 |      6.178 |     -5.678 |
|        26 | 05:54:12.8 |     -6.300 |      0.584 |
|        27 | 05:54:12.8 |     -1.672 |     -3.679 |
|        28 | 05:54:12.8 |      1.802 |      6.582 |
|        29 | 05:54:12.8 |      3.949 |     -0.957 |
|        30 | 05:54:12.8 |     -3.572 |      5.797 |
|        31 | 05:54:12.8 |     -4.448 |     -6.956 |
|        32 | 05:54:12.8 |      4.078 |      3.799 |
|        33 | 05:54:12.8 |      4.428 |     -0.400 |
|        34 | 05:54:12.8 |     -4.050 |      5.370 |
|        35 | 05:54:12.8 |     -3.923 |     -6.399 |
|        36 | 05:54:12.8 |      3.552 |      3.371 |
|        37 | 05:54:12.8 |      1.700 |     -5.246 |
|        38 | 05:54:12.8 |     -1.822 |      0.031 |
|        39 | 05:54:12.9 |     -6.197 |     -3.248 |
|        40 | 05:54:12.9 |      6.328 |      6.030 |
|        41 | 05:54:12.9 |      7.295 |     -7.666 |
|        42 | 05:54:12.9 |     -7.168 |      2.573 |
|        43 | 05:54:12.9 |     -0.789 |     -1.665 |
|        44 | 05:54:12.9 |      0.670 |      4.573 |
|        45 | 05:54:12.9 |      2.583 |     -2.949 |
|        46 | 05:54:12.9 |     -2.954 |      7.796 |
|        47 | 05:54:12.9 |     -5.081 |     -4.951 |
|        48 | 05:54:12.9 |      5.460 |      1.796 |
|        49 | 05:54:12.9 |      5.983 |     -4.175 |
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|        50 | 05:54:12.9 |     -5.605 |      1.079 |
|        51 | 05:54:12.9 |     -2.477 |     -2.175 |
|        52 | 05:54:12.9 |      2.107 |      7.080 |
|        53 | 05:54:12.9 |      0.145 |     -1.460 |
|        54 | 05:54:12.9 |     -0.267 |      4.302 |
|        55 | 05:54:12.9 |     -7.643 |     -7.460 |
|        56 | 05:54:12.9 |      7.773 |      2.301 |
|        57 | 05:54:12.9 |      6.865 |     -3.878 |
|        58 | 05:54:12.9 |     -6.738 |      6.844 |
|        59 | 05:54:12.9 |     -1.360 |     -5.878 |
|        60 | 05:54:12.9 |      1.240 |      0.846 |
|        61 | 05:54:12.9 |      3.013 |     -6.725 |
|        62 | 05:54:12.9 |     -3.384 |      3.506 |
|        63 | 05:54:12.9 |     -4.510 |     -0.726 |
|        64 | 05:54:12.9 |      4.890 |      5.504 |
+-----------+------------+------------+------------+
generator list_scan ['28a13d88'] (scan num: 1)



../_images/tutorials_constrained-himmelblau_6_1.png

In addition to modeling the fitness of the task, the agent models the probability that an input will be feasible:

[4]:
agent.plot_feasibility()
../_images/tutorials_constrained-himmelblau_8_0.png

It combines the estimate of the objective and the estimate of the feasibility in deciding where to go:

[5]:
agent.plot_acquisition(acq_func=["ei", "pi", "ucb"])
../_images/tutorials_constrained-himmelblau_10_0.png
[6]:
RE(agent.learn("ei", n_per_iter=4))


Transient Scan ID: 2     Time: 2023-08-11 05:54:18
Persistent Unique Scan ID: '690bbbf0-5ece-4e44-879d-8876903d023c'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:18.3 |      2.393 |      2.587 |
|         2 | 05:54:18.3 |     -2.336 |      3.083 |
|         3 | 05:54:18.3 |     -2.886 |      2.681 |
|         4 | 05:54:18.3 |     -3.845 |     -2.566 |
+-----------+------------+------------+------------+
generator list_scan ['690bbbf0'] (scan num: 2)



[6]:
('690bbbf0-5ece-4e44-879d-8876903d023c',)

The agent automatically tries to avoid infeasible points, but will end up naturally exploring the boundary of the constraint. Let’s see where the agent is thinking of going:

[7]:
agent.plot_tasks()
agent.plot_acquisition(strategy=["ei", "pi", "ucb"])
../_images/tutorials_constrained-himmelblau_13_0.png
../_images/tutorials_constrained-himmelblau_13_1.png

The agent will naturally explore the whole parameter space

[8]:
RE(agent.learn("ei", n_iter=16))
agent.plot_tasks()


Transient Scan ID: 3     Time: 2023-08-11 05:54:21
Persistent Unique Scan ID: '47d8f47f-1b07-4371-8868-806377508218'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:21.5 |      3.376 |      0.150 |
+-----------+------------+------------+------------+
generator list_scan ['47d8f47f'] (scan num: 3)





Transient Scan ID: 4     Time: 2023-08-11 05:54:22
Persistent Unique Scan ID: '61f3e362-c16e-45d9-9460-93ca633ce219'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:22.4 |     -3.170 |     -3.457 |
+-----------+------------+------------+------------+
generator list_scan ['61f3e362'] (scan num: 4)





Transient Scan ID: 5     Time: 2023-08-11 05:54:23
Persistent Unique Scan ID: 'be2de37f-59a7-49fe-a6df-b46219252303'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:23.2 |      3.857 |     -1.710 |
+-----------+------------+------------+------------+
generator list_scan ['be2de37f'] (scan num: 5)





Transient Scan ID: 6     Time: 2023-08-11 05:54:24
Persistent Unique Scan ID: '388de2b1-e20c-42ac-a670-53f65fabf3b8'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:24.1 |      3.280 |      2.016 |
+-----------+------------+------------+------------+
generator list_scan ['388de2b1'] (scan num: 6)





Transient Scan ID: 7     Time: 2023-08-11 05:54:25
Persistent Unique Scan ID: 'ff51fbec-0cca-4caa-bc9f-4b9ad890079d'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:25.1 |      3.125 |     -2.246 |
+-----------+------------+------------+------------+
generator list_scan ['ff51fbec'] (scan num: 7)





Transient Scan ID: 8     Time: 2023-08-11 05:54:26
Persistent Unique Scan ID: '824ffca6-aced-49ee-b8eb-0442806e8bd8'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:26.0 |      3.899 |     -2.696 |
+-----------+------------+------------+------------+
generator list_scan ['824ffca6'] (scan num: 8)





Transient Scan ID: 9     Time: 2023-08-11 05:54:26
Persistent Unique Scan ID: '2c63f650-8368-4cc0-80c7-d79fe79f4e46'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:26.8 |     -2.581 |      3.735 |
+-----------+------------+------------+------------+
generator list_scan ['2c63f650'] (scan num: 9)





Transient Scan ID: 10     Time: 2023-08-11 05:54:27
Persistent Unique Scan ID: 'c44c6c1b-07d4-42b2-8e0c-fce59116c5de'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:27.8 |     -4.231 |     -3.395 |
+-----------+------------+------------+------------+
generator list_scan ['c44c6c1b'] (scan num: 10)





Transient Scan ID: 11     Time: 2023-08-11 05:54:28
Persistent Unique Scan ID: '8e64a5da-4462-4c8b-a2c3-7109081b394a'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:28.6 |      3.464 |      1.315 |
+-----------+------------+------------+------------+
generator list_scan ['8e64a5da'] (scan num: 11)





Transient Scan ID: 12     Time: 2023-08-11 05:54:29
Persistent Unique Scan ID: 'ad20ba6f-ba4e-4711-aae5-7ae9af21938c'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:29.7 |     -2.969 |      3.077 |
+-----------+------------+------------+------------+
generator list_scan ['ad20ba6f'] (scan num: 12)





Transient Scan ID: 13     Time: 2023-08-11 05:54:30
Persistent Unique Scan ID: '9d30d1cb-2573-43b6-ba79-0647d2f78ce4'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:30.5 |      3.650 |     -2.133 |
+-----------+------------+------------+------------+
generator list_scan ['9d30d1cb'] (scan num: 13)





Transient Scan ID: 14     Time: 2023-08-11 05:54:31
Persistent Unique Scan ID: '42e27d0d-2f52-4316-8064-17937a52b9a5'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:31.5 |      3.564 |     -2.076 |
+-----------+------------+------------+------------+
generator list_scan ['42e27d0d'] (scan num: 14)





Transient Scan ID: 15     Time: 2023-08-11 05:54:32
Persistent Unique Scan ID: '63764d21-6b9b-401a-b303-d57e0bb3425c'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:32.2 |      3.418 |     -1.146 |
+-----------+------------+------------+------------+
generator list_scan ['63764d21'] (scan num: 15)





Transient Scan ID: 16     Time: 2023-08-11 05:54:33
Persistent Unique Scan ID: '21eaa49a-7826-4cd0-b5aa-e2433381eddc'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:33.3 |     -2.979 |      2.947 |
+-----------+------------+------------+------------+
generator list_scan ['21eaa49a'] (scan num: 16)





Transient Scan ID: 17     Time: 2023-08-11 05:54:34
Persistent Unique Scan ID: '8c16ab5c-3b87-4afb-b0c3-c5a3068e45ca'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:34.2 |      2.809 |      2.189 |
+-----------+------------+------------+------------+
generator list_scan ['8c16ab5c'] (scan num: 17)





Transient Scan ID: 18     Time: 2023-08-11 05:54:35
Persistent Unique Scan ID: '7f23be5a-82d5-4ae4-9bfa-d408b556f211'
New stream: 'primary'
+-----------+------------+------------+------------+
|   seq_num |       time |         x1 |         x2 |
+-----------+------------+------------+------------+
|         1 | 05:54:35.4 |      3.592 |     -1.757 |
+-----------+------------+------------+------------+
generator list_scan ['7f23be5a'] (scan num: 18)



../_images/tutorials_constrained-himmelblau_15_1.png