Source code for piglot.objectives.synthetic

"""Provide synthetic test functions"""
from __future__ import annotations
from typing import Dict, Type, Any
import os.path
import numpy as np
import torch
import botorch.test_functions.synthetic
from botorch.test_functions.synthetic import SyntheticTestFunction
from piglot.parameter import ParameterSet
from piglot.objective import GenericObjective, ObjectiveResult
from piglot.utils.reductions import Reduction, read_reduction
from piglot.utils.composition.responses import ResponseComposition, FixedFlatteningUtility


[docs] class SyntheticObjective(GenericObjective): """Objective function derived from a synthetic test function.""" def __init__( self, parameters: ParameterSet, name: str, output_dir: str, transform: str = None, composition: Reduction = None, **kwargs, ) -> None: super().__init__( parameters, stochastic=False, composition=self.__composition(composition) if composition is not None else None, output_dir=output_dir, ) test_functions = self.get_test_functions() if name not in test_functions: raise RuntimeError(f'Unknown function {name}. Must be in {list(test_functions.keys())}') self.func = test_functions[name](**kwargs) self.transform = lambda x, y: x if transform == 'mse_composition': self.transform = lambda v, func: torch.square(torch.tensor([v - func.optimal_value])) with open(os.path.join(output_dir, 'optimum_value'), 'w', encoding='utf8') as file: file.write(f'{self.transform(self.func.optimal_value, self.func)}') @staticmethod def __composition(reduction: Reduction) -> ResponseComposition: """Create a response composition from a reduction. Parameters ---------- reduction : Reduction Reduction to apply. Returns ------- ResponseComposition Composition to apply. """ return ResponseComposition( True, False, [1.0], [reduction], [FixedFlatteningUtility(np.array([0.0]))], )
[docs] @staticmethod def get_test_functions() -> Dict[str, Type[SyntheticTestFunction]]: """Return available test functions. Returns ------- Dict[str, Type[SyntheticTestFunction]] Available test functions. """ return { 'ackley': botorch.test_functions.synthetic.Ackley, 'beale': botorch.test_functions.synthetic.Beale, 'branin': botorch.test_functions.synthetic.Branin, 'bukin': botorch.test_functions.synthetic.Bukin, 'cosine8': botorch.test_functions.synthetic.Cosine8, 'drop_wave': botorch.test_functions.synthetic.DropWave, 'dixon_price': botorch.test_functions.synthetic.DixonPrice, 'egg_holder': botorch.test_functions.synthetic.EggHolder, 'griewank': botorch.test_functions.synthetic.Griewank, 'hartmann': botorch.test_functions.synthetic.Hartmann, 'holder_table': botorch.test_functions.synthetic.HolderTable, 'levy': botorch.test_functions.synthetic.Levy, 'michalewicz': botorch.test_functions.synthetic.Michalewicz, 'powell': botorch.test_functions.synthetic.Powell, 'rastrigin': botorch.test_functions.synthetic.Rastrigin, 'rosenbrock': botorch.test_functions.synthetic.Rosenbrock, 'shekel': botorch.test_functions.synthetic.Shekel, 'six_hump_camel': botorch.test_functions.synthetic.SixHumpCamel, 'styblinski_tang': botorch.test_functions.synthetic.StyblinskiTang, 'three_hump_camel': botorch.test_functions.synthetic.ThreeHumpCamel, }
def _objective(self, values: np.ndarray, concurrent: bool = False) -> ObjectiveResult: """Objective computation for analytical functions. Parameters ---------- values : np.ndarray Set of parameters to evaluate the objective for. parallel : bool, optional Whether this call may be concurrent to others, by default False. Returns ------- ObjectiveResult Objective value. """ params = torch.from_numpy(values) value = self.func.evaluate_true(params) if self.composition is not None: value -= self.func.optimal_value elif self.transform is not None: value = self.transform(value, self.func) value = float(value.item()) if self.composition is None: return ObjectiveResult( values, np.array([value]), np.array([value]), scalar_value=value, ) final_value = self.composition.composition(np.array([value]), values) return ObjectiveResult( values, np.array([value]), np.array([final_value]), scalar_value=final_value.item(), )
[docs] @staticmethod def read( config: Dict[str, Any], parameters: ParameterSet, output_dir: str, ) -> SyntheticObjective: """Read the objective from a configuration dictionary. Parameters ---------- config : Dict[str, Any] Terms from the configuration dictionary. parameters : ParameterSet Set of parameters for this problem. output_dir : str Path to the output directory. Returns ------- SyntheticObjective Objective function to optimise. """ # Check for mandatory arguments if 'function' not in config: raise RuntimeError("Missing test function") function = config.pop('function') # Optional arguments composition = None if 'composition' in config: composition = read_reduction(config.pop('composition')) return SyntheticObjective( parameters, function, output_dir, composition=composition, **config, )