Repository: facebookresearch/nevergrad

Issue:
KeyError: 'x0' on ParametrizedBO() for 10 or more dimensions
## NeverGrad version
0.4.2

## Steps to reproduce

  1. Optimize 10 params using BO, see code in relevant code.

## Observed Results

```
  File ".\.\venv\lib\site-packages\nevergrad\optimization\optimizerlib.py", line 1457, in <listcomp>
    return self._transform.backward(np.array([self.bo.max["params"][f"x{i}"] for i in range(self.dimension)]))
KeyError: 'x0'
```

## Expected Results

  * No KeyError.

## Relevant Code
Sample code to trigger the KeyError.

  ```python
import nevergrad as ng


def objective(**x):
    a = x['a']
    return (a - .5)**2


iparam = {'a': {'init': 1, 'lower': 0, 'upper': 6},
         'b': {'init': 2, 'lower': 0, 'upper': 6},
         'c': {'init': 4, 'lower': 0, 'upper': 6},
         'd': {'init': 6, 'lower': 0, 'upper': 8},
         'e': {'init': 8, 'lower': 0, 'upper': 10},
         'f': {'init': 10, 'lower': 0, 'upper': 16},
         'g': {'init': 9, 'lower': 0, 'upper': 17},
         'h': {'init': 2, 'lower': 0, 'upper': 6},
         'i': {'init': 7, 'lower': 0, 'upper': 12},
         'j': {'init': 6, 'lower': 0, 'upper': 9}}

arg = {}
for k, v in iparam.items():
    arg.update({k: ng.p.Scalar(init=v['init'], lower=v['lower'],
                               upper=v['upper']).set_integer_casting()})
instrum = ng.p.Instrumentation(**arg)

gp_param = {'alpha': 1e-3, 'n_restarts_optimizer': 5}
my_opt = ng.optimizers.ParametrizedBO(gp_parameters=gp_param, initialization='Hammersley')
optimizer = my_opt(parametrization=instrum, budget=4)

recommendation = optimizer.minimize(objective)  # best value
print(recommendation.value)
  ```

## Issue partial evaluation
If dimension is 10 or more but less than 100.

`self.bo.max["params"][f"x{i}"]` will only accept

`x00, x01 ... `    

but not `x0`

If dimension is 100 or more but less than 1000, it will only accept.  

`x000, x001 ...`

If dimension is 1000 or more but less than 10000, it will only accept.  

`x0000, x0001 ...`

## Partial fix
```python
str_len = len(str(self.dimension))
return self._transform.backward(np.array([self.bo.max["params"][f"x{i:0{str_len}d}"] for i in range(self.dimension)]))
```

## Other Reference
https://github.com/facebookresearch/nevergrad/blob/253fd12c420d29af7742ab24c0fe8e953a782ae4/nevergrad/optimization/optimizerlib.py#L1481





Discussion:

Resolving patch:
diff --git a/nevergrad/optimization/optimizerlib.py b/nevergrad/optimization/optimizerlib.py
--- a/nevergrad/optimization/optimizerlib.py
+++ b/nevergrad/optimization/optimizerlib.py
@@ -1477,10 +1477,11 @@ def _internal_tell_candidate(self, candidate: p.Parameter, loss: tp.FloatLoss) -
         self._fake_function._registered.clear()
 
     def _internal_provide_recommendation(self) -> tp.Optional[tp.ArrayLike]:
-        if self.archive:
-            return self._transform.backward(np.array([self.bo.max["params"][f"x{i}"] for i in range(self.dimension)]))
-        else:
+        if not self.archive:
             return None
+        return self._transform.backward(
+            np.array([self.bo.max["params"][self._fake_function.key(i)] for i in range(self.dimension)])
+        )
 
 
 class ParametrizedBO(base.ConfiguredOptimizer):


Test patch:
diff --git a/nevergrad/optimization/test_optimizerlib.py b/nevergrad/optimization/test_optimizerlib.py
--- a/nevergrad/optimization/test_optimizerlib.py
+++ b/nevergrad/optimization/test_optimizerlib.py
@@ -456,12 +456,16 @@ def test_shiwa_selection(name: str, param: tp.Any, budget: int, num_workers: int
 
 
 def test_bo_ordering() -> None:
-    optim = ng.optimizers.ParametrizedBO(initialization='Hammersley')(
-        parametrization=ng.p.Choice(range(12)),
-        budget=10
-    )
+    with warnings.catch_warnings():
+        # tests do not need to be efficient
+        warnings.filterwarnings("ignore", category=base.InefficientSettingsWarning)
+        optim = ng.optimizers.ParametrizedBO(initialization='Hammersley')(
+            parametrization=ng.p.Choice(range(12)),
+            budget=10
+        )
     cand = optim.ask()
     optim.tell(cand, 12)
+    optim.provide_recommendation()
 
 
 @pytest.mark.parametrize(  # type: ignore