#!/usr/bin/env python3

import io
import unittest
import unittest.mock
from typing import Any, Callable, List, Tuple, Union

import torch
from captum._utils.typing import BaselineType, TensorOrTupleOfTensorsGeneric
from captum.attr._core.kernel_shap import KernelShap
from tests.helpers.basic import (
    BaseTest,
    assertTensorAlmostEqual,
    assertTensorTuplesAlmostEqual,
)
from tests.helpers.basic_models import (
    BasicModel_MultiLayer,
    BasicModel_MultiLayer_MultiInput,
)


class Test(BaseTest):
    def setUp(self) -> None:
        super().setUp()
        try:
            import sklearn  # noqa: F401

            assert (
                sklearn.__version__ >= "0.23.0"
            ), "Must have sklearn version 0.23.0 or higher"
        except (ImportError, AssertionError):
            raise unittest.SkipTest("Skipping KernelShap tests, sklearn not available.")

    def test_linear_kernel_shap(self) -> None:
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[20.0, 50.0, 30.0]], requires_grad=True)
        baseline = torch.tensor([[10.0, 20.0, 10.0]], requires_grad=True)

        self._kernel_shap_test_assert(
            net,
            inp,
            [40.0, 120.0, 80.0],
            n_samples=500,
            baselines=baseline,
            expected_coefs=[40.0, 120.0, 80.0],
        )

    def test_simple_kernel_shap(self) -> None:
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[20.0, 50.0, 30.0]], requires_grad=True)
        self._kernel_shap_test_assert(
            net,
            inp,
            [76.66666, 196.66666, 116.66666],
            perturbations_per_eval=(1, 2, 3),
            n_samples=500,
        )

    def test_simple_kernel_shap_with_mask(self) -> None:
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[20.0, 50.0, 30.0]], requires_grad=True)
        self._kernel_shap_test_assert(
            net,
            inp,
            [275.0, 275.0, 115.0],
            feature_mask=torch.tensor([[0, 0, 1]]),
            perturbations_per_eval=(1, 2, 3),
            expected_coefs=[275.0, 115.0],
        )

    @unittest.mock.patch("sys.stderr", new_callable=io.StringIO)
    def test_simple_kernel_shap_with_show_progress(self, mock_stderr) -> None:
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[20.0, 50.0, 30.0]], requires_grad=True)

        # test progress output for each batch size
        for bsz in (1, 2, 3):
            self._kernel_shap_test_assert(
                net,
                inp,
                [76.66666, 196.66666, 116.66666],
                perturbations_per_eval=(bsz,),
                n_samples=500,
                show_progress=True,
            )
            output = mock_stderr.getvalue()

            # to test if progress calculation aligns with the actual iteration
            # all perturbations_per_eval should reach progress of 100%
            assert (
                "Kernel Shap attribution: 100%" in output
            ), f"Error progress output: {repr(output)}"

            mock_stderr.seek(0)
            mock_stderr.truncate(0)

    def test_simple_kernel_shap_with_baselines(self) -> None:
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[20.0, 50.0, 30.0]])
        self._kernel_shap_test_assert(
            net,
            inp,
            [248.0, 248.0, 104.0],
            feature_mask=torch.tensor([[0, 0, 1]]),
            baselines=4,
            perturbations_per_eval=(1, 2, 3),
        )

    def test_simple_batch_kernel_shap(self) -> None:
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[2.0, 10.0, 3.0], [20.0, 50.0, 30.0]], requires_grad=True)
        self._kernel_shap_test_assert(
            net,
            inp,
            [[7.0, 32.5, 10.5], [76.66666, 196.66666, 116.66666]],
            perturbations_per_eval=(1, 2, 3),
            n_samples=20000,
        )

    def test_simple_batch_kernel_shap_with_mask(self) -> None:
        net = BasicModel_MultiLayer()
        inp = torch.tensor([[2.0, 10.0, 3.0], [20.0, 50.0, 30.0]], requires_grad=True)
        self._kernel_shap_test_assert(
            net,
            inp,
            [[39.5, 39.5, 10.5], [275.0, 275.0, 115.0]],
            feature_mask=torch.tensor([[0, 0, 1], [1, 1, 0]]),
            perturbations_per_eval=(1, 2, 3),
            n_samples=100,
            expected_coefs=[[39.5, 10.5], [115.0, 275.0]],
        )

    def test_multi_input_kernel_shap_without_mask(self) -> None:
        net = BasicModel_MultiLayer_MultiInput()
        inp1 = torch.tensor([[23.0, 0.0, 0.0]])
        inp2 = torch.tensor([[20.0, 0.0, 50.0]])
        inp3 = torch.tensor([[0.0, 100.0, 10.0]])
        expected = (
            [[90, 0, 0]],
            [[78, 0, 198]],
            [[0, 398, 38]],
        )
        self._kernel_shap_test_assert(
            net,
            (inp1, inp2, inp3),
            expected,
            additional_input=(1,),
            n_samples=2000,
        )

    def test_multi_input_kernel_shap_with_mask(self) -> None:
        net = BasicModel_MultiLayer_MultiInput()
        inp1 = torch.tensor([[20.0, 50.0, 30.0]])
        inp2 = torch.tensor([[0.0, 100.0, 0.0]])
        inp3 = torch.tensor([[2.0, 10.0, 3.0]])
        mask1 = torch.tensor([[0, 1, 0]])
        mask2 = torch.tensor([[0, 1, 2]])
        mask3 = torch.tensor([[0, 0, 0]])
        expected = (
            [[255.0, 595.0, 255.0]],
            [[255.0, 595.0, 0.0]],
            [[255.0, 255.0, 255.0]],
        )
        self._kernel_shap_test_assert(
            net,
            (inp1, inp2, inp3),
            expected,
            additional_input=(1,),
            feature_mask=(mask1, mask2, mask3),
        )
        expected_with_baseline = (
            [[184, 580.0, 184]],
            [[184, 580.0, -12.0]],
            [[184, 184, 184]],
        )
        self._kernel_shap_test_assert(
            net,
            (inp1, inp2, inp3),
            expected_with_baseline,
            additional_input=(1,),
            feature_mask=(mask1, mask2, mask3),
            baselines=(2, 3.0, 4),
            perturbations_per_eval=(1, 2, 3),
        )

    def test_multi_input_batch_kernel_shap_without_mask(self) -> None:
        net = BasicModel_MultiLayer_MultiInput()
        inp1 = torch.tensor([[23.0, 0.0, 0.0], [20.0, 50.0, 30.0]])
        inp2 = torch.tensor([[20.0, 0.0, 50.0], [0.0, 100.0, 0.0]])
        inp3 = torch.tensor([[0.0, 100.0, 10.0], [0.0, 10.0, 0.0]])
        expected = (
            [[90, 0, 0], [78.0, 198.0, 118.0]],
            [[78, 0, 198], [0.0, 398.0, 0.0]],
            [[0, 398, 38], [0.0, 38.0, 0.0]],
        )
        self._kernel_shap_test_assert(
            net,
            (inp1, inp2, inp3),
            expected,
            additional_input=(1,),
            n_samples=2500,
            expected_coefs=[
                [90.0, 0, 0, 78, 0, 198, 0, 398, 38],
                [78.0, 198.0, 118.0, 0.0, 398.0, 0.0, 0.0, 38.0, 0.0],
            ],
        )

    def test_multi_input_batch_kernel_shap(self) -> None:
        net = BasicModel_MultiLayer_MultiInput()
        inp1 = torch.tensor([[23.0, 100.0, 0.0], [20.0, 50.0, 30.0]])
        inp2 = torch.tensor([[20.0, 50.0, 30.0], [0.0, 100.0, 0.0]])
        inp3 = torch.tensor([[0.0, 100.0, 10.0], [2.0, 10.0, 3.0]])
        mask1 = torch.tensor([[1, 1, 1], [0, 1, 0]])
        mask2 = torch.tensor([[0, 1, 2]])
        mask3 = torch.tensor([[0, 1, 2], [0, 0, 0]])
        expected = (
            [[1088.6666, 1088.6666, 1088.6666], [255.0, 595.0, 255.0]],
            [[76.6666, 1088.6666, 156.6666], [255.0, 595.0, 0.0]],
            [[76.6666, 1088.6666, 156.6666], [255.0, 255.0, 255.0]],
        )
        self._kernel_shap_test_assert(
            net,
            (inp1, inp2, inp3),
            expected,
            additional_input=(1,),
            feature_mask=(mask1, mask2, mask3),
            n_samples=300,
        )
        expected_with_baseline = (
            [[1040, 1040, 1040], [184, 580.0, 184]],
            [[52, 1040, 132], [184, 580.0, -12.0]],
            [[52, 1040, 132], [184, 184, 184]],
        )
        self._kernel_shap_test_assert(
            net,
            (inp1, inp2, inp3),
            expected_with_baseline,
            additional_input=(1,),
            feature_mask=(mask1, mask2, mask3),
            baselines=(2, 3.0, 4),
            perturbations_per_eval=(1, 2, 3),
        )

    # Remaining tests are for cases where forward function returns a scalar
    # as either a float, integer, 0d tensor or 1d tensor.
    def test_single_kernel_shap_scalar_float(self) -> None:
        net = BasicModel_MultiLayer()
        self._single_input_scalar_kernel_shap_assert(
            lambda inp: torch.sum(net(inp)).item()
        )

    def test_single_kernel_shap_scalar_tensor_0d(self) -> None:
        net = BasicModel_MultiLayer()
        self._single_input_scalar_kernel_shap_assert(lambda inp: torch.sum(net(inp)))

    def test_single_kernel_shap_scalar_tensor_1d(self) -> None:
        net = BasicModel_MultiLayer()
        self._single_input_scalar_kernel_shap_assert(
            lambda inp: torch.sum(net(inp)).reshape(1)
        )

    def test_single_kernel_shap_scalar_int(self) -> None:
        net = BasicModel_MultiLayer()
        self._single_input_scalar_kernel_shap_assert(
            lambda inp: int(torch.sum(net(inp)).item())
        )

    def _single_input_scalar_kernel_shap_assert(self, func: Callable) -> None:
        inp = torch.tensor([[2.0, 10.0, 3.0]], requires_grad=True)
        mask = torch.tensor([[0, 0, 1]])

        self._kernel_shap_test_assert(
            func,
            inp,
            [[79.0, 79.0, 21.0]],
            feature_mask=mask,
            perturbations_per_eval=(1,),
            target=None,
        )

    def test_multi_inp_kernel_shap_scalar_tensor_0d(self) -> None:
        net = BasicModel_MultiLayer_MultiInput()
        self._multi_input_scalar_kernel_shap_assert(lambda *inp: torch.sum(net(*inp)))

    def test_multi_inp_kernel_shap_scalar_tensor_1d(self) -> None:
        net = BasicModel_MultiLayer_MultiInput()
        self._multi_input_scalar_kernel_shap_assert(
            lambda *inp: torch.sum(net(*inp)).reshape(1)
        )

    def test_multi_inp_kernel_shap_scalar_tensor_int(self) -> None:
        net = BasicModel_MultiLayer_MultiInput()
        self._multi_input_scalar_kernel_shap_assert(
            lambda *inp: int(torch.sum(net(*inp)).item())
        )

    def test_multi_inp_kernel_shap_scalar_float(self) -> None:
        net = BasicModel_MultiLayer_MultiInput()
        self._multi_input_scalar_kernel_shap_assert(
            lambda *inp: torch.sum(net(*inp)).item()
        )

    def _multi_input_scalar_kernel_shap_assert(self, func: Callable) -> None:
        inp1 = torch.tensor([[23.0, 100.0, 0.0], [20.0, 50.0, 30.0]])
        inp2 = torch.tensor([[20.0, 50.0, 30.0], [0.0, 100.0, 0.0]])
        inp3 = torch.tensor([[0.0, 100.0, 10.0], [20.0, 10.0, 13.0]])
        mask1 = torch.tensor([[1, 1, 1]])
        mask2 = torch.tensor([[0, 1, 2]])
        mask3 = torch.tensor([[0, 1, 2]])
        expected = (
            [[3850.6666, 3850.6666, 3850.6666]],
            [[306.6666, 3850.6666, 410.6666]],
            [[306.6666, 3850.6666, 410.6666]],
        )

        self._kernel_shap_test_assert(
            func,
            (inp1, inp2, inp3),
            expected,
            additional_input=(1,),
            feature_mask=(mask1, mask2, mask3),
            perturbations_per_eval=(1,),
            target=None,
            n_samples=1500,
        )

    def _kernel_shap_test_assert(
        self,
        model: Callable,
        test_input: TensorOrTupleOfTensorsGeneric,
        expected_attr,
        feature_mask: Union[None, TensorOrTupleOfTensorsGeneric] = None,
        additional_input: Any = None,
        perturbations_per_eval: Tuple[int, ...] = (1,),
        baselines: BaselineType = None,
        target: Union[None, int] = 0,
        n_samples: int = 100,
        delta: float = 1.0,
        expected_coefs: Union[None, List[float], List[List[float]]] = None,
        show_progress: bool = False,
    ) -> None:
        for batch_size in perturbations_per_eval:
            kernel_shap = KernelShap(model)
            attributions = kernel_shap.attribute(
                test_input,
                target=target,
                feature_mask=feature_mask,
                additional_forward_args=additional_input,
                baselines=baselines,
                perturbations_per_eval=batch_size,
                n_samples=n_samples,
                show_progress=show_progress,
            )
            assertTensorTuplesAlmostEqual(
                self, attributions, expected_attr, delta=delta, mode="max"
            )

            if expected_coefs is not None:
                # Test with return_input_shape = False
                attributions = kernel_shap.attribute(
                    test_input,
                    target=target,
                    feature_mask=feature_mask,
                    additional_forward_args=additional_input,
                    baselines=baselines,
                    perturbations_per_eval=batch_size,
                    n_samples=n_samples,
                    return_input_shape=False,
                    show_progress=show_progress,
                )
                assertTensorAlmostEqual(
                    self, attributions, expected_coefs, delta=delta, mode="max"
                )


if __name__ == "__main__":
    unittest.main()

[((2126, 2185), 'unittest.mock.patch', 'unittest.mock.patch', (['"""sys.stderr"""'], {'new_callable': 'io.StringIO'}), "('sys.stderr', new_callable=io.StringIO)\n", (2145, 2185), False, 'import unittest\n'), ((13566, 13581), 'unittest.main', 'unittest.main', ([], {}), '()\n', (13579, 13581), False, 'import unittest\n'), ((948, 971), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (969, 971), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((986, 1040), 'torch.tensor', 'torch.tensor', (['[[20.0, 50.0, 30.0]]'], {'requires_grad': '(True)'}), '([[20.0, 50.0, 30.0]], requires_grad=True)\n', (998, 1040), False, 'import torch\n'), ((1060, 1114), 'torch.tensor', 'torch.tensor', (['[[10.0, 20.0, 10.0]]'], {'requires_grad': '(True)'}), '([[10.0, 20.0, 10.0]], requires_grad=True)\n', (1072, 1114), False, 'import torch\n'), ((1401, 1424), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (1422, 1424), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((1439, 1493), 'torch.tensor', 'torch.tensor', (['[[20.0, 50.0, 30.0]]'], {'requires_grad': '(True)'}), '([[20.0, 50.0, 30.0]], requires_grad=True)\n', (1451, 1493), False, 'import torch\n'), ((1768, 1791), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (1789, 1791), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((1806, 1860), 'torch.tensor', 'torch.tensor', (['[[20.0, 50.0, 30.0]]'], {'requires_grad': '(True)'}), '([[20.0, 50.0, 30.0]], requires_grad=True)\n', (1818, 1860), False, 'import torch\n'), ((2279, 2302), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (2300, 2302), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((2317, 2371), 'torch.tensor', 'torch.tensor', (['[[20.0, 50.0, 30.0]]'], {'requires_grad': '(True)'}), '([[20.0, 50.0, 30.0]], requires_grad=True)\n', (2329, 2371), False, 'import torch\n'), ((3193, 3216), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (3214, 3216), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((3231, 3265), 'torch.tensor', 'torch.tensor', (['[[20.0, 50.0, 30.0]]'], {}), '([[20.0, 50.0, 30.0]])\n', (3243, 3265), False, 'import torch\n'), ((3575, 3598), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (3596, 3598), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((3613, 3685), 'torch.tensor', 'torch.tensor', (['[[2.0, 10.0, 3.0], [20.0, 50.0, 30.0]]'], {'requires_grad': '(True)'}), '([[2.0, 10.0, 3.0], [20.0, 50.0, 30.0]], requires_grad=True)\n', (3625, 3685), False, 'import torch\n'), ((3989, 4012), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (4010, 4012), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((4027, 4099), 'torch.tensor', 'torch.tensor', (['[[2.0, 10.0, 3.0], [20.0, 50.0, 30.0]]'], {'requires_grad': '(True)'}), '([[2.0, 10.0, 3.0], [20.0, 50.0, 30.0]], requires_grad=True)\n', (4039, 4099), False, 'import torch\n'), ((4515, 4549), 'tests.helpers.basic_models.BasicModel_MultiLayer_MultiInput', 'BasicModel_MultiLayer_MultiInput', ([], {}), '()\n', (4547, 4549), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((4565, 4597), 'torch.tensor', 'torch.tensor', (['[[23.0, 0.0, 0.0]]'], {}), '([[23.0, 0.0, 0.0]])\n', (4577, 4597), False, 'import torch\n'), ((4613, 4646), 'torch.tensor', 'torch.tensor', (['[[20.0, 0.0, 50.0]]'], {}), '([[20.0, 0.0, 50.0]])\n', (4625, 4646), False, 'import torch\n'), ((4662, 4696), 'torch.tensor', 'torch.tensor', (['[[0.0, 100.0, 10.0]]'], {}), '([[0.0, 100.0, 10.0]])\n', (4674, 4696), False, 'import torch\n'), ((5070, 5104), 'tests.helpers.basic_models.BasicModel_MultiLayer_MultiInput', 'BasicModel_MultiLayer_MultiInput', ([], {}), '()\n', (5102, 5104), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((5120, 5154), 'torch.tensor', 'torch.tensor', (['[[20.0, 50.0, 30.0]]'], {}), '([[20.0, 50.0, 30.0]])\n', (5132, 5154), False, 'import torch\n'), ((5170, 5203), 'torch.tensor', 'torch.tensor', (['[[0.0, 100.0, 0.0]]'], {}), '([[0.0, 100.0, 0.0]])\n', (5182, 5203), False, 'import torch\n'), ((5219, 5251), 'torch.tensor', 'torch.tensor', (['[[2.0, 10.0, 3.0]]'], {}), '([[2.0, 10.0, 3.0]])\n', (5231, 5251), False, 'import torch\n'), ((5268, 5293), 'torch.tensor', 'torch.tensor', (['[[0, 1, 0]]'], {}), '([[0, 1, 0]])\n', (5280, 5293), False, 'import torch\n'), ((5310, 5335), 'torch.tensor', 'torch.tensor', (['[[0, 1, 2]]'], {}), '([[0, 1, 2]])\n', (5322, 5335), False, 'import torch\n'), ((5352, 5377), 'torch.tensor', 'torch.tensor', (['[[0, 0, 0]]'], {}), '([[0, 0, 0]])\n', (5364, 5377), False, 'import torch\n'), ((6249, 6283), 'tests.helpers.basic_models.BasicModel_MultiLayer_MultiInput', 'BasicModel_MultiLayer_MultiInput', ([], {}), '()\n', (6281, 6283), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((6299, 6351), 'torch.tensor', 'torch.tensor', (['[[23.0, 0.0, 0.0], [20.0, 50.0, 30.0]]'], {}), '([[23.0, 0.0, 0.0], [20.0, 50.0, 30.0]])\n', (6311, 6351), False, 'import torch\n'), ((6367, 6419), 'torch.tensor', 'torch.tensor', (['[[20.0, 0.0, 50.0], [0.0, 100.0, 0.0]]'], {}), '([[20.0, 0.0, 50.0], [0.0, 100.0, 0.0]])\n', (6379, 6419), False, 'import torch\n'), ((6435, 6487), 'torch.tensor', 'torch.tensor', (['[[0.0, 100.0, 10.0], [0.0, 10.0, 0.0]]'], {}), '([[0.0, 100.0, 10.0], [0.0, 10.0, 0.0]])\n', (6447, 6487), False, 'import torch\n'), ((7085, 7119), 'tests.helpers.basic_models.BasicModel_MultiLayer_MultiInput', 'BasicModel_MultiLayer_MultiInput', ([], {}), '()\n', (7117, 7119), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((7135, 7189), 'torch.tensor', 'torch.tensor', (['[[23.0, 100.0, 0.0], [20.0, 50.0, 30.0]]'], {}), '([[23.0, 100.0, 0.0], [20.0, 50.0, 30.0]])\n', (7147, 7189), False, 'import torch\n'), ((7205, 7258), 'torch.tensor', 'torch.tensor', (['[[20.0, 50.0, 30.0], [0.0, 100.0, 0.0]]'], {}), '([[20.0, 50.0, 30.0], [0.0, 100.0, 0.0]])\n', (7217, 7258), False, 'import torch\n'), ((7274, 7326), 'torch.tensor', 'torch.tensor', (['[[0.0, 100.0, 10.0], [2.0, 10.0, 3.0]]'], {}), '([[0.0, 100.0, 10.0], [2.0, 10.0, 3.0]])\n', (7286, 7326), False, 'import torch\n'), ((7343, 7379), 'torch.tensor', 'torch.tensor', (['[[1, 1, 1], [0, 1, 0]]'], {}), '([[1, 1, 1], [0, 1, 0]])\n', (7355, 7379), False, 'import torch\n'), ((7396, 7421), 'torch.tensor', 'torch.tensor', (['[[0, 1, 2]]'], {}), '([[0, 1, 2]])\n', (7408, 7421), False, 'import torch\n'), ((7438, 7474), 'torch.tensor', 'torch.tensor', (['[[0, 1, 2], [0, 0, 0]]'], {}), '([[0, 1, 2], [0, 0, 0]])\n', (7450, 7474), False, 'import torch\n'), ((8649, 8672), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (8670, 8672), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((8867, 8890), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (8888, 8890), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((9056, 9079), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (9077, 9079), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((9272, 9295), 'tests.helpers.basic_models.BasicModel_MultiLayer', 'BasicModel_MultiLayer', ([], {}), '()\n', (9293, 9295), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((9510, 9562), 'torch.tensor', 'torch.tensor', (['[[2.0, 10.0, 3.0]]'], {'requires_grad': '(True)'}), '([[2.0, 10.0, 3.0]], requires_grad=True)\n', (9522, 9562), False, 'import torch\n'), ((9578, 9603), 'torch.tensor', 'torch.tensor', (['[[0, 0, 1]]'], {}), '([[0, 0, 1]])\n', (9590, 9603), False, 'import torch\n'), ((9902, 9936), 'tests.helpers.basic_models.BasicModel_MultiLayer_MultiInput', 'BasicModel_MultiLayer_MultiInput', ([], {}), '()\n', (9934, 9936), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((10106, 10140), 'tests.helpers.basic_models.BasicModel_MultiLayer_MultiInput', 'BasicModel_MultiLayer_MultiInput', ([], {}), '()\n', (10138, 10140), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((10344, 10378), 'tests.helpers.basic_models.BasicModel_MultiLayer_MultiInput', 'BasicModel_MultiLayer_MultiInput', ([], {}), '()\n', (10376, 10378), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((10578, 10612), 'tests.helpers.basic_models.BasicModel_MultiLayer_MultiInput', 'BasicModel_MultiLayer_MultiInput', ([], {}), '()\n', (10610, 10612), False, 'from tests.helpers.basic_models import BasicModel_MultiLayer, BasicModel_MultiLayer_MultiInput\n'), ((10823, 10877), 'torch.tensor', 'torch.tensor', (['[[23.0, 100.0, 0.0], [20.0, 50.0, 30.0]]'], {}), '([[23.0, 100.0, 0.0], [20.0, 50.0, 30.0]])\n', (10835, 10877), False, 'import torch\n'), ((10893, 10946), 'torch.tensor', 'torch.tensor', (['[[20.0, 50.0, 30.0], [0.0, 100.0, 0.0]]'], {}), '([[20.0, 50.0, 30.0], [0.0, 100.0, 0.0]])\n', (10905, 10946), False, 'import torch\n'), ((10962, 11016), 'torch.tensor', 'torch.tensor', (['[[0.0, 100.0, 10.0], [20.0, 10.0, 13.0]]'], {}), '([[0.0, 100.0, 10.0], [20.0, 10.0, 13.0]])\n', (10974, 11016), False, 'import torch\n'), ((11033, 11058), 'torch.tensor', 'torch.tensor', (['[[1, 1, 1]]'], {}), '([[1, 1, 1]])\n', (11045, 11058), False, 'import torch\n'), ((11075, 11100), 'torch.tensor', 'torch.tensor', (['[[0, 1, 2]]'], {}), '([[0, 1, 2]])\n', (11087, 11100), False, 'import torch\n'), ((11117, 11142), 'torch.tensor', 'torch.tensor', (['[[0, 1, 2]]'], {}), '([[0, 1, 2]])\n', (11129, 11142), False, 'import torch\n'), ((12271, 12288), 'captum.attr._core.kernel_shap.KernelShap', 'KernelShap', (['model'], {}), '(model)\n', (12281, 12288), False, 'from captum.attr._core.kernel_shap import KernelShap\n'), ((12695, 12789), 'tests.helpers.basic.assertTensorTuplesAlmostEqual', 'assertTensorTuplesAlmostEqual', (['self', 'attributions', 'expected_attr'], {'delta': 'delta', 'mode': '"""max"""'}), "(self, attributions, expected_attr, delta=\n    delta, mode='max')\n", (12724, 12789), False, 'from tests.helpers.basic import BaseTest, assertTensorAlmostEqual, assertTensorTuplesAlmostEqual\n'), ((815, 885), 'unittest.SkipTest', 'unittest.SkipTest', (['"""Skipping KernelShap tests, sklearn not available."""'], {}), "('Skipping KernelShap tests, sklearn not available.')\n", (832, 885), False, 'import unittest\n'), ((1994, 2019), 'torch.tensor', 'torch.tensor', (['[[0, 0, 1]]'], {}), '([[0, 0, 1]])\n', (2006, 2019), False, 'import torch\n'), ((3399, 3424), 'torch.tensor', 'torch.tensor', (['[[0, 0, 1]]'], {}), '([[0, 0, 1]])\n', (3411, 3424), False, 'import torch\n'), ((4255, 4291), 'torch.tensor', 'torch.tensor', (['[[0, 0, 1], [1, 1, 0]]'], {}), '([[0, 0, 1], [1, 1, 0]])\n', (4267, 4291), False, 'import torch\n'), ((13410, 13498), 'tests.helpers.basic.assertTensorAlmostEqual', 'assertTensorAlmostEqual', (['self', 'attributions', 'expected_coefs'], {'delta': 'delta', 'mode': '"""max"""'}), "(self, attributions, expected_coefs, delta=delta,\n    mode='max')\n", (13433, 13498), False, 'from tests.helpers.basic import BaseTest, assertTensorAlmostEqual, assertTensorTuplesAlmostEqual\n')]