Skip to content

Commit 280fa7b

Browse files
0.8.17
1 parent bad219f commit 280fa7b

5 files changed

Lines changed: 193 additions & 118 deletions

File tree

notebooks/testKriging.ipynb

Lines changed: 87 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1451,55 +1451,9 @@
14511451
},
14521452
{
14531453
"cell_type": "code",
1454-
"execution_count": 1,
1454+
"execution_count": null,
14551455
"metadata": {},
1456-
"outputs": [
1457-
{
1458-
"name": "stderr",
1459-
"output_type": "stream",
1460-
"text": [
1461-
"Seed set to 123\n"
1462-
]
1463-
},
1464-
{
1465-
"name": "stdout",
1466-
"output_type": "stream",
1467-
"text": [
1468-
"S.X: [[ 0. 1. ]\n",
1469-
" [ 1. 0. ]\n",
1470-
" [ 1. 1. ]\n",
1471-
" [ 1. 1. ]\n",
1472-
" [ 0.54509876 -0.36921401]\n",
1473-
" [ 0.54509876 -0.36921401]\n",
1474-
" [ 0.18642675 0.87708546]\n",
1475-
" [ 0.18642675 0.87708546]\n",
1476-
" [-0.45060393 -0.208063 ]\n",
1477-
" [-0.45060393 -0.208063 ]]\n",
1478-
"S.y: [0.98021757 0.99264427 2.02575851 2.00387949 0.45185626 0.44499372\n",
1479-
" 0.79130456 0.81487288 0.24000221 0.23988634]\n",
1480-
"X_shape_before: (10, 2)\n",
1481-
"y_size_before: 10\n",
1482-
"S.X: [[ 0. 1. ]\n",
1483-
" [ 1. 0. ]\n",
1484-
" [ 1. 1. ]\n",
1485-
" [ 1. 1. ]\n",
1486-
" [ 0.54509876 -0.36921401]\n",
1487-
" [ 0.54509876 -0.36921401]\n",
1488-
" [ 0.18642675 0.87708546]\n",
1489-
" [ 0.18642675 0.87708546]\n",
1490-
" [-0.45060393 -0.208063 ]\n",
1491-
" [-0.45060393 -0.208063 ]\n",
1492-
" [-0.39841465 -0.21105872]\n",
1493-
" [-0.39841465 -0.21105872]]\n",
1494-
"S.y: [0.98021757 0.99264427 2.02575851 2.00387949 0.45185626 0.44499372\n",
1495-
" 0.79130456 0.81487288 0.24000221 0.23988634 0.18349759 0.19592429]\n",
1496-
"S.n_points: 1\n",
1497-
"S.ocba_delta: 1\n",
1498-
"X_shape_after: (12, 2)\n",
1499-
"y_size_after: 12\n"
1500-
]
1501-
}
1502-
],
1456+
"outputs": [],
15031457
"source": [
15041458
"import numpy as np\n",
15051459
"from spotPython.fun.objectivefunctions import analytical\n",
@@ -1548,6 +1502,91 @@
15481502
"print(f\"y_size_after: {S.y.size}\")\n"
15491503
]
15501504
},
1505+
{
1506+
"cell_type": "code",
1507+
"execution_count": null,
1508+
"metadata": {},
1509+
"outputs": [],
1510+
"source": [
1511+
"from spotPython.budget.ocba import get_ocba, get_ocba_X\n",
1512+
"from spotPython.utils.aggregate import aggregate_mean_var\n",
1513+
"import numpy as np\n",
1514+
"X = np.array([[1,2,3],\n",
1515+
" [1,2,3],\n",
1516+
" [4,5,6],\n",
1517+
" [4,5,6],\n",
1518+
" [4,5,6],\n",
1519+
" [7,8,9],\n",
1520+
" [7,8,9],])\n",
1521+
"y = np.array([1,2,30,40, 40, 500, 600 ])\n",
1522+
"Z = aggregate_mean_var(X=X, y=y)\n",
1523+
"mean_X = Z[0]\n",
1524+
"mean_y = Z[1]\n",
1525+
"var_y = Z[2]\n",
1526+
"print(f\"X: {X}\")\n",
1527+
"print(f\"y: {y}\")\n",
1528+
"print(f\"mean_X: {mean_X}\")\n",
1529+
"print(f\"mean_y: {mean_y}\")\n",
1530+
"print(f\"var_y: {var_y}\")\n",
1531+
"delta = 5\n",
1532+
"# get_ocba(means, vars, delta,verbose=True)\n",
1533+
"X_new = get_ocba_X(X=mean_X, means=mean_y, vars=var_y, delta=delta,verbose=True)\n",
1534+
"X_new\n"
1535+
]
1536+
},
1537+
{
1538+
"cell_type": "code",
1539+
"execution_count": 2,
1540+
"metadata": {},
1541+
"outputs": [
1542+
{
1543+
"name": "stdout",
1544+
"output_type": "stream",
1545+
"text": [
1546+
"X: [[1 2 3]\n",
1547+
" [1 2 3]\n",
1548+
" [4 5 6]\n",
1549+
" [4 5 6]\n",
1550+
" [4 5 6]\n",
1551+
" [4 5 6]\n",
1552+
" [4 5 6]]\n",
1553+
"mean_X.shape: (2, 3)\n",
1554+
"y: [ 1 2 30 40 40 500 600]\n",
1555+
"mean_X: [[1. 2. 3.]\n",
1556+
" [4. 5. 6.]]\n",
1557+
"mean_y: [ 1.5 242. ]\n",
1558+
"var_y: [5.000e-01 8.032e+04]\n"
1559+
]
1560+
}
1561+
],
1562+
"source": [
1563+
"from spotPython.budget.ocba import get_ocba, get_ocba_X\n",
1564+
"from spotPython.utils.aggregate import aggregate_mean_var\n",
1565+
"import numpy as np\n",
1566+
"X = np.array([[1,2,3],\n",
1567+
" [1,2,3],\n",
1568+
" [4,5,6],\n",
1569+
" [4,5,6],\n",
1570+
" [4,5,6],\n",
1571+
" [4, 5, 6],\n",
1572+
" [4, 5 ,6],])\n",
1573+
"y = np.array([1,2,30,40, 40, 500, 600 ])\n",
1574+
"Z = aggregate_mean_var(X=X, y=y)\n",
1575+
"mean_X = Z[0]\n",
1576+
"mean_y = Z[1]\n",
1577+
"var_y = Z[2]\n",
1578+
"print(f\"X: {X}\")\n",
1579+
"print((f\"mean_X.shape: {mean_X.shape}\"))\n",
1580+
"print(f\"y: {y}\")\n",
1581+
"print(f\"mean_X: {mean_X}\")\n",
1582+
"print(f\"mean_y: {mean_y}\")\n",
1583+
"print(f\"var_y: {var_y}\")\n",
1584+
"delta = 5\n",
1585+
"# get_ocba(means, vars, delta,verbose=True)\n",
1586+
"X_new = get_ocba_X(X=mean_X, means=mean_y, vars=var_y, delta=delta,verbose=True)\n",
1587+
"assert X_new is None\n"
1588+
]
1589+
},
15511590
{
15521591
"cell_type": "code",
15531592
"execution_count": null,

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.8.16"
10+
version = "0.8.17"
1111
authors = [
1212
{ name="T. Bartz-Beielstein", email="tbb@bartzundbartz.de" }
1313
]

src/spotPython/budget/ocba.py

Lines changed: 64 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from numpy import int32, float64
77
from numpy import argpartition, repeat
88
from numpy import zeros, square, sqrt, full, around, array
9+
import numpy as np
910

1011

1112
def get_ocba(means, vars, delta, verbose=False) -> array:
@@ -47,63 +48,66 @@ def get_ocba(means, vars, delta, verbose=False) -> array:
4748
get_ocba(mean_y, var_y, 50)
4849
array([11, 9, 19, 9, 2])
4950
"""
50-
n_designs = means.shape[0]
51-
allocations = zeros(n_designs, int32)
52-
ratios = zeros(n_designs, float64)
53-
budget = delta
54-
ranks = get_ranks(means)
55-
best, second_best = argpartition(ranks, 2)[:2]
56-
ratios[second_best] = 1.0
57-
select = [i for i in range(n_designs) if i not in [best, second_best]]
58-
temp = (means[best] - means[second_best]) / (means[best] - means[select])
59-
ratios[select] = square(temp) * (vars[select] / vars[second_best])
60-
select = [i for i in range(n_designs) if i not in [best]]
61-
temp = (square(ratios[select]) / vars[select]).sum()
62-
ratios[best] = sqrt(vars[best] * temp)
63-
more_runs = full(n_designs, True, dtype=bool)
64-
add_budget = zeros(n_designs, dtype=float)
65-
more_alloc = True
66-
if verbose:
67-
print("\nIn get_ocba():")
68-
print(f"means: {means}")
69-
print(f"vars: {vars}")
70-
print(f"delta: {delta}")
71-
print(f"n_designs: {n_designs}")
72-
print(f"Allocations: {allocations}")
73-
print(f"Ratios: {ratios}")
74-
print(f"Budget: {budget}")
75-
print(f"Ranks: {ranks}")
76-
print(f"Best: {best}")
77-
print(f"Second best: {second_best}")
78-
print(f"Select: {select}")
79-
print(f"Temp: {temp}")
80-
print(f"More runs: {more_runs}")
81-
print(f"Add budget: {add_budget}")
82-
print(f"More allocations: {more_alloc}")
83-
while more_alloc:
84-
more_alloc = False
85-
ratio_s = (more_runs * ratios).sum()
86-
add_budget[more_runs] = (budget / ratio_s) * ratios[more_runs]
87-
add_budget = around(add_budget).astype(int)
88-
mask = add_budget < allocations
89-
add_budget[mask] = allocations[mask]
90-
more_runs[mask] = 0
51+
if np.all(vars > 0) and (means.shape[0] > 2):
52+
n_designs = means.shape[0]
53+
allocations = zeros(n_designs, int32)
54+
ratios = zeros(n_designs, float64)
55+
budget = delta
56+
ranks = get_ranks(means)
57+
best, second_best = argpartition(ranks, 2)[:2]
58+
ratios[second_best] = 1.0
59+
select = [i for i in range(n_designs) if i not in [best, second_best]]
60+
temp = (means[best] - means[second_best]) / (means[best] - means[select])
61+
ratios[select] = square(temp) * (vars[select] / vars[second_best])
62+
select = [i for i in range(n_designs) if i not in [best]]
63+
temp = (square(ratios[select]) / vars[select]).sum()
64+
ratios[best] = sqrt(vars[best] * temp)
65+
more_runs = full(n_designs, True, dtype=bool)
66+
add_budget = zeros(n_designs, dtype=float)
67+
more_alloc = True
9168
if verbose:
92-
print("\nIn more_alloc:")
93-
print(f"ratio_s: {ratio_s}")
94-
print(f"more_runs: {more_runs}")
95-
print(f"add_budget: {add_budget}")
96-
if mask.sum() > 0:
97-
more_alloc = True
98-
if more_alloc:
99-
budget = allocations.sum() + delta
100-
budget -= (add_budget * ~more_runs).sum()
101-
t_budget = add_budget.sum()
102-
add_budget[best] += allocations.sum() + delta - t_budget
103-
return add_budget - allocations
69+
print("\nIn get_ocba():")
70+
print(f"means: {means}")
71+
print(f"vars: {vars}")
72+
print(f"delta: {delta}")
73+
print(f"n_designs: {n_designs}")
74+
print(f"Allocations: {allocations}")
75+
print(f"Ratios: {ratios}")
76+
print(f"Budget: {budget}")
77+
print(f"Ranks: {ranks}")
78+
print(f"Best: {best}")
79+
print(f"Second best: {second_best}")
80+
print(f"Select: {select}")
81+
print(f"Temp: {temp}")
82+
print(f"More runs: {more_runs}")
83+
print(f"Add budget: {add_budget}")
84+
print(f"More allocations: {more_alloc}")
85+
while more_alloc:
86+
more_alloc = False
87+
ratio_s = (more_runs * ratios).sum()
88+
add_budget[more_runs] = (budget / ratio_s) * ratios[more_runs]
89+
add_budget = around(add_budget).astype(int)
90+
mask = add_budget < allocations
91+
add_budget[mask] = allocations[mask]
92+
more_runs[mask] = 0
93+
if verbose:
94+
print("\nIn more_alloc:")
95+
print(f"ratio_s: {ratio_s}")
96+
print(f"more_runs: {more_runs}")
97+
print(f"add_budget: {add_budget}")
98+
if mask.sum() > 0:
99+
more_alloc = True
100+
if more_alloc:
101+
budget = allocations.sum() + delta
102+
budget -= (add_budget * ~more_runs).sum()
103+
t_budget = add_budget.sum()
104+
add_budget[best] += allocations.sum() + delta - t_budget
105+
return add_budget - allocations
106+
else:
107+
return None
104108

105109

106-
def get_ocba_X(X, means, vars, delta) -> float64:
110+
def get_ocba_X(X, means, vars, delta, verbose=False) -> float64:
107111
"""
108112
This function calculates the OCBA allocation and repeats the input array X along the specified axis.
109113
@@ -112,6 +116,7 @@ def get_ocba_X(X, means, vars, delta) -> float64:
112116
means (list): List of means for each alternative.
113117
vars (list): List of variances for each alternative.
114118
delta (float): Indifference zone parameter.
119+
verbose (bool): If True, print the results.
115120
116121
Returns:
117122
(numpy.ndarray): Repeated array of X along the specified axis based on the OCBA allocation.
@@ -130,5 +135,8 @@ def get_ocba_X(X, means, vars, delta) -> float64:
130135
[4, 5, 6]])
131136
132137
"""
133-
o = get_ocba(means=means, vars=vars, delta=delta)
134-
return repeat(X, o, axis=0)
138+
if np.all(vars > 0) and (means.shape[0] > 2):
139+
o = get_ocba(means=means, vars=vars, delta=delta, verbose=verbose)
140+
return repeat(X, o, axis=0)
141+
else:
142+
return None

src/spotPython/spot/spot.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -749,12 +749,12 @@ def update_design(self) -> None:
749749
"""
750750
# OCBA (only if noise). Determination of the OCBA points depends on the
751751
# old X and y values.
752-
if self.noise and self.ocba_delta > 0 and not np.all(self.var_y > 0):
753-
logger.warning(
754-
"self.var_y <= 0. OCBA points are not generated, because there are points with no variance information."
755-
)
752+
if self.noise and self.ocba_delta > 0 and not np.all(self.var_y > 0) and (self.mean_X.shape[0] <= 2):
753+
logger.warning("self.var_y <= 0. OCBA points are not generated:")
754+
logger.warning("There are less than 3 points or points with no variance information.")
755+
logger.debug("In update_design(): self.mean_X: %s", self.mean_X)
756756
logger.debug("In update_design(): self.var_y: %s", self.var_y)
757-
if self.noise and self.ocba_delta > 0 and np.all(self.var_y > 0):
757+
if self.noise and self.ocba_delta > 0 and np.all(self.var_y > 0) and (self.mean_X.shape[0] > 2):
758758
X_ocba = get_ocba_X(self.mean_X, self.mean_y, self.var_y, self.ocba_delta)
759759
else:
760760
X_ocba = None

test/test_ocba.py

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
def test_ocba():
2-
"""
3-
Test OCBA.
4-
5-
"""
6-
71
import copy
82
import numpy as np
93
from spotPython.fun.objectivefunctions import analytical
104
from spotPython.spot import spot
11-
from spotPython.budget.ocba import get_ocba
5+
from spotPython.budget.ocba import get_ocba, get_ocba_X
6+
from spotPython.utils.aggregate import aggregate_mean_var
127

8+
def test_ocba():
9+
"""
10+
Test OCBA.
11+
12+
"""
1313
# Test based on the example from the book:
1414
# Chun-Hung Chen and Loo Hay Lee:
1515
# Stochastic Simulation Optimization: An Optimal Computer Budget Allocation,
@@ -43,4 +43,32 @@ def test_ocba():
4343
n = 50
4444
o = get_ocba(spot_2.mean_y, spot_2.var_y, n)
4545
assert sum(o) == 50
46-
assert (o == np.array([[11, 9, 19, 9, 2]])).all()
46+
assert (o == np.array([[11, 9, 19, 9, 2]])).all()
47+
48+
def test_ocba_none_result():
49+
"""
50+
Test OCBA with None result.
51+
52+
"""
53+
X = np.array([[1,2,3],
54+
[1,2,3],
55+
[4,5,6],
56+
[4,5,6],
57+
[4,5,6],
58+
[4, 5, 6],
59+
[4, 5 ,6],])
60+
y = np.array([1,2,30,40, 40, 500, 600 ])
61+
Z = aggregate_mean_var(X=X, y=y)
62+
mean_X = Z[0]
63+
mean_y = Z[1]
64+
var_y = Z[2]
65+
print(f"X: {X}")
66+
print((f"mean_X.shape: {mean_X.shape}"))
67+
print(f"y: {y}")
68+
print(f"mean_X: {mean_X}")
69+
print(f"mean_y: {mean_y}")
70+
print(f"var_y: {var_y}")
71+
delta = 5
72+
# get_ocba(means, vars, delta,verbose=True)
73+
X_new = get_ocba_X(X=mean_X, means=mean_y, vars=var_y, delta=delta,verbose=True)
74+
assert X_new is None

0 commit comments

Comments
 (0)