Source code for alf_core.oracle.oracle
# 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 time
from typing import Union
import numpy as np
from alf_core.dataclasses import Candidate, LabelledCandidates, State
from alf_core.dataset.base_dataset import BaseDataset
from alf_core.model.base_model import BaseModel
[docs]
class Oracle:
"""Oracle model is used to evaluate new candidates proposed by the search/optimiser process.
For offline optimization tasks, the oracle is the dataset.
For online optimization tasks, the oracle is a model.
"""
def __init__(self, scorer: BaseModel | BaseDataset) -> None:
"""Initialize the oracle with a model or dataset.
Args:
scorer: Either a BaseModel (for online evaluation) or BaseDataset
(for offline evaluation from a dataset).
"""
self.scorer: BaseModel | BaseDataset = scorer
[docs]
def evaluate(
self, candidates: list[Candidate], state: State
) -> tuple[LabelledCandidates, State]:
"""Evaluate candidates and return their labels.
Args:
candidates: List of Candidate objects to evaluate.
state: Current task state (updated with evaluation time).
Returns:
A tuple containing:
- Candidates paired with their evaluated labels
- Updated state with oracle_time metric
"""
t0 = time.perf_counter()
if isinstance(self.scorer, BaseDataset):
evaluated_candidates = self.scorer.query(candidates)
else:
evaluated_candidates = LabelledCandidates(
candidates=candidates, labels=self.scorer.predict(candidates).means
)
t1 = time.perf_counter()
state.round_metrics.metrics.update({"oracle_time": t1 - t0})
return evaluated_candidates, state
[docs]
def get_metrics(self) -> dict[str, Union[float, int, np.number]]:
"""Get metrics from the underlying scorer if available.
Returns:
Dictionary of metric names to values. Returns empty dict if the module
doesn't provide metrics.
"""
if hasattr(self.scorer, "get_metrics"):
return self.scorer.get_metrics()
return {}