code: def test_sum_categories(n_feats, ndim, feat_enc_dim, start_idx):
      """
      Tests if summing the columns corresponding to categorical variables into one variable works properly.
      """
  
      # create inputs to feed the function
      if ndim == 2:
          X = get_random_matrix(n_cols=n_feats)
      else:
          X = np.stack(
              [
                  get_random_matrix(n_rows=n_feats, n_cols=n_feats)
                  for _ in range(2)
              ]
          )
  
      # check a value correct is raised if start indices or
      # encoding lengths are not provided
      if feat_enc_dim is None or start_idx is None:
          with pytest.raises(ValueError) as exc_info:
              summ_X = sum_categories(X, start_idx, feat_enc_dim)
              assert exc_info.type is ValueError
      elif len(feat_enc_dim) != len(start_idx):
          with pytest.raises(ValueError) as exc_info:
              summ_X = sum_categories(X, start_idx, feat_enc_dim)
              assert exc_info.type is ValueError
  
      # check if sum of encodings greater than num columns raises value correct
      elif sum(feat_enc_dim) > n_feats:
          with pytest.raises(ValueError) as exc_info:
              summ_X = sum_categories(X, start_idx, feat_enc_dim)
              assert exc_info.type is ValueError
  
      # check that if inputs are correct, we retrieve the sum in the correct col
      else:
          summ_X = sum_categories(X, start_idx, feat_enc_dim)
          # check the reduction gives the correct dimensions for the reduced array
          assert summ_X.shape[0] == X.shape[0]
          for dim in range(1, len(X.shape)):
              assert summ_X.shape[dim] == X.shape[dim] - sum(
                  feat_enc_dim
              ) + len(feat_enc_dim)
          # check the values in the reduced array are as expected
          for i, enc_dim in enumerate(feat_enc_dim):
              # work out the index of the summed column in the returned matrix
              sum_col_idx = (
                  start_idx[i]
                  - sum(feat_enc_dim[:i])
                  + len(feat_enc_dim[:i])
              )
              expected = summ_X[..., sum_col_idx]
              if ndim == 2:
                  actual = np.sum(
                      X[
                          :,
                          start_idx[i] : start_idx[i] + feat_enc_dim[i],
                      ],
                      axis=1,
                  )
              else:
                  # here we compute the expected result naively ...
                  actual = []
                  for j in range(X.shape[0]):
                      tmp = np.sum(
                          X[
                              j,
                              :,
                              start_idx[i] : start_idx[i]
                              + feat_enc_dim[i],
                          ],
                          axis=1,
                      )
                      res = []
                      tmp_idx = 0
                      for s, nelem in zip(start_idx, feat_enc_dim):
                          res.extend(tuple(tmp[tmp_idx:s]))
                          res.append(np.sum(tmp[s : s + nelem]))
                          tmp_idx += s - tmp_idx + nelem
                      if tmp_idx < len(tmp):
                          res += list(tmp[tmp_idx:])
                      res = np.array(res)
                      actual.append(res)
  
                  actual = np.stack(actual)
                  assert actual.shape == expected.shape
              diff = expected - actual
              assert np.isclose(diff.sum(), 0.0)
  
imports: import itertools
  import logging
  import unittest
  from copy import copy
  from itertools import chain
  from unittest.mock import MagicMock
  from typing import Any, List
  import catboost
  import pandas
  import pytest
  import scipy.sparse
  import sklearn
  import shap
  import numpy
  import pandas
  import shap.utils._legacy
  from numpy.testing import assert_allclose, assert_almost_equal
  from scipy.special import expit
  from alibi.api.defaults import DEFAULT_META_KERNEL_SHAP, DEFAULT_DATA_KERNEL_SHAP, DEFAULT_META_TREE_SHAP, DEFAULT_DATA_TREE_SHAP, KERNEL_SHAP_PARAMS, TREE_SHAP_PARAMS
  from alibi.explainers.shap_wrappers import sum_categories, rank_by_importance, KernelExplainerWrapper
  from alibi.explainers.shap_wrappers import KERNEL_SHAP_BACKGROUND_THRESHOLD, TREE_SHAP_BACKGROUND_WARNING_THRESHOLD
  from alibi.explainers.tests.utils import get_random_matrix
  from alibi.tests.utils import assert_message_in_logs, not_raises
  from alibi.utils import DistributedExplainer
label_desc: Use image node_id 11 for calling a global function with example usage: test_sum_categories(n_feats, ndim, feat_enc_dim, start_idx) without return types