Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chimera Objective #455

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft

Chimera Objective #455

wants to merge 7 commits into from

Conversation

jsmz2602
Copy link
Collaborator

@jsmz2602 jsmz2602 commented Jan 3, 2025

This PR introduces Chimera, a general-purpose achievement scalarizing function for multi-target optimization that allows users to establish a hierarchy of targets with relative or absolute thresholds for concurrent optimization.

This implementation includes a new objective class, ChimeraObjective, which follows a similar approach to the DesirabilityObjective. It scalarizes multiple targets into a single score, termed Chimera Merits, which is to be minimized.

For further details, please refer to the following publication:
F. Häse, L.M. Roch, and A. Aspuru-Guzik. Chimera: enabling hierarchy-based multi-objective optimization for self-driving laboratories. Chemical Science 2018, 9(39), 7642-7655.


WIP:

  • Further testing and validation of the ChimeraObjective implementation.
  • Consideration of whether the optimization should be adjusted to a maximization approach, similar to the DesirabilityObjective.
  • Additional documentation and examples to illustrate the usage of ChimeraObjective.

@CLAassistant
Copy link

CLAassistant commented Jan 3, 2025

CLA assistant check
All committers have signed the CLA.

@Scienfitz Scienfitz changed the title Chimera Extension Chimera Objective Jan 3, 2025
@Scienfitz
Copy link
Collaborator

@AVHopp @AdrianSosic PR in draft mode, NOT for review


@define(frozen=True, slots=False)
class ChimeraObjective(Objective):
"""An objective scalarizing multiple targets using desirability values."""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong docstring mentioning desirability
incude a link to the publication, see other code parts (eg edbo) for how to properly include links

)
"The targets considered by the objective."

targets_threshold_values: tuple[float, ...] = field(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targets_ in fornt is not necessary for either of the two threshold attributes

"""The softness parameter regulating the Heaviside function."""

@targets_threshold_values.default
def _default_targets_threshold_values(self) -> tuple[float, ...]:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think there are no rasonable defaults so these should not have defaults
apart from that the defaults you specified do not satisfy the requirements ge(0.0)

arg = -value / softness
return np.exp(-np.logaddexp(0, arg))

def _hard_heaviside(self, value: float) -> float:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the hard function really needed? I think the soft heavyside should just recover the hard one for an extreme value of softness. If so that can simply be sued wherever a hard heaviside is needed


@st.composite
def chimera_objectives(draw: st.DrawFn):
"""Generate :class:`baybe.objectives.chimera.ChimeraObjective` and its reference."""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"and its reference" is not accurate anymore

targets = draw(
st.lists(
numerical_targets(intervals),
min_size=3, # At least 2 targets.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is it set to 3?

# Now draw threshold values one-by-one based on each threshold type.
threshold_values = []
for i, tt in enumerate(threshold_types):
if tt == ThresholdType.ABSOLUTE:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for singletons, always use is and never ==

return are_close


@settings(max_examples=2)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i assume this is for your testing purposes and not supposed to be here genereally?

@settings(max_examples=2)
@given(chimera_obj=chimera_objectives(), data=st.data())
def test_chimera_merits(chimera_obj, data):
"""Validating chimerra merits value with external reference."""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

absolutes=[
tt.value.upper() == "ABSOLUTE" for tt in chimera_obj.threshold_types
],
goals=[g.lower() for g in goals],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicated application of lower?

]

target_vals = data.draw(data_frames(columns=columns))
assume(target_vals.shape[0] >= 6)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does data_frames not have options to specify the amount of rows?

Also, why 6 specifically?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants