class_docstr: This class specifies the basic skeleton for a random model.
  
  As random generators do not make use of models, they do not implement
  the fit or predict methods.
  
  These models do not need data, or optimization configs.
  
  To satisfy search space parameter constraints, these models can use
  rejection sampling. To enable rejection sampling for a subclass, only
  only `_gen_samples` needs to be implemented, or alternatively,
  `_gen_unconstrained`/`gen` can be directly implemented.
  
  Attributes:
      deduplicate: If True (defaults to True), a single instantiation
          of the model will not return the same point twice. This flag
          is used in rejection sampling.
      seed: An optional seed value for scrambling.
      generated_points: A set of previously generated points to use
          for deduplication. These should be provided in the raw transformed
          space the model operates in.
      fallback_to_sample_polytope: If True, when rejection sampling fails,
          we fall back to the HitAndRunPolytopeSampler.
class_docstr_tok: ["This","class","specifies","the","basic","skeleton","for","a","random","model",".","As","random","generators","do","not","make","use","of","models",",","they","do","not","implement","the","fit","or","predict","methods",".","These","models","do","not","need","data",",","or","optimization","configs",".","To","satisfy","search","space","parameter","constraints",",","these","models","can","use","rejection","sampling",".","To","enable","rejection","sampling","for","a","subclass",",","only","only","`","_gen_samples","`","needs","to","be","implemented",",","or","alternatively",",","`","_gen_unconstrained","`","\/","`","gen","`","can","be","directly","implemented",".","Attributes",":","deduplicate",":","If","True","(","defaults","to","True",")",",","a","single","instantiation","of","the","model","will","not","return","the","same","point","twice",".","This","flag","is","used","in","rejection","sampling",".","seed",":","An","optional","seed","value","for","scrambling",".","generated_points",":","A","set","of","previously","generated","points","to","use","for","deduplication",".","These","should","be","provided","in","the","raw","transformed","space","the","model","operates","in",".","fallback_to_sample_polytope",":","If","True",",","when","rejection","sampling","fails",",","we","fall","back","to","the","HitAndRunPolytopeSampler","."]
docstr: Generate new candidates.
  
  Args:
      n: Number of candidates to generate.
      bounds: A list of (lower, upper) tuples for each column of X.
          Defined on [0, 1]^d.
      linear_constraints: A tuple of (A, b). For k linear constraints on
          d-dimensional x, A is (k x d) and b is (k x 1) such that
          A x <= b.
      fixed_features: A map {feature_index: value} for features that
          should be fixed to a particular value during generation.
      model_gen_options: A config dictionary that is passed along to the
          model.
      rounding_func: A function that rounds an optimization result
          appropriately (e.g., according to `round-trip` transformations).
  
  Returns:
      2-element tuple containing
  
      - (n x d) array of generated points.
      - Uniform weights, an n-array of ones for each point.
docstr_tok: ["Generate","new","candidates",".","Args",":","n",":","Number","of","candidates","to","generate",".","bounds",":","A","list","of","(","lower",",","upper",")","tuples","for","each","column","of","X",".","Defined","on","[","0",",","1","]","^d",".","linear_constraints",":","A","tuple","of","(","A",",","b",")",".","For","k","linear","constraints","on","d-dimensional","x",",","A","is","(","k","x","d",")","and","b","is","(","k","x","1",")","such","that","A","x","<","=","b.","fixed_features",":","A","map","{","feature_index",":","value","}","for","features","that","should","be","fixed","to","a","particular","value","during","generation",".","model_gen_options",":","A","config","dictionary","that","is","passed","along","to","the","model",".","rounding_func",":","A","function","that","rounds","an","optimization","result","appropriately","(","e.g.",",","according","to","`","round-trip","`","transformations",")",".","Returns",":","2-element","tuple","containing","-","(","n","x","d",")","array","of","generated","points",".","-","Uniform","weights",",","an","n-array","of","ones","for","each","point","."]
code: def gen(
      self,
      n: int,
      bounds: List[Tuple[float, float]],
      linear_constraints: Optional[
          Tuple[np.ndarray, np.ndarray]
      ] = None,
      fixed_features: Optional[Dict[int, float]] = None,
      model_gen_options: Optional[TConfig] = None,
      rounding_func: Optional[
          Callable[[np.ndarray], np.ndarray]
      ] = None,
  ) -> Tuple[np.ndarray, np.ndarray]:
      """Generate new candidates.
  
      Args:
          n: Number of candidates to generate.
          bounds: A list of (lower, upper) tuples for each column of X.
              Defined on [0, 1]^d.
          linear_constraints: A tuple of (A, b). For k linear constraints on
              d-dimensional x, A is (k x d) and b is (k x 1) such that
              A x <= b.
          fixed_features: A map {feature_index: value} for features that
              should be fixed to a particular value during generation.
          model_gen_options: A config dictionary that is passed along to the
              model.
          rounding_func: A function that rounds an optimization result
              appropriately (e.g., according to `round-trip` transformations).
  
      Returns:
          2-element tuple containing
  
          - (n x d) array of generated points.
          - Uniform weights, an n-array of ones for each point.
  
      """
      tf_indices = tunable_feature_indices(
          bounds=bounds, fixed_features=fixed_features
      )
      if fixed_features:
          fixed_feature_indices = np.array(list(fixed_features.keys()))
      else:
          fixed_feature_indices = np.array([])
  
      validate_bounds(
          bounds=bounds, fixed_feature_indices=fixed_feature_indices
      )
      attempted_draws = 0
      max_draws = None
      if model_gen_options:
          max_draws = model_gen_options.get("max_rs_draws")
          if max_draws is not None:
              max_draws = int(
                  checked_cast_to_tuple((int, float), max_draws)
              )
      try:
          # Always rejection sample, but this only rejects if there are
          # constraints or actual duplicates and deduplicate is specified.
          # If rejection sampling fails, fall back to polytope sampling
          points, attempted_draws = rejection_sample(
              gen_unconstrained=self._gen_unconstrained,
              n=n,
              d=len(bounds),
              tunable_feature_indices=tf_indices,
              linear_constraints=linear_constraints,
              deduplicate=self.deduplicate,
              max_draws=max_draws,
              fixed_features=fixed_features,
              rounding_func=rounding_func,
              existing_points=self.generated_points,
          )
      except SearchSpaceExhausted as e:
          if self.fallback_to_sample_polytope:
              logger.info(
                  "Rejection sampling exceeded specified maximum draws."
                  "Falling back on HitAndRunPolytopeSampler instead of "
                  f"{self.__class__.__name__}."
              )
              # If rejection sampling fails, try polytope sampler.
              polytope_sampler = HitAndRunPolytopeSampler(
                  inequality_constraints=self._convert_inequality_constraints(
                      linear_constraints
                  ),
                  equality_constraints=self._convert_equality_constraints(
                      len(bounds), fixed_features
                  ),
                  interior_point=self._get_last_point(),
                  bounds=self._convert_bounds(bounds),
              )
              num_generated = (
                  len(self.generated_points)
                  if self.generated_points is not None
                  else 0
              )
              points = polytope_sampler.draw(
                  n=n, seed=self.seed + num_generated
              ).numpy()
              # TODO: Should this round & deduplicate?
          else:
              raise e
  
      self.attempted_draws = attempted_draws
      if self.deduplicate:
          if self.generated_points is None:
              self.generated_points = points
          else:
              self.generated_points = np.vstack(
                  [self.generated_points, points]
              )
      return points, np.ones(len(points))
  
imports: from logging import Logger
  from typing import Any, Callable, Dict, List, Optional, Tuple
  import numpy
  import torch
  from ax.exceptions.core import SearchSpaceExhausted
  from ax.models.base import Model
  from ax.models.model_utils import add_fixed_features, rejection_sample, tunable_feature_indices, validate_bounds
  from ax.models.types import TConfig
  from ax.utils.common.docutils import copy_doc
  from ax.utils.common.logger import get_logger
  from ax.utils.common.typeutils import checked_cast, checked_cast_to_tuple
  from botorch.utils.sampling import HitAndRunPolytopeSampler
  from torch import Tensor
label_desc: Use image node_id 2 for calling the RandomModel obj's underlying member method code with example usage: obj.gen(n, bounds, linear_constraints, fixed_features, model_gen_options, rounding_func) and returns: points,  np