Skip to content

Commit 4e88bd8

Browse files
0.34.11
1 parent eee0a40 commit 4e88bd8

6 files changed

Lines changed: 313 additions & 7 deletions

File tree

notebooks/spot_aquisition_random_rosenbrock_2d.ipynb

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,119 @@
197197
"source": [
198198
"spot_exact_mm.plot_important_hyperparameter_contour(max_imp=3)"
199199
]
200+
},
201+
{
202+
"cell_type": "code",
203+
"execution_count": 1,
204+
"metadata": {},
205+
"outputs": [
206+
{
207+
"name": "stderr",
208+
"output_type": "stream",
209+
"text": [
210+
"Seed set to 123\n",
211+
"Seed set to 123\n"
212+
]
213+
},
214+
{
215+
"name": "stdout",
216+
"output_type": "stream",
217+
"text": [
218+
"S.X: [[ 0.86352963 0.7892358 ]\n",
219+
" [-0.24407197 -0.83687436]\n",
220+
" [ 0.36481882 0.8375811 ]\n",
221+
" [ 0.415331 0.54468512]\n",
222+
" [-0.56395091 -0.77797854]\n",
223+
" [-0.90259409 -0.04899292]\n",
224+
" [-0.16484832 0.35724741]\n",
225+
" [ 0.05170659 0.07401196]\n",
226+
" [-0.78548145 -0.44638164]\n",
227+
" [ 0.64017497 -0.30363301]]\n",
228+
"S.y: [1.36857656 0.75992983 0.83463487 0.46918172 0.92329124 0.8170764\n",
229+
" 0.15480068 0.00815134 0.81623768 0.502017 ]\n",
230+
"y_infill: [0.50052583]\n"
231+
]
232+
}
233+
],
234+
"source": [
235+
"import numpy as np\n",
236+
"from spotpython.spot import Spot\n",
237+
"from spotpython.fun import Analytical\n",
238+
"from spotpython.utils.init import fun_control_init\n",
239+
"nn = 3\n",
240+
"fun_sphere = Analytical().fun_sphere\n",
241+
"fun_control = fun_control_init(\n",
242+
" lower = np.array([-1, -1]),\n",
243+
" upper = np.array([1, 1]),\n",
244+
" n_points=nn,\n",
245+
" )\n",
246+
"S = Spot(\n",
247+
" fun=fun_sphere,\n",
248+
" fun_control=fun_control,\n",
249+
" )\n",
250+
"S.X = S.design.scipy_lhd(\n",
251+
" S.design_control[\"init_size\"], lower=S.lower, upper=S.upper\n",
252+
")\n",
253+
"print(f\"S.X: {S.X}\")\n",
254+
"S.y = S.fun(S.X)\n",
255+
"print(f\"S.y: {S.y}\")\n",
256+
"S.fit_surrogate()\n",
257+
"x = np.array([0.5, 0.5])\n",
258+
"y_infill = S.infill(x)\n",
259+
"print(f\"y_infill: {y_infill}\")\n",
260+
"assert np.isscalar(y_infill) or y_infill.shape == (1,)"
261+
]
262+
},
263+
{
264+
"cell_type": "code",
265+
"execution_count": 6,
266+
"metadata": {},
267+
"outputs": [
268+
{
269+
"name": "stderr",
270+
"output_type": "stream",
271+
"text": [
272+
"Seed set to 123\n"
273+
]
274+
},
275+
{
276+
"data": {
277+
"text/plain": [
278+
"[np.float64(3.0), np.int64(2), np.int64(3), np.float64(6.0)]"
279+
]
280+
},
281+
"execution_count": 6,
282+
"metadata": {},
283+
"output_type": "execute_result"
284+
}
285+
],
286+
"source": [
287+
"import numpy as np\n",
288+
"from spotpython.spot import Spot\n",
289+
"from spotpython.fun import Analytical\n",
290+
"from spotpython.utils.init import fun_control_init\n",
291+
"nn = 3\n",
292+
"fun_sphere = Analytical().fun_sphere\n",
293+
"fun_control = fun_control_init(\n",
294+
" lower = np.array([-1, -1]),\n",
295+
" upper = np.array([1, 1]),\n",
296+
" n_points=nn,\n",
297+
" )\n",
298+
"S = Spot(\n",
299+
" fun=fun_sphere,\n",
300+
" fun_control=fun_control,\n",
301+
" )\n",
302+
"z00 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])\n",
303+
"S.var_type = [\"float\", \"int\", \"int\", \"float\"]\n",
304+
"S.process_z00(z00)"
305+
]
306+
},
307+
{
308+
"cell_type": "code",
309+
"execution_count": null,
310+
"metadata": {},
311+
"outputs": [],
312+
"source": []
200313
}
201314
],
202315
"metadata": {

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
77

88
[project]
99
name = "spotpython"
10-
version = "0.34.10"
10+
version = "0.34.11"
1111
authors = [
1212
{ name="T. Bartz-Beielstein", email="tbb@bartzundbartz.de" }
1313
]

src/spotpython/spot/spot.py

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2325,6 +2325,34 @@ def infill(self, x) -> float:
23252325
(numpy.ndarray): value based on infill criterion, e.g., `"ei"`. Shape `(1,)`.
23262326
The objective function value `y` that is used as a base value for the
23272327
infill criterion is calculated in natural units.
2328+
2329+
Examples:
2330+
>>> import numpy as np
2331+
from spotpython.spot import Spot
2332+
from spotpython.fun import Analytical
2333+
from spotpython.utils.init import fun_control_init
2334+
nn = 3
2335+
fun_sphere = Analytical().fun_sphere
2336+
fun_control = fun_control_init(
2337+
lower = np.array([-1, -1]),
2338+
upper = np.array([1, 1]),
2339+
n_points=nn,
2340+
)
2341+
S = Spot(
2342+
fun=fun_sphere,
2343+
fun_control=fun_control,
2344+
)
2345+
S.X = S.design.scipy_lhd(
2346+
S.design_control["init_size"], lower=S.lower, upper=S.upper
2347+
)
2348+
print(f"S.X: {S.X}")
2349+
S.y = S.fun(S.X)
2350+
print(f"S.y: {S.y}")
2351+
S.fit_surrogate()
2352+
x = np.array([0.5, 0.5])
2353+
y_infill = S.infill(x)
2354+
print(f"y_infill: {y_infill}")
2355+
assert np.isscalar(y_infill) or y_infill.shape == (1,)
23282356
23292357
"""
23302358
# Reshape x to have shape (1, -1) because the predict method expects a 2D array
@@ -2702,7 +2730,7 @@ def process_z00(self, z00, use_min=True) -> list:
27022730
"""Process each entry in the `z00` array according to the corresponding type
27032731
in the `self.var_type` list.
27042732
Specifically, if the type is "float", the function will calculate the mean of the two `z00` values.
2705-
If the type is not "float", the function will retrun the maximum of the two `z00` values.
2733+
If the type is not "float", the function will retrun the minimum of the two `z00` values.
27062734
27072735
Args:
27082736
z00 (numpy.ndarray):
@@ -2714,13 +2742,25 @@ def process_z00(self, z00, use_min=True) -> list:
27142742
(list): Processed values.
27152743
27162744
Examples:
2717-
from spotpython.spot import spot
27182745
import numpy as np
2719-
import random
2746+
from spotpython.spot import Spot
2747+
from spotpython.fun import Analytical
2748+
from spotpython.utils.init import fun_control_init
2749+
nn = 3
2750+
fun_sphere = Analytical().fun_sphere
2751+
fun_control = fun_control_init(
2752+
lower = np.array([-1, -1]),
2753+
upper = np.array([1, 1]),
2754+
n_points=nn,
2755+
)
2756+
S = Spot(
2757+
fun=fun_sphere,
2758+
fun_control=fun_control,
2759+
)
27202760
z00 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
2721-
spot.var_type = ["float", "int", "int", "float"]
2722-
spot.process_z00(z00)
2723-
[3, 6, 7, 6]
2761+
S.var_type = ["float", "int", "int", "float"]
2762+
S.process_z00(z00)
2763+
[np.float64(3.0), np.int64(2), np.int64(3), np.float64(6.0)]
27242764
27252765
"""
27262766
result = []

test/test_process_z00.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import numpy as np
2+
import pytest
3+
from spotpython.spot.spot import Spot
4+
from spotpython.utils.init import fun_control_init
5+
6+
def dummy_fun(X, **kwargs):
7+
return np.sum(X, axis=1)
8+
9+
@pytest.fixture
10+
def spot_instance():
11+
fun_control = fun_control_init(
12+
lower=np.array([0, 0, 0, 0]),
13+
upper=np.array([1, 1, 1, 1]),
14+
var_type=["float", "int", "int", "float"],
15+
PREFIX="pytest_process_z00"
16+
)
17+
spot = Spot(fun=dummy_fun, fun_control=fun_control)
18+
spot.var_type = ["float", "int", "int", "float"]
19+
return spot
20+
21+
def test_process_z00_use_min(spot_instance):
22+
z00 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
23+
result = spot_instance.process_z00(z00, use_min=True)
24+
# float: mean, int: min
25+
assert np.isclose(result[0], 3.0)
26+
assert result[1] == 2
27+
assert result[2] == 3
28+
assert np.isclose(result[3], 6.0)
29+
30+
def test_process_z00_use_max(spot_instance):
31+
z00 = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
32+
result = spot_instance.process_z00(z00, use_min=False)
33+
# float: mean, int: max
34+
assert np.isclose(result[0], 3.0)
35+
assert result[1] == 6
36+
assert result[2] == 7
37+
assert np.isclose(result[3], 6.0)
38+
39+
def test_process_z00_single_row(spot_instance):
40+
z00 = np.array([[10, 20, 30, 40]])
41+
result = spot_instance.process_z00(z00, use_min=True)
42+
assert np.isclose(result[0], 10.0)
43+
assert result[1] == 20
44+
assert result[2] == 30
45+
assert np.isclose(result[3], 40.0)
46+
47+
def test_process_z00_all_float(spot_instance):
48+
spot_instance.var_type = ["float", "float"]
49+
z00 = np.array([[1.5, 2.5], [3.5, 4.5]])
50+
result = spot_instance.process_z00(z00, use_min=True)
51+
assert np.allclose(result, [2.5, 3.5])
52+
53+
def test_process_z00_all_int(spot_instance):
54+
spot_instance.var_type = ["int", "int"]
55+
z00 = np.array([[1, 2], [3, 4]])
56+
result = spot_instance.process_z00(z00, use_min=True)
57+
assert result == [1, 2]
58+
result_max = spot_instance.process_z00(z00, use_min=False)
59+
assert result_max == [3, 4]

test/test_spot_chg.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import numpy as np
2+
import pytest
3+
from spotpython.spot.spot import Spot
4+
from spotpython.utils.init import fun_control_init
5+
6+
def quadratic_fun(X, **kwargs):
7+
return np.sum(X**2, axis=1)
8+
9+
@pytest.fixture
10+
def spot_instance():
11+
fun_control = fun_control_init(
12+
lower=np.array([-1, -1, -1]),
13+
upper=np.array([1, 1, 1]),
14+
PREFIX="pytest_chg",
15+
save_result=False,
16+
save_experiment=False,
17+
)
18+
spot = Spot(fun=quadratic_fun, fun_control=fun_control)
19+
return spot
20+
21+
def test_chg_list(spot_instance):
22+
z0 = [1, 2, 3]
23+
result = spot_instance.chg(x=10, y=20, z0=z0.copy(), i=0, j=2)
24+
assert result == [10, 2, 20]
25+
26+
def test_chg_numpy_array(spot_instance):
27+
z0 = np.array([1, 2, 3])
28+
result = spot_instance.chg(x=5, y=7, z0=z0.copy(), i=1, j=0)
29+
assert np.array_equal(result, np.array([7, 5, 3]))
30+
31+
def test_chg_same_index(spot_instance):
32+
z0 = [1, 2, 3]
33+
result = spot_instance.chg(x=9, y=8, z0=z0.copy(), i=1, j=1)
34+
assert result == [1, 8, 3] # last assignment wins
35+
36+
def test_chg_does_not_modify_original(spot_instance):
37+
z0 = [1, 2, 3]
38+
z0_copy = z0.copy()
39+
_ = spot_instance.chg(x=4, y=5, z0=z0_copy, i=0, j=2)
40+
assert z0 == [1, 2, 3]

test/test_spot_infill.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import numpy as np
2+
import pytest
3+
from spotpython.spot.spot import Spot
4+
from spotpython.utils.init import fun_control_init, design_control_init, surrogate_control_init
5+
6+
def quadratic_fun(X, **kwargs):
7+
return np.sum(X**2, axis=1)
8+
9+
@pytest.fixture
10+
def spot_instance():
11+
fun_control = fun_control_init(
12+
lower=np.array([-2, -1]),
13+
upper=np.array([2, 1]),
14+
fun_evals=5,
15+
PREFIX="pytest_infill",
16+
save_result=False,
17+
save_experiment=False,
18+
)
19+
design_control = design_control_init(init_size=5)
20+
surrogate_control = surrogate_control_init()
21+
spot = Spot(fun=quadratic_fun, fun_control=fun_control, design_control=design_control, surrogate_control=surrogate_control)
22+
spot.initialize_design()
23+
spot.evaluate_initial_design()
24+
spot.update_stats()
25+
spot.fit_surrogate()
26+
return spot
27+
28+
def test_infill_returns_float(spot_instance):
29+
# Use a point in the middle of the domain
30+
x = np.array([0.0, 0.0])
31+
val = spot_instance.infill(x)
32+
assert isinstance(val, float) or np.isscalar(val) or (isinstance(val, np.ndarray) and val.size == 1)
33+
34+
def test_infill_on_design_points(spot_instance):
35+
# Should not raise and should return a float for each design point
36+
for x in spot_instance.X:
37+
val = spot_instance.infill(x)
38+
assert isinstance(val, float) or np.isscalar(val) or (isinstance(val, np.ndarray) and val.size == 1)
39+
40+
def test_infill_within_bounds(spot_instance):
41+
# Try a point at the lower bound
42+
x = spot_instance.lower.copy()
43+
val = spot_instance.infill(x)
44+
assert isinstance(val, float) or np.isscalar(val) or (isinstance(val, np.ndarray) and val.size == 1)
45+
# Try a point at the upper bound
46+
x = spot_instance.upper.copy()
47+
val = spot_instance.infill(x)
48+
assert isinstance(val, float) or np.isscalar(val) or (isinstance(val, np.ndarray) and val.size == 1)
49+
50+
def test_infill_shape(spot_instance):
51+
# Should accept 1D input of correct length
52+
x = np.zeros(spot_instance.k)
53+
val = spot_instance.infill(x)
54+
assert np.isscalar(val) or (isinstance(val, np.ndarray) and val.shape == (1,))

0 commit comments

Comments
 (0)