# Path: guacamol/score_modifier.py
# class ScoreModifier:
# class ChainedModifier(ScoreModifier):
# class LinearModifier(ScoreModifier):
# class SquaredModifier(ScoreModifier):
# class AbsoluteScoreModifier(ScoreModifier):
# class GaussianModifier(ScoreModifier):
# class MinMaxGaussianModifier(ScoreModifier):
# class ClippedScoreModifier(ScoreModifier):
# class SmoothClippedScoreModifier(ScoreModifier):
# class ThresholdedLinearModifier(ScoreModifier):
#     def __call__(self, x):
#     def __init__(self, modifiers: List[ScoreModifier]) -> None:
#     def __call__(self, x):
#     def __init__(self, slope=1.0):
#     def __call__(self, x):
#     def __init__(self, target_value: float, coefficient=1.0) -> None:
#     def __call__(self, x):
#     def __init__(self, target_value: float) -> None:
#     def __call__(self, x):
#     def __init__(self, mu: float, sigma: float) -> None:
#     def __call__(self, x):
#     def __init__(self, mu: float, sigma: float, minimize=False) -> None:
#     def __call__(self, x):
#     def __init__(self, upper_x: float, lower_x=0.0, high_score=1.0, low_score=0.0) -> None:
#     def __call__(self, x):
#     def __init__(self, upper_x: float, lower_x=0.0, high_score=1.0, low_score=0.0) -> None:
#     def __call__(self, x):
#     def __init__(self, threshold: float) -> None:
#     def __call__(self, x):


from functools import partial
from guacamol.score_modifier import LinearModifier, SquaredModifier, AbsoluteScoreModifier, GaussianModifier, \
    MinGaussianModifier, MaxGaussianModifier, ThresholdedLinearModifier, ClippedScoreModifier, \
    SmoothClippedScoreModifier, ChainedModifier
import numpy as np
import pytest
    min_x = 4.4
    max_x = 8.8
    min_score = -3.3
    max_score = 9.2

    modifier = ClippedScoreModifier(upper_x=max_x, lower_x=min_x, high_score=max_score, low_score=min_score)

    # values smaller than min_x should be assigned min_score
    for x in [-2, 0, 4, 4.4]:
        assert modifier(x) == min_score

    # values larger than max_x should be assigned min_score
    for x in [8.8, 9.0, 1000]:
        assert modifier(x) == max_score

    # values in between are interpolated
    slope = (max_score - min_score) / (max_x - min_x)
    for x in [4.4, 4.8, 5.353, 8.034, 8.8]:
        dx = x - min_x
        dy = dx * slope
        assert modifier(x) == pytest.approx(min_score + dy)


def test_clipped_function_inverted():
    # The clipped function also works for decreasing scores
    max_x = 4.4
    min_x = 8.8
    min_score = -3.3
    max_score = 9.2


# Path: guacamol/score_modifier.py
# class ScoreModifier:
# class ChainedModifier(ScoreModifier):
# class LinearModifier(ScoreModifier):
# class SquaredModifier(ScoreModifier):
# class AbsoluteScoreModifier(ScoreModifier):
# class GaussianModifier(ScoreModifier):
# class MinMaxGaussianModifier(ScoreModifier):
# class ClippedScoreModifier(ScoreModifier):
# class SmoothClippedScoreModifier(ScoreModifier):
# class ThresholdedLinearModifier(ScoreModifier):
#     def __call__(self, x):
#     def __init__(self, modifiers: List[ScoreModifier]) -> None:
#     def __call__(self, x):
#     def __init__(self, slope=1.0):
#     def __call__(self, x):
#     def __init__(self, target_value: float, coefficient=1.0) -> None:
#     def __call__(self, x):
#     def __init__(self, target_value: float) -> None:
#     def __call__(self, x):
#     def __init__(self, mu: float, sigma: float) -> None:
#     def __call__(self, x):
#     def __init__(self, mu: float, sigma: float, minimize=False) -> None:
#     def __call__(self, x):
#     def __init__(self, upper_x: float, lower_x=0.0, high_score=1.0, low_score=0.0) -> None:
#     def __call__(self, x):
#     def __init__(self, upper_x: float, lower_x=0.0, high_score=1.0, low_score=0.0) -> None:
#     def __call__(self, x):
#     def __init__(self, threshold: float) -> None:
#     def __call__(self, x):


# Path: tests/test_score_modifier.py
from functools import partial
from guacamol.score_modifier import LinearModifier, SquaredModifier, AbsoluteScoreModifier, GaussianModifier, \
    MinGaussianModifier, MaxGaussianModifier, ThresholdedLinearModifier, ClippedScoreModifier, \
    SmoothClippedScoreModifier, ChainedModifier
import numpy as np
import pytest

    min_x = 4.4
    max_x = 8.8
    min_score = -3.3
    max_score = 9.2

    modifier = ClippedScoreModifier(upper_x=max_x, lower_x=min_x, high_score=max_score, low_score=min_score)

    # values smaller than min_x should be assigned min_score
    for x in [-2, 0, 4, 4.4]:
        assert modifier(x) == min_score

    # values larger than max_x should be assigned min_score
    for x in [8.8, 9.0, 1000]:
        assert modifier(x) == max_score

    # values in between are interpolated
    slope = (max_score - min_score) / (max_x - min_x)
    for x in [4.4, 4.8, 5.353, 8.034, 8.8]:
        dx = x - min_x
        dy = dx * slope
        assert modifier(x) == pytest.approx(min_score + dy)


def test_clipped_function_inverted():
    # The clipped function also works for decreasing scores
    max_x = 4.4
    min_x = 8.8
    min_score = -3.3
    max_score = 9.2


    modifier = ClippedScoreModifier(upper_x=max_x, lower_x=min_x, high_score=max_score, low_score=min_score)