Skip to content

Commit f692d04

Browse files
authored
Merge pull request #383 from bwheelz36/update_simple_contraints_docs
Update simple contraints docs
2 parents 8ed5a37 + 9263e07 commit f692d04

File tree

3 files changed

+149
-4
lines changed

3 files changed

+149
-4
lines changed

.github/workflows/run_tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
runs-on: ubuntu-latest
2020
strategy:
2121
matrix:
22-
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
22+
python-version: ["3.7", "3.8", "3.9", "3.10"]
2323

2424
steps:
2525
- uses: actions/checkout@v3

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,5 @@ env/
2727
venv/
2828
ENV/
2929
env.bak/
30-
venv.bak/
30+
venv.bak/
31+
*temp*

examples/constraints.ipynb

Lines changed: 146 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,149 @@
11
{
22
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Constrained Optimization\n",
8+
"\n",
9+
"Constrained optimization refers to situations in which you must for instance maximize `f`, a function of `x` and `y`, but the solution must lie in a region where for instance `x<y`.\n",
10+
"\n",
11+
"There are two distinct situations you may find yourself in:\n",
12+
"\n",
13+
"1. Simple, cheap contraints: in this case, you know whether or not a given solution violates your constraints **before** you even assess it. In this case, you can codify your constraints directly into the objective function and you should read **1** below.\n",
14+
"2. Expensive contraints - in other situations, you may not know whether or not a given solution violates your constraints until you have explicitly evaluate the objective function there - which is typically an expensive operation. In such situations, it is desirable to **learn** the constrained regions on the fly in order to avoid unnecessary expensive calls to the objective function. The way to handle these situations is descrived in **2. Advanced Constrained Optimization**\n",
15+
"\n",
16+
"\n",
17+
"# 1. Simple Constrained Optimization\n",
18+
"\n",
19+
"In situations where you know in advance whether or not a given point violates your constraints, you can normally simply code them directly into the objective function. To demonstrate this, let's start with a standart non-contrained optimziation:"
20+
]
21+
},
22+
{
23+
"cell_type": "code",
24+
"execution_count": 14,
25+
"metadata": {},
26+
"outputs": [
27+
{
28+
"name": "stdout",
29+
"output_type": "stream",
30+
"text": [
31+
"the best solution with no constraints is {'target': -3.0000001251185324, 'params': {'x': 2.0, 'y': 0.9996462790185919}}\n"
32+
]
33+
}
34+
],
35+
"source": [
36+
"from bayes_opt import BayesianOptimization\n",
37+
"\n",
38+
"def black_box_function_no_constraints(x, y):\n",
39+
" return -x ** 2 - (y - 1) ** 2 + 1\n",
40+
"\n",
41+
"# Bounded region of parameter space\n",
42+
"pbounds = {'x': (2, 4), 'y': (-3, 3)}\n",
43+
"\n",
44+
"optimizer = BayesianOptimization(\n",
45+
" f=black_box_function_no_constraints,\n",
46+
" pbounds=pbounds,\n",
47+
" random_state=0,\n",
48+
" verbose=0\n",
49+
")\n",
50+
"\n",
51+
"optimizer.maximize(\n",
52+
" init_points=2,\n",
53+
" n_iter=100\n",
54+
")\n",
55+
"\n",
56+
"print(f'the best solution with no constraints is {optimizer.max}')"
57+
]
58+
},
59+
{
60+
"cell_type": "markdown",
61+
"metadata": {},
62+
"source": [
63+
"Now, let's rerun this example, except with the constraint that y>x. To do this, we are simply going to return a 'bad' value from the objective function whenever this constrain is violated. What constitutes a 'bad' value is objective function specific - in general, it's a good idea for the 'bad' value you use to be similar in magnitude to the worst value that the objective function naturally has."
64+
]
65+
},
66+
{
67+
"cell_type": "code",
68+
"execution_count": 15,
69+
"metadata": {},
70+
"outputs": [
71+
{
72+
"name": "stdout",
73+
"output_type": "stream",
74+
"text": [
75+
"the best solution with no constraints is {'target': -4.226389709162731, 'params': {'x': 2.0042130207949307, 'y': 2.099781740364328}}\n"
76+
]
77+
}
78+
],
79+
"source": [
80+
"def black_box_function_with_constraints(x, y):\n",
81+
" if y <= x:\n",
82+
" return -10\n",
83+
" else:\n",
84+
" return -x ** 2 - (y - 1) ** 2 + 1\n",
85+
" \n",
86+
"optimizer = BayesianOptimization(\n",
87+
" f=black_box_function_with_constraints,\n",
88+
" pbounds=pbounds,\n",
89+
" random_state=0,\n",
90+
" verbose=0\n",
91+
")\n",
92+
"\n",
93+
"optimizer.maximize(\n",
94+
" init_points=2,\n",
95+
" n_iter=100\n",
96+
")\n",
97+
"\n",
98+
"print(f'the best solution with no constraints is {optimizer.max}')"
99+
]
100+
},
101+
{
102+
"cell_type": "markdown",
103+
"metadata": {},
104+
"source": [
105+
"Ok, this seems to have worked pretty well; our constraints have been respected and the target value isn't even **that** much worse!\n",
106+
"\n",
107+
"In certain other cases, you may be able to reformulate your objective function such that the constraint is explicitly embedded. For instance, consider the constraint `x+y=4`. Since this implies that `y=4-x`, we could simply reformulate the objective function explicitly:"
108+
]
109+
},
110+
{
111+
"cell_type": "code",
112+
"execution_count": 12,
113+
"metadata": {},
114+
"outputs": [
115+
{
116+
"name": "stdout",
117+
"output_type": "stream",
118+
"text": [
119+
"the best solution with no constraints is {'target': -4.0, 'params': {'x': 2.0}}\n"
120+
]
121+
}
122+
],
123+
"source": [
124+
"def surrogate_objective(x):\n",
125+
" y=4-x\n",
126+
" return black_box_function_no_constraints(x,y)\n",
127+
"\n",
128+
"pbounds = {'x': (2, 4)}\n",
129+
"# note that in general, we would have to update pbounds such that the values that x were allowed to take on\n",
130+
"# respected the bounds of y. In this case (4-4=0)<=y<=(4-2=2) already respect our original bounds -3<=y<=3\n",
131+
"\n",
132+
"optimizer = BayesianOptimization(\n",
133+
" f=surrogate_objective,\n",
134+
" pbounds=pbounds,\n",
135+
" random_state=0,\n",
136+
" verbose=0\n",
137+
")\n",
138+
"\n",
139+
"optimizer.maximize(\n",
140+
" init_points=2,\n",
141+
" n_iter=100\n",
142+
")\n",
143+
"\n",
144+
"print(f'the best solution with no constraints is {optimizer.max}')"
145+
]
146+
},
3147
{
4148
"cell_type": "markdown",
5149
"metadata": {},
@@ -459,7 +603,7 @@
459603
],
460604
"metadata": {
461605
"kernelspec": {
462-
"display_name": "Python 3.8.9 ('bopt')",
606+
"display_name": "Python 3 (ipykernel)",
463607
"language": "python",
464608
"name": "python3"
465609
},
@@ -473,7 +617,7 @@
473617
"name": "python",
474618
"nbconvert_exporter": "python",
475619
"pygments_lexer": "ipython3",
476-
"version": "3.8.9"
620+
"version": "3.9.5"
477621
},
478622
"vscode": {
479623
"interpreter": {

0 commit comments

Comments
 (0)