class_docstr: This is a multi-task dataset that is constructed from the datasets of
  individual tasks. It offers functionality to combine parts of individual
  datasets to construct the inputs necessary for the `MultiTaskGP` models.
  
  The datasets of individual tasks are allowed to represent different sets
  of features. When there are heterogeneous feature sets, calling
  `MultiTaskDataset.X` will result in an error.
docstr: Appends task features, if needed, and concatenates the Xs of datasets to
  produce the `train_X` expected by `MultiTaskGP` and subclasses.
  
  If appending the task features, 0 is reserved for the target task and the
  remaining tasks are populated with 1, 2, ..., len(datasets) - 1.
code: def X(self) -> Tensor:
      """Appends task features, if needed, and concatenates the Xs of datasets to
      produce the `train_X` expected by `MultiTaskGP` and subclasses.
  
      If appending the task features, 0 is reserved for the target task and the
      remaining tasks are populated with 1, 2, ..., len(datasets) - 1.
      """
      if self.has_heterogeneous_features:
          raise UnsupportedError(
              "Concatenating `X`s from datasets with heterogeneous feature sets "
              "is not supported."
          )
      all_Xs = []
      next_task = 1
      for outcome, ds in self.datasets.items():
          if self.task_feature_index is None:
              # Append the task feature index.
              if outcome == self.target_outcome_name:
                  task_feature = 0
              else:
                  task_feature = next_task
                  next_task = next_task + 1
              all_Xs.append(
                  torch.nn.functional.pad(
                      ds.X, (0, 1), value=task_feature
                  )
              )
          else:
              all_Xs.append(ds.X)
      return torch.cat(all_Xs, dim=0)
  
imports: from __future__ import annotations
  import collections
  import warnings
  from typing import Any, Dict, List, Optional, Union
  import torch
  from botorch.exceptions.errors import InputDataError, UnsupportedError
  from botorch.utils.containers import BotorchContainer, SliceContainer
  from torch import long, ones, Tensor
label_desc: Use image node_id 4 for calling the MultiTaskDataset obj's underlying member method code with example usage: obj.X() and returns: torch