Пример #1
0
def test_population_size() -> None:
    # Set `population_size` to 10.
    sampler = NSGAIISampler(population_size=10)

    study = optuna.create_study(directions=["minimize"], sampler=sampler)
    study.optimize(lambda t: [t.suggest_uniform("x", 0, 9)], n_trials=40)

    generations = Counter([
        t.system_attrs[optuna.samplers._nsga2._GENERATION_KEY]
        for t in study.trials
    ])
    assert generations == {0: 10, 1: 10, 2: 10, 3: 10}

    # Set `population_size` to 2.
    sampler = NSGAIISampler(population_size=2)

    study = optuna.create_study(directions=["minimize"], sampler=sampler)
    study.optimize(lambda t: [t.suggest_uniform("x", 0, 9)], n_trials=40)

    generations = Counter([
        t.system_attrs[optuna.samplers._nsga2._GENERATION_KEY]
        for t in study.trials
    ])
    assert generations == {i: 2 for i in range(20)}

    # Invalid population size.
    with pytest.raises(ValueError):
        # Less than 2.
        NSGAIISampler(population_size=1)

    with pytest.raises(TypeError):
        # Not an integer.
        NSGAIISampler(population_size=2.5)  # type: ignore
Пример #2
0
def test_fast_non_dominated_sort_constrained_feasible_infeasible() -> None:
    with warnings.catch_warnings():
        warnings.simplefilter("ignore", optuna.exceptions.ExperimentalWarning)
        sampler = NSGAIISampler(constraints_func=lambda _: [0])

    # Single objective.
    directions = [StudyDirection.MINIMIZE]
    trials = [
        _create_frozen_trial(0, [10], [0]),
        _create_frozen_trial(1, [20], [-1]),
        _create_frozen_trial(2, [20], [-2]),
        _create_frozen_trial(3, [30], [1]),
    ]
    population_per_rank = sampler._fast_non_dominated_sort(trials, directions)
    assert [{t.number
             for t in population} for population in population_per_rank] == [
                 {0},
                 {1, 2},
                 {3},
             ]

    # Two objective.
    directions = [StudyDirection.MAXIMIZE, StudyDirection.MAXIMIZE]
    trials = [
        _create_frozen_trial(0, [10, 30], [-1, -1]),
        _create_frozen_trial(1, [10, 10], [-2, -2]),
        _create_frozen_trial(2, [20, 20], [3, 3]),
        _create_frozen_trial(3, [30, 10], [6, -1]),
        _create_frozen_trial(4, [15, 15], [4, 4]),
    ]
    population_per_rank = sampler._fast_non_dominated_sort(trials, directions)
    assert [{t.number
             for t in population} for population in population_per_rank] == [
                 {0},
                 {1},
                 {2, 3},
                 {4},
             ]

    # Three objective.
    directions = [
        StudyDirection.MAXIMIZE, StudyDirection.MAXIMIZE,
        StudyDirection.MINIMIZE
    ]
    trials = [
        _create_frozen_trial(0, [5, 5, 4], [-1, -1, -1]),
        _create_frozen_trial(1, [5, 5, 5], [1, 1, -1]),
        _create_frozen_trial(2, [9, 9, 0], [1, -1, -1]),
        _create_frozen_trial(3, [5, 7, 5], [-1, -1, -1]),
        _create_frozen_trial(4, [0, 0, 9], [-1, -1, -1]),
        _create_frozen_trial(5, [0, 9, 9], [-1, -1, -1]),
    ]
    population_per_rank = sampler._fast_non_dominated_sort(trials, directions)
    assert [{t.number
             for t in population} for population in population_per_rank] == [
                 {0, 3, 5},
                 {4},
                 {2},
                 {1},
             ]
Пример #3
0
def test_reseed_rng() -> None:
    sampler = NSGAIISampler(population_size=10)
    original_seed = sampler._rng.seed
    original_random_sampler_seed = sampler._random_sampler._rng.seed

    sampler.reseed_rng()
    assert original_seed != sampler._rng.seed
    assert original_random_sampler_seed != sampler._random_sampler._rng.seed
Пример #4
0
def test_fast_non_dominated_sort_empty(n_dims: int) -> None:
    for directions in itertools.product(
        [StudyDirection.MINIMIZE, StudyDirection.MAXIMIZE], repeat=n_dims):
        trials: List[FrozenTrial] = []
        sampler = NSGAIISampler()
        population_per_rank = sampler._fast_non_dominated_sort(
            trials, list(directions))
        assert population_per_rank == []
Пример #5
0
def test_fast_non_dominated_sort() -> None:
    sampler = NSGAIISampler()

    # Single objective.
    directions = [StudyDirection.MINIMIZE]
    trials = [
        _create_frozen_trial(0, [10]),
        _create_frozen_trial(1, [20]),
        _create_frozen_trial(2, [20]),
        _create_frozen_trial(3, [30]),
    ]
    population_per_rank = sampler._fast_non_dominated_sort(trials, directions)
    assert [{t.number
             for t in population} for population in population_per_rank] == [
                 {0},
                 {1, 2},
                 {3},
             ]

    # Two objective.
    directions = [StudyDirection.MAXIMIZE, StudyDirection.MAXIMIZE]
    trials = [
        _create_frozen_trial(0, [10, 30]),
        _create_frozen_trial(1, [10, 10]),
        _create_frozen_trial(2, [20, 20]),
        _create_frozen_trial(3, [30, 10]),
        _create_frozen_trial(4, [15, 15]),
    ]
    population_per_rank = sampler._fast_non_dominated_sort(trials, directions)
    assert [{t.number
             for t in population} for population in population_per_rank] == [
                 {0, 2, 3},
                 {4},
                 {1},
             ]

    # Three objective.
    directions = [
        StudyDirection.MAXIMIZE, StudyDirection.MAXIMIZE,
        StudyDirection.MINIMIZE
    ]
    trials = [
        _create_frozen_trial(0, [5, 5, 4]),
        _create_frozen_trial(1, [5, 5, 5]),
        _create_frozen_trial(2, [9, 9, 0]),
        _create_frozen_trial(3, [5, 7, 5]),
        _create_frozen_trial(4, [0, 0, 9]),
        _create_frozen_trial(5, [0, 9, 9]),
    ]
    population_per_rank = sampler._fast_non_dominated_sort(trials, directions)
    assert [{t.number
             for t in population} for population in population_per_rank] == [
                 {2},
                 {0, 3, 5},
                 {1},
                 {4},
             ]
Пример #6
0
def test_crossover_prob() -> None:
    NSGAIISampler(crossover_prob=0.0)
    NSGAIISampler(crossover_prob=0.5)
    NSGAIISampler(crossover_prob=1.0)

    with pytest.raises(ValueError):
        NSGAIISampler(crossover_prob=-0.5)

    with pytest.raises(ValueError):
        NSGAIISampler(crossover_prob=1.1)
Пример #7
0
def test_swapping_prob() -> None:
    NSGAIISampler(swapping_prob=0.0)
    NSGAIISampler(swapping_prob=0.5)
    NSGAIISampler(swapping_prob=1.0)

    with pytest.raises(ValueError):
        NSGAIISampler(swapping_prob=-0.5)

    with pytest.raises(ValueError):
        NSGAIISampler(swapping_prob=1.1)
Пример #8
0
def test_fast_non_dominated_sort_no_constraints(
        direction1: StudyDirection, direction2: StudyDirection) -> None:
    sampler = NSGAIISampler()

    directions = [direction1, direction2]
    value_list = [10, 20, 20, 30, float("inf"), float("inf"), -float("inf")]
    values = [[v1, v2] for v1 in value_list for v2 in value_list]

    trials = [_create_frozen_trial(i, v) for i, v in enumerate(values)]
    population_per_rank = sampler._fast_non_dominated_sort(
        copy.copy(trials), directions)
    _assert_population_per_rank(trials, directions, population_per_rank)
Пример #9
0
def test_study_system_attr_for_population_cache() -> None:
    sampler = NSGAIISampler(population_size=10)
    study = optuna.create_study(directions=["minimize"], sampler=sampler)

    def get_cached_entries(
        study: optuna.study.Study, ) -> List[Tuple[int, List[int]]]:
        return [
            v for k, v in study.system_attrs.items() if k.startswith(
                optuna.samplers._nsga2._POPULATION_CACHE_KEY_PREFIX)
        ]

    study.optimize(lambda t: [t.suggest_uniform("x", 0, 9)], n_trials=10)
    cached_entries = get_cached_entries(study)
    assert len(cached_entries) == 0

    study.optimize(lambda t: [t.suggest_uniform("x", 0, 9)], n_trials=1)
    cached_entries = get_cached_entries(study)
    assert len(cached_entries) == 1
    assert cached_entries[0][0] == 0  # Cached generation.
    assert len(cached_entries[0][1]) == 10  # Population size.

    study.optimize(lambda t: [t.suggest_uniform("x", 0, 9)], n_trials=10)
    cached_entries = get_cached_entries(study)
    assert len(cached_entries) == 1
    assert cached_entries[0][0] == 1  # Cached generation.
    assert len(cached_entries[0][1]) == 10  # Population size.
Пример #10
0
def test_constraints_func_nan() -> None:
    n_trials = 4
    n_objectives = 2

    def constraints_func(_: FrozenTrial) -> Sequence[float]:
        return (float("nan"), )

    with warnings.catch_warnings():
        warnings.simplefilter("ignore", optuna.exceptions.ExperimentalWarning)
        sampler = NSGAIISampler(population_size=2,
                                constraints_func=constraints_func)

    study = optuna.create_study(directions=["minimize"] * n_objectives,
                                sampler=sampler)
    with pytest.raises(ValueError):
        study.optimize(
            lambda t:
            [t.suggest_float(f"x{i}", 0, 1) for i in range(n_objectives)],
            n_trials=n_trials,
        )

    trials = study.get_trials()
    assert len(
        trials
    ) == 1  # The error stops optimization, but completed trials are recorded.
    assert all(0 <= x <= 1
               for x in trials[0].params.values())  # The params are normal.
    assert trials[0].values == list(
        trials[0].params.values())  # The values are normal.
    assert trials[0].system_attrs[
        _CONSTRAINTS_KEY] is None  # None is set for constraints.
Пример #11
0
def test_constraints_func() -> None:
    n_trials = 4
    n_objectives = 2
    constraints_func_call_count = 0

    def constraints_func(trial: FrozenTrial) -> Sequence[float]:
        nonlocal constraints_func_call_count
        constraints_func_call_count += 1

        return (trial.number, )

    with warnings.catch_warnings():
        warnings.simplefilter("ignore", optuna.exceptions.ExperimentalWarning)
        sampler = NSGAIISampler(population_size=2,
                                constraints_func=constraints_func)

    study = optuna.create_study(directions=["minimize"] * n_objectives,
                                sampler=sampler)
    study.optimize(
        lambda t:
        [t.suggest_float(f"x{i}", 0, 1) for i in range(n_objectives)],
        n_trials=n_trials)

    assert len(study.trials) == n_trials
    assert constraints_func_call_count == n_trials
    for trial in study.trials:
        assert trial.system_attrs[_CONSTRAINTS_KEY] == (trial.number, )
Пример #12
0
def test_call_after_trial_of_random_sampler() -> None:
    sampler = NSGAIISampler()
    study = optuna.create_study(sampler=sampler)
    with patch.object(
        sampler._random_sampler, "after_trial", wraps=sampler._random_sampler.after_trial
    ) as mock_object:
        study.optimize(lambda _: 1.0, n_trials=1)
        assert mock_object.call_count == 1
Пример #13
0
def test_fast_non_dominated_sort_missing_constraint_values() -> None:
    with warnings.catch_warnings():
        warnings.simplefilter("ignore", optuna.exceptions.ExperimentalWarning)
        sampler = NSGAIISampler(constraints_func=lambda _: [0])

    # Single objective.
    directions = [StudyDirection.MINIMIZE]
    trials = [
        _create_frozen_trial(0, [10]),
        _create_frozen_trial(1, [20]),
        _create_frozen_trial(2, [20], [0]),
        _create_frozen_trial(3, [20], [1]),
        _create_frozen_trial(4, [30], [-1]),
    ]
    with pytest.warns(UserWarning):
        population_per_rank = sampler._fast_non_dominated_sort(
            trials, directions)
    assert [{t.number
             for t in population} for population in population_per_rank] == [
                 {2},
                 {4},
                 {3},
                 {0},
                 {1},
             ]

    # Two objectives.
    directions = [StudyDirection.MAXIMIZE, StudyDirection.MAXIMIZE]
    trials = [
        _create_frozen_trial(0, [50, 30]),
        _create_frozen_trial(1, [30, 50]),
        _create_frozen_trial(2, [20, 20], [3, 3]),
        _create_frozen_trial(3, [30, 10], [0, -1]),
        _create_frozen_trial(4, [15, 15], [4, 4]),
    ]
    with pytest.warns(UserWarning):
        population_per_rank = sampler._fast_non_dominated_sort(
            trials, directions)
    assert [{t.number
             for t in population} for population in population_per_rank] == [
                 {3},
                 {2},
                 {4},
                 {0, 1},
             ]
Пример #14
0
def test_crossover() -> None:
    NSGAIISampler()
    NSGAIISampler(crossover="uniform")
    NSGAIISampler(crossover="blxalpha")
    NSGAIISampler(crossover="sbx")
    NSGAIISampler(crossover="vsbx")
    NSGAIISampler(crossover="undx")
    NSGAIISampler(crossover="spx")

    with pytest.raises(ValueError):
        NSGAIISampler(crossover="no_imp_crossover")
Пример #15
0
def test_fast_non_dominated_sort_missing_constraint_values(
        values_and_constraints: List[Tuple[List[float], List[float]]]) -> None:
    with warnings.catch_warnings():
        warnings.simplefilter("ignore", optuna.exceptions.ExperimentalWarning)
        sampler = NSGAIISampler(constraints_func=lambda _: [0])

    values_dim = len(values_and_constraints[0][0])
    for directions in itertools.product(
        [StudyDirection.MINIMIZE, StudyDirection.MAXIMIZE], repeat=values_dim):
        trials = [
            _create_frozen_trial(i, v, c)
            for i, (v, c) in enumerate(values_and_constraints)
        ]

        with pytest.warns(UserWarning):
            population_per_rank = sampler._fast_non_dominated_sort(
                copy.copy(trials), list(directions))
        _assert_population_per_rank(trials, list(directions),
                                    population_per_rank)
Пример #16
0
def test_crossover_invalid_population(crossover: BaseCrossover) -> None:
    n_objectives = 2
    n_trials = 8

    with pytest.raises(ValueError):
        sampler = NSGAIISampler(population_size=2, crossover=crossover)
        study = optuna.create_study(directions=["minimize"] * n_objectives, sampler=sampler)
        study.optimize(
            lambda t: [t.suggest_float(f"x{i}", 0, 1) for i in range(n_objectives)],
            n_trials=n_trials,
        )
Пример #17
0
def test_fast_non_dominated_sort_with_constraints() -> None:
    with warnings.catch_warnings():
        warnings.simplefilter("ignore", optuna.exceptions.ExperimentalWarning)
        sampler = NSGAIISampler(constraints_func=lambda _: [0])

    value_list = [10, 20, 20, 30, float("inf"), float("inf"), -float("inf")]
    values = [[v1, v2] for v1 in value_list for v2 in value_list]

    constraint_list = [-float("inf"), -2, 0, 1, 2, 3, float("inf")]
    constraints = [[c1, c2] for c1 in constraint_list
                   for c2 in constraint_list]

    trials = [
        _create_frozen_trial(i, v, c)
        for i, (v, c) in enumerate(itertools.product(values, constraints))
    ]
    directions = [StudyDirection.MINIMIZE, StudyDirection.MAXIMIZE]
    population_per_rank = sampler._fast_non_dominated_sort(
        copy.copy(trials), directions)
    _assert_population_per_rank(trials, directions, population_per_rank)
Пример #18
0
def test_constraints_func_none() -> None:
    n_trials = 4
    n_objectives = 2

    sampler = NSGAIISampler(population_size=2)

    study = optuna.create_study(directions=["minimize"] * n_objectives, sampler=sampler)
    study.optimize(
        lambda t: [t.suggest_float(f"x{i}", 0, 1) for i in range(n_objectives)], n_trials=n_trials
    )

    assert len(study.trials) == n_trials
    for trial in study.trials:
        assert _CONSTRAINTS_KEY not in trial.system_attrs
Пример #19
0
def test_mutation_prob() -> None:
    NSGAIISampler(mutation_prob=None)
    NSGAIISampler(mutation_prob=0.0)
    NSGAIISampler(mutation_prob=0.5)
    NSGAIISampler(mutation_prob=1.0)

    with pytest.raises(ValueError):
        NSGAIISampler(mutation_prob=-0.5)

    with pytest.raises(ValueError):
        NSGAIISampler(mutation_prob=1.1)
Пример #20
0
def test_crossover_invalid_population(crossover: BaseCrossover,
                                      population_size: int) -> None:
    with pytest.raises(ValueError):
        NSGAIISampler(population_size=population_size, crossover=crossover)
Пример #21
0
    NSGAIISampler()
    NSGAIISampler(crossover="uniform")
    NSGAIISampler(crossover="blxalpha")
    NSGAIISampler(crossover="sbx")
    NSGAIISampler(crossover="vsbx")
    NSGAIISampler(crossover="undx")
    NSGAIISampler(crossover="spx")

    with pytest.raises(ValueError):
        NSGAIISampler(crossover="no_imp_crossover")


parametrize_nsga2_sampler = pytest.mark.parametrize(
    "sampler_class",
    [
        lambda: NSGAIISampler(population_size=2, crossover="uniform"),
        lambda: NSGAIISampler(population_size=2, crossover="blxalpha"),
        lambda: NSGAIISampler(population_size=2, crossover="sbx"),
        lambda: NSGAIISampler(population_size=2, crossover="vsbx"),
        lambda: NSGAIISampler(population_size=3, crossover="undx"),
        lambda: NSGAIISampler(population_size=3, crossover="spx"),
    ],
)


@parametrize_nsga2_sampler
@pytest.mark.parametrize("n_objectives", [1, 2, 3])
def test_crossover_objectives(
        n_objectives: int, sampler_class: Callable[[], BaseSampler]) -> None:
    n_trials = 8
Пример #22
0
def test_constraints_func_experimental_warning() -> None:
    with pytest.warns(optuna.exceptions.ExperimentalWarning):
        NSGAIISampler(constraints_func=lambda _: [0])
Пример #23
0
def test_call_after_trial_of_random_sampler() -> None:
    sampler = NSGAIISampler()
    study = optuna.create_study(sampler=sampler)
    with patch.object(
            sampler._random_sampler,
            "after_trial",
            wraps=sampler._random_sampler.after_trial) as mock_object:
        study.optimize(lambda _: 1.0, n_trials=1)
        assert mock_object.call_count == 1


parametrize_nsga2_sampler = pytest.mark.parametrize(
    "sampler_class",
    [
        lambda: NSGAIISampler(population_size=2, crossover=UniformCrossover()),
        lambda: NSGAIISampler(population_size=2, crossover=BLXAlphaCrossover()
                              ),
        lambda: NSGAIISampler(population_size=2, crossover=SBXCrossover()),
        lambda: NSGAIISampler(population_size=2, crossover=VSBXCrossover()),
        lambda: NSGAIISampler(population_size=3, crossover=UNDXCrossover()),
        lambda: NSGAIISampler(population_size=3, crossover=UNDXCrossover()),
    ],
)


@parametrize_nsga2_sampler
@pytest.mark.parametrize("n_objectives", [1, 2, 3])
def test_crossover_objectives(
        n_objectives: int, sampler_class: Callable[[], BaseSampler]) -> None:
    n_trials = 8