//  [python]
def create_variables(self):

    with tf.name_scope("model_inputs"):
      # raw state representation
      self.states = tf.placeholder(tf.float32, (None, self.state_dim), name="states")

    # rollout action based on current policy
    with tf.name_scope("predict_actions"):
      # initialize actor-critic network
      with tf.variable_scope("actor_network"):
        self.policy_outputs = self.actor_network(self.states)
      with tf.variable_scope("critic_network"):
        self.value_outputs = self.critic_network(self.states)

      # predict actions from policy network
      self.action_scores = tf.identity(self.policy_outputs, name="action_scores")
      # Note 1: tf.multinomial is not good enough to use yet
      # so we don't use self.predicted_actions for now
      self.predicted_actions = tf.multinomial(self.action_scores, 1)

    # get variable list
    actor_network_variables  = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="actor_network")
    critic_network_variables = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope="critic_network")

    # compute loss and gradients
    with tf.name_scope("compute_pg_gradients"):
      # gradients for selecting action from policy network
      self.taken_actions = tf.placeholder(tf.int32, (None,), name="taken_actions")
      self.discounted_rewards = tf.placeholder(tf.float32, (None,), name="discounted_rewards")

      with tf.variable_scope("actor_network", reuse=True):
        self.logprobs = self.actor_network(self.states)

      with tf.variable_scope("critic_network", reuse=True):
        self.estimated_values = self.critic_network(self.states)

      # compute policy loss and regularization loss
      self.cross_entropy_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=self.logprobs, labels=self.taken_actions)
      self.pg_loss            = tf.reduce_mean(self.cross_entropy_loss)
      self.actor_reg_loss     = tf.reduce_sum([tf.reduce_sum(tf.square(x)) for x in actor_network_variables])
      self.actor_loss         = self.pg_loss + self.reg_param * self.actor_reg_loss

      # compute actor gradients
      self.actor_gradients = self.optimizer.compute_gradients(self.actor_loss, actor_network_variables)
      # compute advantages A(s) = R - V(s)
      self.advantages = tf.reduce_sum(self.discounted_rewards - self.estimated_values)
      # compute policy gradients
      for i, (grad, var) in enumerate(self.actor_gradients):
        if grad is not None:
          self.actor_gradients[i] = (grad * self.advantages, var)

      # compute critic gradients
      self.mean_square_loss = tf.reduce_mean(tf.square(self.discounted_rewards - self.estimated_values))
      self.critic_reg_loss  = tf.reduce_sum([tf.reduce_sum(tf.square(x)) for x in critic_network_variables])
      self.critic_loss      = self.mean_square_loss + self.reg_param * self.critic_reg_loss
      self.critic_gradients = self.optimizer.compute_gradients(self.critic_loss, critic_network_variables)

      # collect all gradients
      self.gradients = self.actor_gradients + self.critic_gradients

      # clip gradients
      for i, (grad, var) in enumerate(self.gradients):
        # clip gradients by norm
        if grad is not None:
          self.gradients[i] = (tf.clip_by_norm(grad, self.max_gradient), var)

      # summarize gradients
      for grad, var in self.gradients:
        tf.summary.histogram(var.name, var)
        if grad is not None:
          tf.summary.histogram(var.name + '/gradients', grad)

      # emit summaries
      tf.summary.histogram("estimated_values", self.estimated_values)
      tf.summary.scalar("actor_loss", self.actor_loss)
      tf.summary.scalar("critic_loss", self.critic_loss)
      tf.summary.scalar("reg_loss", self.actor_reg_loss + self.critic_reg_loss)

    # training update
    with tf.name_scope("train_actor_critic"):
      # apply gradients to update actor network
      self.train_op = self.optimizer.apply_gradients(self.gradients)

    self.summarize = tf.summary.merge_all()
    self.no_op = tf.no_op()