class_docstr: Generator for Thompson sampling.
  
  The generator performs Thompson sampling on the data passed in via `fit`.
  Arms are given weight proportional to the probability that they are
  winners, according to Monte Carlo simulations.
class_docstr_tok: ["Generator","for","Thompson","sampling",".","The","generator","performs","Thompson","sampling","on","the","data","passed","in","via","`","fit","`",".","Arms","are","given","weight","proportional","to","the","probability","that","they","are","winners",",","according","to","Monte","Carlo","simulations","."]
code: def gen(
      self,
      n: int,
      parameter_values: List[TParamValueList],
      objective_weights: Optional[np.ndarray],
      outcome_constraints: Optional[
          Tuple[np.ndarray, np.ndarray]
      ] = None,
      fixed_features: Optional[Dict[int, TParamValue]] = None,
      pending_observations: Optional[
          List[List[TParamValueList]]
      ] = None,
      model_gen_options: Optional[TConfig] = None,
  ) -> Tuple[List[TParamValueList], List[float], TGenMetadata]:
      if objective_weights is None:
          raise ValueError(
              "ThompsonSampler requires objective weights."
          )
  
      arms = self.X
      k = len(arms)
  
      weights = self._generate_weights(
          objective_weights=objective_weights,
          outcome_constraints=outcome_constraints,
      )
      min_weight = (
          self.min_weight if self.min_weight is not None else 2.0 / k
      )
  
      # Second entry is used for tie-breaking
      weighted_arms = [
          (weights[i], np.random.random(), arms[i])
          for i in range(k)
          if weights[i] > min_weight
      ]
  
      if len(weighted_arms) == 0:
          raise ModelError(
              TS_MIN_WEIGHT_ERROR.format(
                  min_weight=min_weight, max_weight=max(weights)
              )
          )
  
      weighted_arms.sort(reverse=True)
      top_weighted_arms = weighted_arms[:n] if n > 0 else weighted_arms
      top_arms = [arm for _, _, arm in top_weighted_arms]
      top_weights = [weight for weight, _, _ in top_weighted_arms]
  
      # N TS arms should have total weight N
      if self.uniform_weights:
          top_weights = [1.0 for _ in top_weights]
      else:
          top_weights = [
              (x * len(top_weights)) / sum(top_weights)
              for x in top_weights
          ]
      return (
          top_arms,
          top_weights,
          {"arms_to_weights": list(zip(arms, weights))},
      )
  
imports: import hashlib
  import json
  from typing import Dict, List, Optional, Tuple
  import numpy
  from ax.core.types import TGenMetadata, TParamValue, TParamValueList
  from ax.exceptions.constants import TS_MIN_WEIGHT_ERROR, TS_NO_FEASIBLE_ARMS_ERROR
  from ax.exceptions.model import ModelError
  from ax.models.discrete_base import DiscreteModel
  from ax.models.types import TConfig
  from ax.utils.common.docutils import copy_doc
label_desc: Use image node_id 3 for calling the ThompsonSampler obj's underlying member method code with example usage: obj.gen(n, parameter_values, objective_weights, outcome_constraints, fixed_features, pending_observations, model_gen_options) and returns: top_arms,  top_weights,  dict