diff --git a/.github/workflows/citation.yml b/.github/workflows/citation.yml index 9ca4ace4b..91509b900 100644 --- a/.github/workflows/citation.yml +++ b/.github/workflows/citation.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out a copy of the repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check whether the citation metadata from CITATION.cff is valid uses: citation-file-format/cffconvert-github-action@2.0.0 diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index 0965ea2f1..39f187b0f 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -28,7 +28,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index d89791712..d97c162f0 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 diff --git a/.github/workflows/pre-commit-update.yml b/.github/workflows/pre-commit-update.yml index 1688f60d7..d475d0a9b 100644 --- a/.github/workflows/pre-commit-update.yml +++ b/.github/workflows/pre-commit-update.yml @@ -11,7 +11,7 @@ jobs: auto-update: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index e9ba1a01b..d22888093 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -27,7 +27,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: submodules: recursive diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 37e15a472..4c1afcd4d 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -54,7 +54,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 @@ -108,10 +108,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Conda install - uses: conda-incubator/setup-miniconda@v2 + uses: conda-incubator/setup-miniconda@v3 with: auto-update-conda: true python-version: ${{ matrix.python-version }} @@ -148,7 +148,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 diff --git a/CHANGELOG.md b/CHANGELOG.md index 648028bc8..dc5a8df29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,17 @@ # 2.0.3 ## Bugfixes - -- Add OrdinalHyperparameter for random forest imputer (#1065). - Fix path for dask scheduler file (#1055). -- Propagate the Scenario random seed to `get_random_design` (#1066) +- Add OrdinalHyperparameter for random forest imputer (#1065). +- Propagate the Scenario random seed to `get_random_design` (#1066). +- Configurations that fail to become incumbents will be added to the rejected lists (#1069). +- SMAC RandomForest doesn't crash when `np.integer` used, i.e. as generated from a `np.random.RandomState` (#1084). + +## Misc +- ci: Update action version (#1072). + +## Minor +- When a custom dask client is provided, emit the warning that the `n_workers` parameter is ignored only if it deviates from its default value, `1` ([#1071](https://github.com/automl/SMAC3/pull/1071)). # 2.0.2 diff --git a/smac/facade/abstract_facade.py b/smac/facade/abstract_facade.py index a5db5ab52..c98451a27 100644 --- a/smac/facade/abstract_facade.py +++ b/smac/facade/abstract_facade.py @@ -190,7 +190,7 @@ def __init__( # In case of multiple jobs, we need to wrap the runner again using DaskParallelRunner if (n_workers := scenario.n_workers) > 1 or dask_client is not None: - if dask_client is not None: + if dask_client is not None and n_workers > 1: logger.warning( "Provided `dask_client`. Ignore `scenario.n_workers`, directly set `n_workers` in `dask_client`." ) diff --git a/smac/intensifier/abstract_intensifier.py b/smac/intensifier/abstract_intensifier.py index b94486727..cb537e9cc 100644 --- a/smac/intensifier/abstract_intensifier.py +++ b/smac/intensifier/abstract_intensifier.py @@ -571,8 +571,12 @@ def update_incumbents(self, config: Configuration) -> None: if len(previous_incumbents) == len(new_incumbents): if previous_incumbents == new_incumbents: - # No changes in the incumbents - self._remove_rejected_config(config_id) + # No changes in the incumbents, we need this clause because we can't use set difference then + if config_id in new_incumbent_ids: + self._remove_rejected_config(config_id) + else: + # config worse than incumbents and thus rejected + self._add_rejected_config(config_id) return else: # In this case, we have to determine which config replaced which incumbent and reject it diff --git a/smac/model/random_forest/random_forest.py b/smac/model/random_forest/random_forest.py index 6d7840d2a..634e0af06 100644 --- a/smac/model/random_forest/random_forest.py +++ b/smac/model/random_forest/random_forest.py @@ -87,7 +87,9 @@ def __init__( self._rf_opts.compute_law_of_total_variance = False self._rf: BinaryForest | None = None self._log_y = log_y - self._rng = regression.default_random_engine(seed) + + # Case to `int` incase we get an `np.integer` type + self._rng = regression.default_random_engine(int(seed)) self._n_trees = n_trees self._n_points_per_tree = n_points_per_tree diff --git a/tests/test_intensifier/test_abstract_intensifier.py b/tests/test_intensifier/test_abstract_intensifier.py index ce980c49b..b8dc91a1c 100644 --- a/tests/test_intensifier/test_abstract_intensifier.py +++ b/tests/test_intensifier/test_abstract_intensifier.py @@ -109,6 +109,48 @@ def test_incumbent_selection_multi_objective(make_scenario, configspace_small, m assert intensifier.get_incumbents() == [config] +def test_config_rejection_single_objective(configspace_small, make_scenario): + """ Tests whether configs are rejected properly if they are worse than the incumbent. """ + scenario = make_scenario(configspace_small, use_instances=False) + runhistory = RunHistory() + intensifier = Intensifier(scenario=scenario) + intensifier.runhistory = runhistory + + configs = configspace_small.sample_configuration(3) + + runhistory.add(config=configs[0], + cost=5, + time=0.0, + seed=0, + status=StatusType.SUCCESS, + force_update=True) + intensifier.update_incumbents(configs[0]) + + assert intensifier._rejected_config_ids == [] + + # add config that yielded better results, updating incumbent and sending prior incumbent to rejected + runhistory.add(config=configs[1], + cost=1, + time=0.0, + seed=0, + status=StatusType.SUCCESS, + force_update=True) + intensifier.update_incumbents(config=configs[1]) + + assert intensifier._rejected_config_ids == [1] + + # add config that is no better should thus go to rejected + runhistory.add(config=configs[2], + cost=1, + time=0.0, + seed=0, + status=StatusType.SUCCESS, + force_update=True) + intensifier.update_incumbents(config=configs[2]) + + assert intensifier._rejected_config_ids == [1, 3] + + def test_incumbent_differences(make_scenario, configspace_small): pass