class_docstr: Deep autoencoding Gaussian mixture model for anomaly detection (DAGMM).
  DAGMM combines an autoencoder with a Gaussian mixture model to model the distribution
  of the reconstruction errors. DAGMM jointly optimizes the parameters of the deep autoencoder
  and the mixture model simultaneously in an end-to-end fashion.
  
  - paper: `Bo Zong, Qi Song, Martin Renqiang Min, Wei Cheng, Cristian Lumezanu, Daeki Cho and Haifeng Chen.
    Deep Autoencoding Gaussian Mixture Model for Unsupervised Anomaly Detection. 2018.
    <https://openreview.net/forum?id=BJJLHbb0->`_.
docstr: Trains the anomaly detector (unsupervised) and its post-rule
  (supervised, if labels are given) on the input multiple time series.
  
  :param multiple_train_data: a list of `TimeSeries` of metric values to train the model.
  :param train_config: Additional training config dict with keys:
  
      * | "n_epochs": ``int`` indicating how many times the model must be
        | trained on the timeseries in ``multiple_train_data``. Defaults to 1.
      * | "shuffle": ``bool`` indicating if the ``multiple_train_data`` collection
        | should be shuffled before every epoch. Defaults to True if "n_epochs" > 1.
  :param anomaly_labels: a list of `TimeSeries` indicating which timestamps are  anomalous. Optional.
  :param post_rule_train_config: The config to use for training the
      model's post-rule. The model's default post-rule train config is
      used if none is supplied here.
  
  :return: A list of `TimeSeries` of the model's anomaly scores on the training
      data with each element corresponds to time series from ``multiple_train_data``.
code: def train_multiple(
      self,
      multiple_train_data: List[TimeSeries],
      train_config=None,
      anomaly_labels: List[TimeSeries] = None,
      post_rule_train_config=None,
  ) -> List[TimeSeries]:
      """
      Trains the anomaly detector (unsupervised) and its post-rule
      (supervised, if labels are given) on the input multiple time series.
  
      :param multiple_train_data: a list of `TimeSeries` of metric values to train the model.
      :param train_config: Additional training config dict with keys:
  
          * | "n_epochs": ``int`` indicating how many times the model must be
            | trained on the timeseries in ``multiple_train_data``. Defaults to 1.
          * | "shuffle": ``bool`` indicating if the ``multiple_train_data`` collection
            | should be shuffled before every epoch. Defaults to True if "n_epochs" > 1.
      :param anomaly_labels: a list of `TimeSeries` indicating which timestamps are  anomalous. Optional.
      :param post_rule_train_config: The config to use for training the
          model's post-rule. The model's default post-rule train config is
          used if none is supplied here.
  
      :return: A list of `TimeSeries` of the model's anomaly scores on the training
          data with each element corresponds to time series from ``multiple_train_data``.
      """
      if train_config is None:
          train_config = copy.deepcopy(self._default_train_config)
      n_epochs = train_config.pop("n_epochs", 1)
      shuffle = train_config.pop("shuffle", n_epochs > 1)
  
      if anomaly_labels is not None:
          assert len(multiple_train_data) == len(anomaly_labels)
      else:
          anomaly_labels = [None] * len(multiple_train_data)
      train_scores_list = []
      for _ in range(n_epochs):
          if shuffle:
              random.shuffle(multiple_train_data)
          for train_data, anomaly_series in zip(
              multiple_train_data, anomaly_labels
          ):
              train_scores_list.append(
                  self.train(
                      train_data=train_data,
                      train_config=train_config,
                      anomaly_labels=anomaly_series,
                      post_rule_train_config=post_rule_train_config
                      # FIXME: the post-rule (calibrator and threshold) is trained individually on each time series
                      # but ideally it needs to be re-trained on all of the `train_scores_list`
                  )
              )
      return train_scores_list
  
imports: import copy
  import random
  from typing import List
  import numpy
  import pandas
  from merlion.utils import TimeSeries
  from merlion.models.base import NormalizingConfig
  from merlion.models.anomaly.base import DetectorBase, DetectorConfig, MultipleTimeseriesDetectorMixin
  from merlion.post_process.threshold import AggregateAlarms
  from merlion.utils.misc import ProgressBar, initializer
  from merlion.models.utils.rolling_window_dataset import RollingWindowDataset
label_desc: Use image node_id 9 for calling the DAGMM obj's underlying member method code with example usage: obj.train_multiple(multiple_train_data, train_config, anomaly_labels, post_rule_train_config) and returns: train_scores_list