docstr: Tests that n-step loss handles LAST time steps properly.
code: def testLossNStepMidMidLastFirst(self, agent_class):
      """Tests that n-step loss handles LAST time steps properly."""
      q_net = DummyNet(self._observation_spec, self._action_spec)
      agent = agent_class(
          self._time_step_spec,
          self._action_spec,
          q_network=q_net,
          optimizer=None,
          n_step_update=3,
      )
  
      observations = tf.constant([[1, 2], [3, 4]], dtype=tf.float32)
      rewards = tf.constant([10, 20], dtype=tf.float32)
      discounts = tf.constant([0.9, 0.9], dtype=tf.float32)
      # MID: use ts.transition
      time_steps = ts.transition(observations, rewards, discounts)
  
      actions = tf.constant([0, 1], dtype=tf.int32)
      action_steps = policy_step.PolicyStep(actions)
  
      second_observations = tf.constant(
          [[5, 6], [7, 8]], dtype=tf.float32
      )
      # MID: use ts.transition
      second_time_steps = ts.transition(
          second_observations, rewards, discounts
      )
  
      third_observations = tf.constant(
          [[9, 10], [11, 12]], dtype=tf.float32
      )
      # LAST: use ts.termination
      third_time_steps = ts.termination(third_observations, rewards)
  
      fourth_observations = tf.constant(
          [[13, 14], [15, 16]], dtype=tf.float32
      )
      # FIRST: use ts.restart
      fourth_time_steps = ts.restart(fourth_observations, batch_size=2)
  
      experience1 = trajectory.from_transition(
          time_steps, action_steps, second_time_steps
      )
      experience2 = trajectory.from_transition(
          second_time_steps, action_steps, third_time_steps
      )
      experience3 = trajectory.from_transition(
          third_time_steps, action_steps, fourth_time_steps
      )
      experience4 = trajectory.from_transition(
          fourth_time_steps, action_steps, fourth_time_steps
      )
  
      experience = tf.nest.map_structure(
          lambda w, x, y, z: tf.stack([w, x, y, z], axis=1),
          experience1,
          experience2,
          experience3,
          experience4,
      )
  
      # Once again we can extend the analysis from testLoss above as follows:
      # Original Q-values are still 5 and 8 for the same reasons.
      # However next Q-values are now zeroed out due to the LAST time step in
      # between. Thus the TD targets become the discounted reward sums, or:
      # 10 + 0.9 * 10 = 19 and 20 + 0.9 * 20 = 38
      # TD errors: 19 - 5 = 14 and 38 - 8 = 30
      # TD loss: 13.5 and 29.5 (Huber loss subtracts 0.5)
      # Overall loss: (13.5 + 29.5) / 2 = 21.5
      expected_loss = 21.5
      loss, _ = agent._loss(experience)
  
      self.evaluate(tf.compat.v1.global_variables_initializer())
      self.assertAllClose(self.evaluate(loss), expected_loss)
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  from absl.testing import parameterized
  import tensorflow
  from tf_agents.agents.dqn import dqn_agent
  from tf_agents.networks import network
  from tf_agents.networks import q_network
  from tf_agents.networks import sequential
  from tf_agents.networks import test_utils
  from tf_agents.specs import tensor_spec
  from tf_agents.trajectories import policy_step
  from tf_agents.trajectories import test_utils
  from tf_agents.trajectories import time_step
  from tf_agents.trajectories import trajectory
  from tf_agents.utils import common
  from tf_agents.utils import test_utils
label_desc: Use image node_id 13 for calling the DqnAgentTest obj's underlying member method code with example usage: obj.testLossNStepMidMidLastFirst(agent_class) without return types