Source code for alf_tools.optimizer.acquisition_functions.expected_improvement
# Copyright 2026 InstaDeep Ltd. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import numpy as np
from alf_core import AcquisitionFunction, Candidate, LabelledCandidates, State
from scipy.stats import norm
[docs]
class ExpectedImprovement(AcquisitionFunction):
"""Expected improvement acquisition function.
The Expected Improvement acquisition value is given by:
EI = (μ - best_f) * Φ(z) + σ * φ(z), where μ is the mean prediction,
σ is the standard deviation, best_f is the best observed value,
z is (μ - best_f) / σ, and Φ and φ are the CDF and PDF of the
standard normal distribution.
Higher EI values indicate more improvement over the best observed value.
This is a maximising acquisition function.
"""
def __call__(self, search_candidates: list[Candidate], state: State) -> LabelledCandidates:
"""Compute Expected Improvement acquisition values for unlabelled candidates.
Args:
search_candidates: List of unlabelled candidates to score.
state: The task state containing the current datasets and surrogate model.
Raises:
ValueError: If `empirical_dist` or `variances` is not found in predictions.
Returns:
LabelledCandidates with Expected Improvement acquisition values.
"""
predictions = state.surrogate.predict(search_candidates)
best_f = state.dataset.train_dataset.labels.max()
if predictions.empirical_dist is not None:
acquisition_values = np.mean(np.maximum(predictions.empirical_dist - best_f, 0), -1)
elif predictions.variances is not None:
mu = predictions.means
sigma = np.sqrt(predictions.variances)
sigma = np.clip(sigma, 1e-9, None)
z = (mu - best_f) / sigma
ei = (mu - best_f) * norm.cdf(z) + sigma * norm.pdf(z)
acquisition_values = np.maximum(ei, 0.0)
else:
raise ValueError(
"Expected either `empirical_dist` or `variances` in predictions, "
"but neither was found. Cannot compute expected improvement."
)
return LabelledCandidates(candidates=search_candidates, labels=acquisition_values)