code: def create_from_tensors_parametric_dqn(
      cls,
      trainer: ParametricDQNTrainer,
      mdp_ids: torch.Tensor,
      sequence_numbers: torch.Tensor,
      states: rlt.FeatureData,
      actions: rlt.FeatureData,
      propensities: torch.Tensor,
      rewards: torch.Tensor,
      possible_actions_mask: torch.Tensor,
      possible_actions: rlt.FeatureData,
      max_num_actions: int,
      metrics: Optional[torch.Tensor] = None,
  ):
      reward_network = trainer.reward_network
      assert (
          reward_network is not None
      ), "CFEval requires a trained reward network"
  
      old_q_train_state = trainer.q_network.training
      old_reward_train_state = reward_network.training
      trainer.q_network.train(False)
      reward_network.train(False)
  
      tiled_state = states.float_features.repeat(
          1, max_num_actions
      ).reshape(-1, states.float_features.shape[1])
      assert possible_actions is not None
      # Get Q-value of action taken
      possible_actions_state_concat = (
          rlt.FeatureData(tiled_state),
          possible_actions,
      )
  
      # FIXME: model_values and model_metrics_values should be
      # calculated using q_network_cpe (as in discrete dqn).
      # q_network_cpe has not been added in parametric dqn yet.
      model_values = trainer.q_network(*possible_actions_state_concat)
      optimal_q_values, _ = trainer.get_detached_model_outputs(
          *possible_actions_state_concat
      )
      eval_action_idxs = None
  
      assert (
          model_values.shape[1] == 1
          and model_values.shape[0]
          == possible_actions_mask.shape[0]
          * possible_actions_mask.shape[1]
      ), (
          "Invalid shapes: "
          + str(model_values.shape)
          + " != "
          + str(possible_actions_mask.shape)
      )
      model_values = model_values.reshape(possible_actions_mask.shape)
      optimal_q_values = optimal_q_values.reshape(
          possible_actions_mask.shape
      )
      model_propensities = masked_softmax(
          optimal_q_values,
          # pyre-fixme[6]: For 2nd param expected `float` but got `Tensor`.
          possible_actions_mask,
          trainer.rl_temperature,
      )
  
      rewards_and_metric_rewards = reward_network(
          *possible_actions_state_concat
      )
      model_rewards = rewards_and_metric_rewards[:, :1]
      assert (
          model_rewards.shape[0] * model_rewards.shape[1]
          == possible_actions_mask.shape[0]
          * possible_actions_mask.shape[1]
      ), (
          "Invalid shapes: "
          + str(model_rewards.shape)
          + " != "
          + str(possible_actions_mask.shape)
      )
      model_rewards = model_rewards.reshape(possible_actions_mask.shape)
  
      model_metrics = rewards_and_metric_rewards[:, 1:]
      model_metrics = model_metrics.reshape(
          possible_actions_mask.shape[0], -1
      )
  
      model_rewards_and_metrics_for_logged_action = reward_network(
          states, actions
      )
      model_rewards_for_logged_action = (
          model_rewards_and_metrics_for_logged_action[:, :1]
      )
  
      action_dim = possible_actions.float_features.shape[1]
      action_mask = torch.all(
          possible_actions.float_features.view(
              -1, max_num_actions, action_dim
          )
          == actions.float_features.unsqueeze(dim=1),
          dim=2,
      ).float()
      assert torch.all(action_mask.sum(dim=1) == 1)
      num_metrics = model_metrics.shape[1] // max_num_actions
  
      model_metrics_values = None
      model_metrics_for_logged_action = None
      model_metrics_values_for_logged_action = None
      if num_metrics > 0:
          # FIXME: calculate model_metrics_values when q_network_cpe is added
          # to parametric dqn
          model_metrics_values = model_values.repeat(1, num_metrics)
  
      trainer.q_network.train(old_q_train_state)
      reward_network.train(old_reward_train_state)
  
      return cls(
          mdp_id=mdp_ids,
          sequence_number=sequence_numbers,
          logged_propensities=propensities,
          logged_rewards=rewards,
          action_mask=action_mask,
          model_rewards=model_rewards,
          model_rewards_for_logged_action=model_rewards_for_logged_action,
          model_values=model_values,
          model_metrics_values=model_metrics_values,
          model_metrics_values_for_logged_action=model_metrics_values_for_logged_action,
          model_propensities=model_propensities,
          logged_metrics=metrics,
          model_metrics=model_metrics,
          model_metrics_for_logged_action=model_metrics_for_logged_action,
          # Will compute later
          logged_values=None,
          logged_metrics_values=None,
          possible_actions_mask=possible_actions_mask,
          optimal_q_values=optimal_q_values,
          eval_action_idxs=eval_action_idxs,
      )
  
imports: from __future__ import annotations
  import logging
  import math
  from dataclasses import dataclass, fields
  from typing import cast, Optional, TYPE_CHECKING
  import numpy
  import torch
  import torch.nn
  from reagent.core import types
  from reagent.core.torch_utils import masked_softmax
  from reagent.model_utils.seq2slate_utils import Seq2SlateMode
  from reagent.models.seq2slate import Seq2SlateTransformerNet
label_desc: Use image node_id 3 for calling the EvaluationDataPage obj's underlying member method code with example usage: obj.create_from_tensors_parametric_dqn(cls, trainer, mdp_ids, sequence_numbers, states, actions, propensities, rewards, possible_actions_mask, possible_actions, max_num_actions, metrics) and returns: cls