code: def test_policy_gradient_optimizer_discrete(self):
      batch_size = 32
      learning_rate = 0.1
      input_param = discrete_input_param()
      gt_net = create_ground_truth_net(input_param)
      obj_func = create_discrete_choice_obj_func(input_param, gt_net)
      optimizer = PolicyGradientOptimizer(
          input_param,
          obj_func,
          batch_size=batch_size,
          learning_rate=learning_rate,
      )
      best_rs_result = random_sample(
          input_param, obj_func, n_generations=20
      )
      n_generations = 100
      for i in range(n_generations):
          (
              sampled_solutions,
              reward,
              sampled_log_probs,
          ) = optimizer.optimize_step()
          mean_reward = torch.mean(reward.data)
          print(
              f"Generation={i}, mean_reward={mean_reward}, "
              f"min_reward={torch.min(reward.data)}, "
              f"mean_sample_prob={torch.mean(torch.exp(sampled_log_probs))}, "
              f"temperature={optimizer.temp}"
          )
      assert (
          abs(best_rs_result - mean_reward) < POLICY_GRADIENT_TEST_THRES
      ), f"Learning not converged. best random search={best_rs_result}, optimizer mean result={mean_reward}"
      # just test sampling() can run
      optimizer.sample(10)
  
imports: import random
  import unittest
  from collections import defaultdict
  from typing import Dict
  import nevergrad
  import numpy
  import torch
  import torch.nn
  from reagent.lite.optimizer import BayesianByBackpropOptimizer, BayesianMLPEnsemblerOptimizer, BayesianOptimizerBase, GREEDY_TEMP, GumbelSoftmaxOptimizer, NeverGradOptimizer, PolicyGradientOptimizer, QLearningOptimizer, RandomSearchOptimizer, sol_to_tensors
label_desc: Use image node_id 6 for calling the TestComboOptimizer obj's underlying member method code with example usage: obj.test_policy_gradient_optimizer_discrete() without return types