code: def test_lsdd(lsdd_params):
      (
          n_features,
          n_enc,
          preprocess,
          n_permutations,
          update_x_ref,
          preprocess_at_init,
      ) = lsdd_params
  
      np.random.seed(0)
      torch.manual_seed(0)
  
      x_ref = (
          np.random.randn(n * n_features)
          .reshape(n, n_features)
          .astype(np.float32)
      )
      preprocess_fn, preprocess_kwargs = preprocess
      to_list = False
      if (
          hasattr(preprocess_fn, "__name__")
          and preprocess_fn.__name__ == "preprocess_list"
      ):
          if not preprocess_at_init:
              return
          to_list = True
          x_ref = [_[None, :] for _ in x_ref]
      elif (
          isinstance(preprocess_fn, Callable)
          and "layer" in list(preprocess_kwargs.keys())
          and preprocess_kwargs["model"].__name__ == "HiddenOutput"
      ):
          model = MyModel(n_features)
          layer = preprocess_kwargs["layer"]
          preprocess_fn = partial(
              preprocess_fn,
              model=HiddenOutput(model=model, layer=layer),
          )
      else:
          preprocess_fn = None
  
      cd = LSDDDriftTorch(
          x_ref=x_ref,
          p_val=0.05,
          preprocess_at_init=preprocess_at_init
          if isinstance(preprocess_fn, Callable)
          else False,
          update_x_ref=update_x_ref,
          preprocess_fn=preprocess_fn,
          n_permutations=n_permutations,
      )
  
      perturbation = (
          np.random.normal(size=(n, n_features)) / 100
      )  # LSDD struggles with copies/repeats
      x = x_ref.copy() + perturbation.astype(np.float32)
      preds = cd.predict(x, return_p_val=True)
      assert (
          preds["data"]["is_drift"] == 0
          and preds["data"]["p_val"] >= cd.p_val
      )
      if isinstance(update_x_ref, dict):
          k = list(update_x_ref.keys())[0]
          assert cd.n == len(x) + len(x_ref)
          assert cd.x_ref.shape[0] == min(
              update_x_ref[k], len(x) + len(x_ref)
          )
  
      x_h1 = (
          np.random.randn(n * n_features)
          .reshape(n, n_features)
          .astype(np.float32)
      )
      if to_list:
          x_h1 = [_[None, :] for _ in x_h1]
      preds = cd.predict(x_h1, return_p_val=True)
      if preds["data"]["is_drift"] == 1:
          assert (
              preds["data"]["p_val"]
              < preds["data"]["threshold"]
              == cd.p_val
          )
          assert (
              preds["data"]["distance"]
              > preds["data"]["distance_threshold"]
          )
      else:
          assert (
              preds["data"]["p_val"]
              >= preds["data"]["threshold"]
              == cd.p_val
          )
          assert (
              preds["data"]["distance"]
              <= preds["data"]["distance_threshold"]
          )
  
file_path: alibi-detect/alibi_detect/cd/pytorch/tests/test_lsdd_pt.py
imports: from functools import partial
  from itertools import product
  import numpy
  import pytest
  import torch
  import torch.nn
  from typing import Callable, List
  from alibi_detect.cd.pytorch.lsdd import LSDDDriftTorch
  from alibi_detect.cd.pytorch.preprocess import HiddenOutput, preprocess_drift
label_desc: Use image node_id 3 for calling a global function with example usage: test_lsdd(lsdd_params) without return types