class_docstr: Implements REMBO (Bayesian optimization in a linear subspace).
  
  The (D x d) projection matrix A must be provided, and must be that used for
  the initialization. In the original REMBO paper A ~ N(0, 1). Box bounds
  in the low-d space must also be provided, which in the REMBO paper should
  be [(-sqrt(d), sqrt(d)]^d.
  
  Function evaluations happen in the high-D space, and so the arms on the
  experiment will also be tracked in the high-D space. This class maintains
  a list of points in the low-d spac that have been launched, so we can match
  arms in high-D space back to their low-d point on update.
  
  Args:
      A: (D x d) projection matrix.
      initial_X_d: Points in low-d space for initial data.
      bounds_d: Box bounds in the low-d space.
      kwargs: kwargs for BotorchModel init
code: def gen(
      self,
      n: int,
      search_space_digest: SearchSpaceDigest,
      torch_opt_config: TorchOptConfig,
  ) -> TorchGenResults:
      for b in search_space_digest.bounds:
          assert b == (-1, 1)
      # The following can be easily handled in the future when needed
      assert torch_opt_config.linear_constraints is None
      assert torch_opt_config.fixed_features is None
      assert torch_opt_config.pending_observations is None
      # Do gen in the low-dimensional space and project up
      rounding_func = torch_opt_config.rounding_func
      gen_results = super().gen(
          n=n,
          search_space_digest=dataclasses.replace(
              search_space_digest,
              bounds=[(0.0, 1.0)] * len(self.bounds_d),
          ),
          torch_opt_config=dataclasses.replace(
              torch_opt_config, rounding_func=None
          ),
      )
      Xopt = self.from_01(gen_results.points)
      self.X_d.extend([x.clone() for x in Xopt])
      self.X_d_gen.extend([x.clone() for x in Xopt])
      gen_points = self.project_up(Xopt)
      if rounding_func is not None:
          for i in range(len(gen_points)):
              gen_points[i] = rounding_func(gen_points[i])
      return TorchGenResults(
          points=gen_points,
          weights=gen_results.weights,
      )
  
imports: import dataclasses
  from typing import Any, List, Optional, Tuple
  from warnings import warn
  import torch
  from ax.core.search_space import SearchSpaceDigest
  from ax.core.types import TCandidateMetadata
  from ax.models.torch.botorch import BotorchModel
  from ax.models.torch_base import TorchGenResults, TorchModel, TorchOptConfig
  from ax.utils.common.docutils import copy_doc
  from botorch.utils.datasets import SupervisedDataset
  from torch import Tensor
label_desc: Use image node_id 8 for calling the REMBO obj's underlying member method code with example usage: obj.gen(n, search_space_digest, torch_opt_config) and returns: TorchGenResults