Repository: optuna/optuna

Issue:
Tensorboard integration with integers for parameter boundaries
When using the `optuna.integration.tensorboard.TensorBoardCallback` with integer parameters for `suggest_uniform`, a `TypeError` is raised.

## Expected behavior
No TypeError should be raised, instead the integer should be casted to a float.

## Environment

- Optuna version: 2.5.0
- Python version: 3.7.5
- OS: Debian Testing
- (Optional) Other libraries and their versions: Tensorboard 2.4.1

## Error messages, stack traces, or logs

```
Traceback (most recent call last):
  File "tensorboard_test.py", line 13, in <module>
    study.optimize(objective, n_trials=10, timeout=600, callbacks=[tensorboard_callback])
  File "/home/timon/.pyenv/versions/3.7.5/lib/python3.7/site-packages/optuna/study.py", line 385, in optimize
    show_progress_bar=show_progress_bar,
  File "/home/timon/.pyenv/versions/3.7.5/lib/python3.7/site-packages/optuna/_optimize.py", line 73, in _optimize
    progress_bar=progress_bar,
  File "/home/timon/.pyenv/versions/3.7.5/lib/python3.7/site-packages/optuna/_optimize.py", line 178, in _optimize_sequential
    callback(study, frozen_trial)
  File "/home/timon/.pyenv/versions/3.7.5/lib/python3.7/site-packages/optuna/integration/tensorboard.py", line 41, in __call__
    self._initialization(study)
  File "/home/timon/.pyenv/versions/3.7.5/lib/python3.7/site-packages/optuna/integration/tensorboard.py", line 102, in _initialization
    self._add_distributions(trial.distributions)
  File "/home/timon/.pyenv/versions/3.7.5/lib/python3.7/site-packages/optuna/integration/tensorboard.py", line 62, in _add_distributions
    param_name, hp.RealInterval(param_distribution.low, param_distribution.high)
  File "/home/timon/.pyenv/versions/3.7.5/lib/python3.7/site-packages/tensorboard/plugins/hparams/summary_v2.py", line 444, in __init__
    raise TypeError("min_value must be a float: %r" % (min_value,))
TypeError: min_value must be a float: 0
```

## Steps to reproduce

1. Execute the example below

## Reproducible examples (optional)

```python
import optuna
from optuna.integration.tensorboard import TensorBoardCallback

def objective(trial: optuna.trial.Trial) -> float:
    param = trial.suggest_uniform("param", 0, 1)
    return param**2

tensorboard_callback = TensorBoardCallback("logs/", metric_name="value")

study = optuna.create_study()
study.optimize(objective, n_trials=10, callbacks=[tensorboard_callback])
```


Discussion:

Resolving patch:
diff --git a/optuna/integration/tensorboard.py b/optuna/integration/tensorboard.py
--- a/optuna/integration/tensorboard.py
+++ b/optuna/integration/tensorboard.py
@@ -56,34 +56,36 @@ def __call__(self, study: optuna.study.Study, trial: optuna.trial.FrozenTrial) -
     def _add_distributions(
         self, distributions: Dict[str, optuna.distributions.BaseDistribution]
     ) -> None:
+        real_distributions = (
+            optuna.distributions.UniformDistribution,
+            optuna.distributions.LogUniformDistribution,
+            optuna.distributions.DiscreteUniformDistribution,
+        )
+        int_distributions = (optuna.distributions.IntUniformDistribution,)
+        categorical_distributions = (optuna.distributions.CategoricalDistribution,)
+        supported_distributions = (
+            real_distributions + int_distributions + categorical_distributions
+        )
+
         for param_name, param_distribution in distributions.items():
-            if isinstance(param_distribution, optuna.distributions.UniformDistribution):
-                self._hp_params[param_name] = hp.HParam(
-                    param_name, hp.RealInterval(param_distribution.low, param_distribution.high)
-                )
-            elif isinstance(param_distribution, optuna.distributions.LogUniformDistribution):
-                self._hp_params[param_name] = hp.HParam(
-                    param_name, hp.RealInterval(param_distribution.low, param_distribution.high)
-                )
-            elif isinstance(param_distribution, optuna.distributions.DiscreteUniformDistribution):
+            if isinstance(param_distribution, real_distributions):
                 self._hp_params[param_name] = hp.HParam(
-                    param_name, hp.RealInterval(param_distribution.low, param_distribution.high)
+                    param_name,
+                    hp.RealInterval(float(param_distribution.low), float(param_distribution.high)),
                 )
-            elif isinstance(param_distribution, optuna.distributions.IntUniformDistribution):
+            elif isinstance(param_distribution, int_distributions):
                 self._hp_params[param_name] = hp.HParam(
-                    param_name, hp.IntInterval(param_distribution.low, param_distribution.high)
+                    param_name,
+                    hp.IntInterval(param_distribution.low, param_distribution.high),
                 )
-            elif isinstance(param_distribution, optuna.distributions.CategoricalDistribution):
+            elif isinstance(param_distribution, categorical_distributions):
                 self._hp_params[param_name] = hp.HParam(
-                    param_name, hp.Discrete(param_distribution.choices)
+                    param_name,
+                    hp.Discrete(param_distribution.choices),
                 )
             else:
                 distribution_list = [
-                    optuna.distributions.UniformDistribution.__name__,
-                    optuna.distributions.LogUniformDistribution.__name__,
-                    optuna.distributions.DiscreteUniformDistribution.__name__,
-                    optuna.distributions.IntUniformDistribution.__name__,
-                    optuna.distributions.CategoricalDistribution.__name__,
+                    distribution.__name__ for distribution in supported_distributions
                 ]
                 raise NotImplementedError(
                     "The distribution {} is not implemented. "


Test patch:
diff --git a/tests/integration_tests/test_tensorboard.py b/tests/integration_tests/test_tensorboard.py
--- a/tests/integration_tests/test_tensorboard.py
+++ b/tests/integration_tests/test_tensorboard.py
@@ -39,6 +39,23 @@ def test_study_name() -> None:
         shutil.rmtree(dirname)
 
 
+def test_cast_float() -> None:
+    def objective(trial: optuna.trial.Trial) -> float:
+        x = trial.suggest_float("x", 1, 2)
+        y = trial.suggest_float("y", 1, 2, log=True)
+        assert isinstance(x, float)
+        assert isinstance(y, float)
+        return x + y
+
+    dirname = tempfile.mkdtemp()
+    metric_name = "target"
+    study_name = "test_tensorboard_integration"
+
+    tbcallback = TensorBoardCallback(dirname, metric_name)
+    study = optuna.create_study(study_name=study_name)
+    study.optimize(objective, n_trials=1, callbacks=[tbcallback])
+
+
 def test_experimental_warning() -> None:
     with pytest.warns(optuna.exceptions.ExperimentalWarning):
         TensorBoardCallback(dirname="", metric_name="")