Repository: optuna/optuna

Issue:
`PartialFixedSampler` does not handle `None` correctly
### Expected behavior

In the following codes, "x" should be `None`. But sometimes 0 is sampled.

```python
import optuna

def objective(trial):
    x = trial.suggest_categorical("x", (None, 0))
    return 0

tpe = optuna.samplers.TPESampler()
sampler = optuna.samplers.PartialFixedSampler({"x": None}, tpe)
study = optuna.create_study(sampler=sampler)
study.optimize(objective, n_trials=10)
```

```
[I 2022-11-06 14:47:19,010] A new study created in memory with name: no-name-4c144572-cd3b-442a-99d8-962f8401367a
[I 2022-11-06 14:47:19,013] Trial 0 finished with value: 0.0 and parameters: {'x': None}. Best is trial 0 with value: 0.0.
[I 2022-11-06 14:47:19,013] Trial 1 finished with value: 0.0 and parameters: {'x': 0}. Best is trial 0 with value: 0.0.
[I 2022-11-06 14:47:19,014] Trial 2 finished with value: 0.0 and parameters: {'x': None}. Best is trial 0 with value: 0.0.
[I 2022-11-06 14:47:19,014] Trial 3 finished with value: 0.0 and parameters: {'x': 0}. Best is trial 0 with value: 0.0.
[I 2022-11-06 14:47:19,014] Trial 4 finished with value: 0.0 and parameters: {'x': None}. Best is trial 0 with value: 0.0.
[I 2022-11-06 14:47:19,015] Trial 5 finished with value: 0.0 and parameters: {'x': 0}. Best is trial 0 with value: 0.0.
[I 2022-11-06 14:47:19,015] Trial 6 finished with value: 0.0 and parameters: {'x': None}. Best is trial 0 with value: 0.0.
[I 2022-11-06 14:47:19,015] Trial 7 finished with value: 0.0 and parameters: {'x': 0}. Best is trial 0 with value: 0.0.
[I 2022-11-06 14:47:19,016] Trial 8 finished with value: 0.0 and parameters: {'x': 0}. Best is trial 0 with value: 0.0.
[I 2022-11-06 14:47:19,016] Trial 9 finished with value: 0.0 and parameters: {'x': 0}. Best is trial 0 with value: 0.0.
```

### Environment

- Optuna version:3.1.0.dev
- Python version:3.8.6
- OS:macOS-10.16-x86_64-i386-64bit
- (Optional) Other libraries and their versions:


### Error messages, stack traces, or logs

See `Expected behavior`


### Steps to reproduce

See `Expected behavior`

### Additional context (optional)

This code is buggy when param_value is `None`.

https://github.com/optuna/optuna/blob/c155cea56c9fb0f4752a9838e2518d416719f949/optuna/samplers/_partial_fixed.py#L94-L113


Discussion:
I am working on this issue!

Resolving patch:
diff --git a/optuna/samplers/_partial_fixed.py b/optuna/samplers/_partial_fixed.py
--- a/optuna/samplers/_partial_fixed.py
+++ b/optuna/samplers/_partial_fixed.py
@@ -91,10 +91,7 @@ def sample_independent(
         param_distribution: BaseDistribution,
     ) -> Any:
 
-        # If param_name isn't in self._fixed_params.keys(), param_value is set to None.
-        param_value = self._fixed_params.get(param_name)
-
-        if param_value is None:
+        if param_name not in self._fixed_params:
             # Unfixed params are sampled here.
             return self._base_sampler.sample_independent(
                 study, trial, param_name, param_distribution
@@ -102,6 +99,8 @@ def sample_independent(
         else:
             # Fixed params are sampled here.
             # Check if a parameter value is contained in the range of this distribution.
+            param_value = self._fixed_params[param_name]
+
             param_value_in_internal_repr = param_distribution.to_internal_repr(param_value)
             contained = param_distribution._contains(param_value_in_internal_repr)
 


Test patch:
diff --git a/tests/samplers_tests/test_partial_fixed.py b/tests/samplers_tests/test_partial_fixed.py
--- a/tests/samplers_tests/test_partial_fixed.py
+++ b/tests/samplers_tests/test_partial_fixed.py
@@ -115,3 +115,22 @@ def test_call_after_trial_of_base_sampler() -> None:
     with patch.object(base_sampler, "after_trial", wraps=base_sampler.after_trial) as mock_object:
         study.optimize(lambda _: 1.0, n_trials=1)
         assert mock_object.call_count == 1
+
+
+def test_fixed_none_value_sampling() -> None:
+    def objective(trial: Trial) -> float:
+        trial.suggest_categorical("x", (None, 0))
+        return 0.0
+
+    tpe = optuna.samplers.TPESampler()
+
+    with warnings.catch_warnings():
+        warnings.simplefilter("ignore", optuna.exceptions.ExperimentalWarning)
+        # In this following case , "x" should sample only `None`
+        sampler = optuna.samplers.PartialFixedSampler(fixed_params={"x": None}, base_sampler=tpe)
+
+    study = optuna.create_study(sampler=sampler)
+    study.optimize(objective, n_trials=10)
+
+    for trial in study.trials:
+        assert trial.params["x"] is None