Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Pytest #100

Merged
merged 2 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ jobs:
- name: Upload coverage reports to Codecov with GitHub Action
# if: ${{ runner.os == 'Linux' && matrix.python-version == 3.8 }}
uses: codecov/codecov-action@v3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
2 changes: 1 addition & 1 deletion openbox/core/ea/adaptive_ea_advisor.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(self,
self.last_observations = []

def get_suggestion(self):
if not self.last_suggestions:
while not self.last_suggestions:
self.update_observations(self.last_observations)
self.last_observations = []
self.last_suggestions = self.get_suggestions()
Expand Down
17 changes: 16 additions & 1 deletion test/acq_optimizer/test_random_configuration_chooser.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,41 @@ def test_no_cool_down_chooser_returns_expected_result(self):
self.assertTrue(chooser.check(2))
self.assertFalse(chooser.check(3))

chooser2 = ChooserNoCoolDown(1.0)
self.assertTrue(chooser2.modulus == 1.0)

def test_linear_cool_down_chooser_returns_expected_result(self):
chooser = ChooserLinearCoolDown(2.0, 0.3, np.inf)
self.assertTrue(chooser.check(2))
self.assertFalse(chooser.check(3))

chooser.next_smbo_iteration()
self.assertTrue(chooser.check(3))

def test_prob_chooser_returns_expected_result(self):
chooser = ChooserProb(0.5, self.rng)
self.assertTrue(chooser.check(1))
self.assertFalse(chooser.check(2))

def test_prob_cool_down_chooser_returns_expected_result(self):
chooser = ChooserProbCoolDown(0.5, 0.1, self.rng)
chooser = ChooserProbCoolDown(0.5, 2, self.rng)
self.assertTrue(chooser.check(1))
self.assertFalse(chooser.check(2))

chooser.next_smbo_iteration()
self.assertTrue(chooser.check(3))

def test_cosine_annealing_chooser_returns_expected_result(self):
chooser = ChooserCosineAnnealing(0.5, 0.1, 2, self.rng)
self.assertTrue(chooser.check(1))
self.assertFalse(chooser.check(2))

chooser.next_smbo_iteration()
self.assertTrue(chooser.iteration == 1)
chooser.next_smbo_iteration()
chooser.next_smbo_iteration()
self.assertTrue(chooser.iteration == 0)


if __name__ == '__main__':
unittest.main()
115 changes: 112 additions & 3 deletions test/acquisition_function/test_acquisition.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@
LCB,
Uncertainty,
)

'''
加入其他函数的测试
'''
from openbox.acquisition_function.multi_objective_acquisition import (
MaxvalueEntropySearch,
MESMO,
MESMOC,
MESMOC2,
)
class ConfigurationMock:
def __init__(self, values=None):
self.values = values
Expand All @@ -22,6 +30,13 @@ def get_array(self):
return np.array(self.values, dtype=np.float64)

class MockModel:
'''
其实axis的重点在于方向,而不是行和列。具体到各种用法而言也是如此。
当axis=1时,如果是求平均,那么是从左到右横向求平均;如果是拼接,那么也是左右横向拼接;如果是drop,那么也是横向发生变化,体现为列的减少。
mean_col_vector = np.mean(X, axis=1).reshape(-1, 1)
return mean_col_vector, mean_col_vector
这里代码重复了?
'''
def predict_marginalized_over_instances(self, X):
return np.array([np.mean(X, axis=1).reshape((1, -1))]).reshape((-1, 1)), np.array(
[np.mean(X, axis=1).reshape((1, -1))]
Expand All @@ -45,11 +60,30 @@ def __init__(self, num_targets=1):
self.num_targets = num_targets

def predict_marginalized_over_instances(self, X):
'''
这个乘法真的没有问题?不是引用?
np.full(X.shape[0], 0.0):创建一个与 X 的行数相同的全 0 数组。
>>> b=[a]
>>> b
[array([1, 2])]
>>> b*2
[array([1, 2]), array([1, 2])]
>>> c=b*2
>>> c
[array([1, 2]), array([1, 2])]
>>> c[0][0]=2
>>> c
[array([2, 2]), array([2, 2])]
>>>
'''
return np.array([np.mean(X, axis=1).reshape((1, -1))] * self.num_targets).reshape((-1, 2)), np.array(
[np.full(X.shape[0], 0.0).reshape((1, -1))] * self.num_targets
).reshape((-1, 2))

class MockConstraintModel:
'''
np.full(m.shape, 0.1):创建一个与 m 形状相同的数组,数组中的每个元素都为 0.1
'''
def predict_marginalized_over_instances(self, X):
m = -np.abs(np.mean(X, axis=1)).reshape((-1, 1))
v = np.full(m.shape, 0.1)
Expand All @@ -60,6 +94,7 @@ def predict_marginalized_over_instances(self, X):
return np.full(X.shape[0], np.nan).reshape((-1, 1)), np.full(X.shape[0], np.nan).reshape((-1, 1))

class MockModelWrongVShape:
#错的v shape?
def predict_marginalized_over_instances(self, X):
m = np.mean(X, axis=1).reshape((-1, 2))
v = np.var(X, axis=1).reshape((-1, 1))
Expand Down Expand Up @@ -150,6 +185,12 @@ def test_ei_eta_fail(model, acquisition_function):
ei.update(model=model)
configurations = [ConfigurationMock([1.0])]
with pytest.raises(ValueError):
'''
1. with pytest.raises(ValueError):
pytest.raises 是 pytest 提供的一个上下文管理器,用于检查某段代码是否抛出特定类型的异常。
ValueError 是期望的异常类型。
这段代码的含义是:在 with 语句的块内,pytest 期望执行的代码会引发 ValueError。如果代码没有抛出 ValueError,测试将会失败。
'''
ei(configurations)

def test_ei_1x1(model, acquisition_function):
Expand Down Expand Up @@ -426,7 +467,7 @@ def test_pi_1xD(model, acq_pi):
def test_pi_NxD(model, acq_pi):
pi = acq_pi
pi.update(model=model, eta=1.0)
configurations = [
configurations = [
ConfigurationMock([0.0001, 0.0001, 0.0001]),
ConfigurationMock([0.1, 0.1, 0.1]),
ConfigurationMock([1.0, 1.0, 1.0]),
Expand Down Expand Up @@ -549,4 +590,72 @@ def test_uncertainty_with_nan(model_with_nan, acq_uncer):
configurations = [ConfigurationMock([0.5])]
acq = uncertainty(configurations)

assert np.all(acq == 0)
assert np.all(acq == 0)




'''
import numpy as np

# 创建一个形状为 (2, 3, 4) 的三维数组
data = np.array([
[[1, 2, 3, 4], # 实验 1
[5, 6, 7, 8],
[9, 10, 11, 12]],

[[13, 14, 15, 16], # 实验 2
[17, 18, 19, 20],
[21, 22, 23, 24]]
])

print("原始数组:")
print(data)
mean_axis_0 = np.mean(data, axis=0)
print("沿 axis=0 计算的均值:")
print(mean_axis_0)
# 输出:
# [[ 7. 8. 9. 10.]
# [11. 12. 13. 14.]
# [15. 16. 17. 18.]]
mean_axis_1 = np.mean(data, axis=1)

print("沿 axis=1 计算的均值:")
print(mean_axis_1)
# 输出:
# [[ 5. 6. 7. 8.]
# [19. 20. 21. 22.]]

mean_axis_neg1 = np.mean(data, axis=-1)
print("沿 axis=-1 计算的均值:")
print(mean_axis_neg1)
# 输出:
# [[ 2.5 6.5 10.5]
# [14.5 18.5 22.5]]
总结
'''

'''
使用 np.expand_dims
当我们调用:
expanded = np.expand_dims(self.cell_lower_bounds, axis=(1, 2))
axis=(1, 2) 指定在第 1 和第 2 维的位置插入新维度。
变化步骤
第一次扩展 (axis=1):

原始数组形状为 (m,),在第 1 维插入一个新维度后,形状变为 (1, m):
python
复制代码
[[1, 2, 3]] # 形状为 (1, 3)
第二次扩展 (axis=2):

在新数组的第 2 维插入新维度,形状变为 (1, m, 1):
python
复制代码
[[[1],
[2],
[3]]] # 形状为 (1, 3, 1)
总结
因此,经过两次扩展后,self.cell_lower_bounds 的形状最终变为 (1, m, 1),表示有一个批次(第一维为 1),m 个目标(第二维为 m),
以及每个目标的单个值(第三维为 1)。这种形状使得该数组可以与其他三维数组(如 Y_samples)进行有效的广播和运算。
'''
28 changes: 23 additions & 5 deletions test/core/ea/test_adaptive_ea_advisor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@

def test_adaptive_ea_advisor(configspace_tiny):
config_space = configspace_tiny
advisor = AdaptiveEAAdvisor(config_space, population_size=4, subset_size=2, num_objectives=2, pc=1, pm=1)
advisor = AdaptiveEAAdvisor(config_space, population_size=8, subset_size=2, num_objectives=2, pc=1, pm=1)
#换一个oldest策略再来一次?
'''
目前看来这个只支持单目标优化,这里的多目标似乎是假的
'''
advisor_oldest = AdaptiveEAAdvisor(config_space, strategy='oldest', population_size=8, subset_size=2, num_objectives=2, pc=1, pm=1)
assert advisor.config_space == config_space
assert advisor.subset_size == 2
assert advisor.epsilon == 0.2
Expand All @@ -20,13 +25,23 @@ def test_adaptive_ea_advisor(configspace_tiny):
assert advisor.k4 == 0.3
assert advisor.last_suggestions == []
assert advisor.last_observations == []

perfs = [[2, 1], [1, 2], [2, 2], [1, 1], [1, 2]]
for i in range(4):
'''
多assert
'''
perfs = [[2, 1], [1, 2], [2, 2], [1, 1], [1, 2], [1, 1], [1, 1], [1, 1], [1, 1], [2, 3], [4, 5], [6, 7], [3, 6]]
#修改为10次 ref_point多给点
for i in range(13):
suggestion1 = advisor.get_suggestion()
assert isinstance(suggestion1, Configuration)
observation1 = Observation(suggestion1, perfs[i], trial_state=SUCCESS, elapsed_time=2.0, extra_info={})
advisor.update_observation(observation1)
'''
oldest strategy
'''
suggestion1 = advisor_oldest.get_suggestion()
assert isinstance(suggestion1, Configuration)
observation1 = Observation(suggestion1, perfs[i], trial_state=SUCCESS, elapsed_time=2.0, extra_info={})
advisor_oldest.update_observation(observation1)

config_a = config_space.sample_configuration()
config_b = config_space.sample_configuration()
Expand All @@ -35,4 +50,7 @@ def test_adaptive_ea_advisor(configspace_tiny):

config = config_space.sample_configuration()
next_config = advisor.mutation(config)
assert isinstance(next_config, Configuration)
## 测试None
# config = None
# next_config = advisor.mutation(config)
# assert isinstance(next_config, Configuration)
35 changes: 31 additions & 4 deletions test/core/ea/test_differential_ea_advisor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,19 @@
from openbox.utils.constants import MAXINT, SUCCESS


def test_cmaes_ea_advisor_initialization(configspace_tiny):
def test_cmaes_ea_advisor_initialization(configspace_tiny, configspace_cat):
config_space = configspace_tiny
advisor = DifferentialEAAdvisor(config_space, num_objectives=2, population_size=4)
config_cat = configspace_cat
#添加变化的f以及cr

'''
在单目标优化中,允许使用动态的 f 和 cr 来提升算法的表现。
在多目标优化中,为了保持多个目标的平衡,限制动态调整 f 和 cr,因此在这种情况下需要固定这些参数。
断言的目的是避免算法在不合适的情况下使用动态参数,确保差分进化算法在不同优化问题上的一致性和正确性。
'''
advisor_vary = DifferentialEAAdvisor(config_space, f=(0,1), cr=(0,1), num_objectives=1, population_size=4)
advisor_cat = DifferentialEAAdvisor(config_cat, num_objectives=1, population_size=4)
assert advisor.config_space == config_space
assert advisor.num_objectives == 2
assert advisor.num_constraints == 0
Expand All @@ -24,13 +34,23 @@ def test_cmaes_ea_advisor_initialization(configspace_tiny):
assert advisor.filter_gen_population is None
assert advisor.keep_unexpected_population is True
assert advisor.save_cached_configuration is True

perfs = [[2, 1], [1, 2], [2, 2], [1, 1], [1, 2]]
for i in range(5):
perfs = [[2, 1], [1, 2], [2, 2], [1, 1], [1, 2], [1, 1], [1, 1], [-1, 1]]
for i in range(8):
suggestion1 = advisor.get_suggestion()
assert isinstance(suggestion1, Configuration)
observation1 = Observation(suggestion1, perfs[i], trial_state=SUCCESS, elapsed_time=2.0, extra_info={})
#这个update内有next_population的更新,会把suggestion1也就是gen的config加入sub,让sel能使用sub
advisor.update_observation(observation1)

suggestion2 = advisor_vary.get_suggestion()
assert isinstance(suggestion2, Configuration)
observation2 = Observation(suggestion2, [perfs[i][0]], trial_state=SUCCESS, elapsed_time=2.0, extra_info={})
advisor_vary.update_observation(observation2)

# suggestion3 = advisor_cat.get_suggestion()
# assert isinstance(suggestion3, Configuration)
# observation3 = Observation(suggestion3, [1], trial_state=SUCCESS, elapsed_time=2.0, extra_info={})
# advisor_cat.update_observation(observation3)

config_a = config_space.sample_configuration()
config_b = config_space.sample_configuration()
Expand All @@ -40,3 +60,10 @@ def test_cmaes_ea_advisor_initialization(configspace_tiny):

config = advisor.cross_over(config_a, config_b, 0.5)
assert isinstance(config, Configuration)


config_a = config_cat.sample_configuration()
config_b = config_cat.sample_configuration()
config_c = config_cat.sample_configuration()
config = advisor_cat.mutate(config_a, config_b, config_c, 0.5)
#这里的prefs对应ref_point吧?传到Observation中对应objectives属性
18 changes: 16 additions & 2 deletions test/core/ea/test_nsga2_ea_advisor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from openbox.utils.constants import MAXINT, SUCCESS


def test_nsga2_ea_advisor_initialization(configspace_tiny):
def test_nsga2_ea_advisor_initialization(configspace_tiny, configspace_huge):
config_space = configspace_tiny
advisor = NSGA2EAdvisor(config_space, num_objectives=2, subset_size=2, population_size=4)
assert advisor.config_space == config_space
Expand All @@ -25,4 +25,18 @@ def test_nsga2_ea_advisor_initialization(configspace_tiny):
suggestion1 = advisor.get_suggestion()
assert isinstance(suggestion1, Configuration)
observation1 = Observation(suggestion1, perfs[i], trial_state=SUCCESS, elapsed_time=2.0, extra_info={})
advisor.update_observation(observation1)
advisor.update_observation(observation1)

obs = list()
for i in range(5):
configs = advisor.get_suggestions()
for config in configs:
obs.append(Observation(config, perfs[i], trial_state=SUCCESS, elapsed_time=2.0, extra_info={}))
advisor.update_observations(obs)


#test cross_over
advisor_2 = NSGA2EAdvisor(config_space=configspace_huge)
for i in range(5):
config = advisor_2.cross_over(configspace_huge.sample_configuration(), configspace_huge.sample_configuration())
assert config.configuration_space == configspace_huge
Loading
Loading