class_docstr: A data module which provides an arbitrary dataset from GlounTS.
  
  Parameters
  ----------
  dataset_name: str
      The GluonTS name of the dataset.
  context_length_multiple: int
      Context length is prediction length x ``context_length_multiple``.
  support_length_multiple: int
      Support time series length is prediction length x ``support_length_multiple``.
  support_set_size: int
      Number of time series in the support set.
  num_queries: int
      Number of queries used for the same support set.
  data_dir: pathlib.Path
      Path to data.
  prediction_length: int
      Number of predicted time steps.
  standardize: bool
      If each time series is standardized.
  batch_size_train: int
      Batch size during training.
  batch_size_val_test: int
      Batch size during validation and testing.
  num_workers: int
      Number of workers.
  seed: int
      The random seed.
  catch22_train: bool
      If catch22 similarity measure is used for support set selection during training.
  catch22_val_test: bool
      If catch22 similarity measure is used for support set selection during validation and testing.
  cheat: float
      Chance of hiding the ground truth in the support set.
class_docstr_tok: ["A","data","module","which","provides","an","arbitrary","dataset","from","GlounTS",".","Parameters","--","--","--","--","--","dataset_name",":","str","The","GluonTS","name","of","the","dataset",".","context_length_multiple",":","int","Context","length","is","prediction","length","x","``","context_length_multiple","``",".","support_length_multiple",":","int","Support","time","series","length","is","prediction","length","x","``","support_length_multiple","``",".","support_set_size",":","int","Number","of","time","series","in","the","support","set",".","num_queries",":","int","Number","of","queries","used","for","the","same","support","set",".","data_dir",":","pathlib.Path","Path","to","data",".","prediction_length",":","int","Number","of","predicted","time","steps",".","standardize",":","bool","If","each","time","series","is","standardized",".","batch_size_train",":","int","Batch","size","during","training",".","batch_size_val_test",":","int","Batch","size","during","validation","and","testing",".","num_workers",":","int","Number","of","workers",".","seed",":","int","The","random","seed",".","catch22_train",":","bool","If","catch22","similarity","measure","is","used","for","support","set","selection","during","training",".","catch22_val_test",":","bool","If","catch22","similarity","measure","is","used","for","support","set","selection","during","validation","and","testing",".","cheat",":","float","Chance","of","hiding","the","ground","truth","in","the","support","set","."]
code: def generate(self) -> None:
      if not self.root.exists():
          self.root.mkdir(parents=True)
  
          # Download data and move to our own managed directory
          with tempfile.TemporaryDirectory() as directory:
              self._materialize(Path(directory))
              source = Path(directory) / self.dataset_name
  
              # Copy and read metadata
              meta_file = self.root / "metadata.json"
              shutil.copyfile(source / "metadata.json", meta_file)
              meta = MetaData.parse_file(meta_file)
  
              # Copy the data and apply filters
              # We filter all ts with length smaller than 3 * prediction length in the train / val set.
              # Since for the train split the prediction-length-long tail is cropped
              # we have that ts in train split are at least 2 * prediction length long.
              # This makes it possible to predict a full prediction length
              # and have a context window of size prediction length.
              filters = self._filters(
                  meta.prediction_length, 3 * meta.prediction_length
              )
              read_transform_write(
                  self.root / "train" / "data.json",
                  filters=filters
                  + [
                      EndOfSeriesCutFilter(meta.prediction_length),
                      ItemIDTransform(),
                  ],
                  source=source / "train" / "data.json",
              )
              num_train = count_lines(self.root / "train" / "data.json")
  
              read_transform_write(
                  self.root / "val" / "data.json",
                  filters=filters + [ItemIDTransform(num_train)],
                  source=source / "train" / "data.json",
              )
  
              # Although we increase the prediction length for the filters here, this does not
              # exclude any more data! The time series is only longer by the prediction length...
              read_transform_write(
                  self.root / "test" / "data.json",
                  filters=self._filters(
                      2 * meta.prediction_length,
                      4 * meta.prediction_length,
                  )
                  + [
                      ItemIDTransform(num_train),
                  ],
                  source=source / "test" / "data.json",
              )
      num_train = count_lines(self.root / "train" / "data.json")
      num_val = count_lines(self.root / "val" / "data.json")
      num_test = count_lines(self.root / "test" / "data.json")
  
      assert num_train == num_val and (
          num_test % num_val == 0
      ), "Splits do not match."
  
      # compute catch22 features
      file = self.root / "catch22" / "features.pkl"
      val_data = (
          DatasetSplits(
              self.meta,
              self.root,
              self.dataset_name,
              self.prediction_length,
              _standardize=False,
          )
          .val()
          .data()
      )
      if not file.exists() and (
          self.catch22_train or self.catch22_val_test
      ):
          file.parent.mkdir(parents=True, exist_ok=True)
  
          ts_features = []
          # running this in parallel with more workers seems to throw errors
          for ts in tqdm(val_data, desc="generate catch22 features"):
              # only use 5000 times steps tail to compute features
              start = max(len(ts) - self.catch22_tail, 0)
              ts_features.append(get_features(ts[start:]))
  
          df = pd.DataFrame(ts_features)
          # remove constant features
          df = df.loc[:, (df != df.iloc[0]).any()]
          df.to_pickle(file)
  
          # compute catch22 nearest neighbours
      file = self.root / "catch22" / "nn_100.pkl"
      if not file.exists() and (
          self.catch22_train or self.catch22_val_test
      ):
          df = normalize_features(self.catch22())
          num_ts = len(val_data)
          # for more than 5000 ts use kd_tree algo
          algo = "brute" if num_ts <= 5000 else "kd_tree"
          num_nn = 100
          nbrs = NearestNeighbors(
              n_neighbors=min(num_ts, num_nn + 1), algorithm=algo
          ).fit(df)
          distances, indices = nbrs.kneighbors(df)
          with open(file, "wb") as f:
              # exclude the query ts itself
              pickle.dump(indices[:, 1:], f)
  
imports: from typing import List, Optional, Literal, Dict, Any
  from pathlib import Path
  from functools import cached_property
  import shutil
  import tempfile
  import pickle
  import pandas
  from tqdm import tqdm
  import catch22
  import pytorch_lightning
  from gluonts.dataset.repository.datasets import materialize_dataset
  from gluonts.dataset.common import MetaData
  from torch.utils.data import DataLoader
  from sklearn.neighbors import NearestNeighbors
  from meta.data.batch import TripletBatch
  from meta.data.sampling import SamplingTripletDataset, SequentialTripletDataset
  from meta.datasets.splits import DatasetSplits
  from meta.data.dataset import TimeSeries
  from meta.datasets.preprocessing import Filter, AbsoluteValueFilter, ConstantTargetFilter, EndOfSeriesCutFilter, MinLengthFilter, read_transform_write, ItemIDTransform
  from meta.datasets.registry import register_data_module
label_desc: Use image node_id 14 for calling the GluonTSDataModule obj's underlying member method code with example usage: obj.generate() without return types