Source code for obsidian.objectives.sequence
"""Wrapper class for combining multiple objectives into a single objective."""
from .base import Objective
from .config import obj_class_dict
from torch import Tensor
[docs]
class Objective_Sequence(Objective):
"""
A composite objective that combines multiple acquisition
objectives into a single objective, potentially single or multi-output
Attributes:
obj_list (list[Objective]): The list of acquisition objectives.
Raises:
TypeError: If the input is not a list of Objective objects.
"""
def __init__(self,
obj_list: list[Objective]) -> None:
if not isinstance(obj_list, list):
raise TypeError('Objective_Sequence input must be a list of objectives')
if not all(isinstance(obj, Objective) for obj in obj_list):
raise TypeError('All elements in the list must be Objective objects')
super().__init__(mo=obj_list[-1]._is_mo)
self.obj_list = obj_list
# None but the last objective can squeeze the multi-output dimension (if at all)
for obj in obj_list[:-1]:
obj._is_mo = True
def __repr__(self):
"""String representation of object"""
return f'{self.__class__.__name__} (obj_list={self.obj_list})'
[docs]
def forward(self,
samples: Tensor,
X: Tensor | None = None) -> Tensor:
"""
Evaluate the objective function(s) on the candidate set samples, X
"""
for obj in self.obj_list:
samples = obj.forward(samples, X=X)
return samples
[docs]
def save_state(self) -> dict:
"""Saves the objective(s) to a state dictionary"""
obj_dict = {'name': self.__class__.__name__,
'obj_list': [obj.save_state() for obj in self.obj_list]}
return obj_dict
[docs]
@classmethod
def load_state(cls, obj_dict: dict):
"""Loads the objective(s) from a state dictionary"""
new_obj_list = []
for obj_dict_i in obj_dict['obj_list']:
obj_class = obj_class_dict[obj_dict_i['name']]
new_obj_list.append(obj_class.load_state(obj_dict_i))
return cls(new_obj_list)