jiahuimbzuai/CoQuIR huggingface dataset:
//  [python]
def _LU(M):
    """
    Perform an LU decomposition and returns L, U and a permutation vector P. 

    Args:
        M (torch.tensor): [description]

    Returns:
        tuple[torch.tensor,torch.tensor,torch.tensor]: L, U, P
    """
    LU,P = tn.linalg.lu_factor(M)
    P,L,U = tn.lu_unpack(LU,P) # P transpose or not transpose?
    P = P@tn.reshape(tn.arange(P.shape[1],dtype=P.dtype,device=P.device),[-1,1])
    # P = tn.reshape(tn.arange(P.shape[1],dtype=P.dtype,device=P.device),[1,-1]) @ P
    
    return L, U, tn.squeeze(P).to(tn.int64)
//  [python]
def test_module_global_hook_invalid_outputs(self):
        module = nn.Sigmoid()
        input = torch.randn(5, 5, requires_grad=True)

        def bw_fail1(self, grad_input, grad_output):
            return grad_input[:-1]

        def bw_fail2(self, grad_input, grad_output):
            return grad_input + (torch.randn(2, 2),)

        with nn.modules.module.register_module_backward_hook(bw_fail1):
            with self.assertRaisesRegex(RuntimeError, "got 0, but expected 1"):
                module(input).sum().backward()

        with nn.modules.module.register_module_backward_hook(bw_fail2):
            with self.assertRaisesRegex(RuntimeError, "got 2, but expected 1"):
                module(input).sum().backward()
//  [python]
def test_module_global_hook_invalid_outputs(self):
        module = nn.Sigmoid()
        input = torch.randn(5, 5, requires_grad=True)

        def bw_fail1(self, grad_input, grad_output):
            return grad_input[:-1]

        def bw_fail2(self, grad_input, grad_output):
            return grad_input + (torch.randn(2, 2),)

        with nn.modules.module.register_module_full_backward_hook(bw_fail1):
            with self.assertRaisesRegex(RuntimeError, "got 0, but expected 1"):
                module(input).sum().backward()

        with nn.modules.module.register_module_full_backward_hook(bw_fail2):
            with self.assertRaisesRegex(RuntimeError, "got 2, but expected 1"):
                module(input).sum().backward()
//  [python]
def test_module_backward_global_hook_writeable(self):
        module = nn.Sigmoid()
        input = torch.randn(5, 5, requires_grad=True)
        sig_x = torch.sigmoid(input)

        def bw_hook(module, grad_input, grad_output):
            for grad in grad_input:
                self.assertTrue(isinstance(grad, torch.Tensor))
            for grad in grad_output:
                self.assertTrue(isinstance(grad, torch.Tensor))
            return tuple(gi * 2 for gi in grad_input)

        nn.modules.module.register_module_backward_hook(bw_hook)
        module(input).backward(torch.ones(5, 5))
        expected_grad = sig_x * (1 - sig_x) * 2
        self.assertEqual(input.grad, expected_grad)
//  [python]
def test_module_backward_global_hook_writeable(self):
        module = nn.Sigmoid()
        input = torch.randn(5, 5, requires_grad=True)
        sig_x = torch.sigmoid(input)

        def bw_hook(module, grad_input, grad_output):
            for grad in grad_input:
                self.assertTrue(isinstance(grad, torch.Tensor))
            for grad in grad_output:
                self.assertTrue(isinstance(grad, torch.Tensor))
            return tuple(gi * 2 for gi in grad_input)

        module.register_full_backward_hook(bw_hook)
        module(input).backward(torch.ones(5, 5))
        expected_grad = sig_x * (1 - sig_x) * 2
        self.assertEqual(input.grad, expected_grad)
//  [python]
def test_module_backward_global_hook_writeable(self):
        module = nn.Sigmoid()
        input = torch.randn(5, 5, requires_grad=True)
        sig_x = torch.nn.functional.sigmoid(input)

        def bw_hook(module, grad_input, grad_output):
            for grad in grad_input:
                self.assertTrue(isinstance(grad, torch.Tensor))
            for grad in grad_output:
                self.assertTrue(isinstance(grad, torch.Tensor))
            return tuple(gi * 2 for gi in grad_input)

        nn.modules.module.register_module_backward_hook(bw_hook)
        module(input).backward(torch.ones(5, 5))
        expected_grad = sig_x * (1 - sig_x) * 2
        self.assertEqual(input.grad, expected_grad)
//  [python]
def test_module_backward_global_hook_writeable(self):
        module = nn.Sigmoid()
        input = torch.randn(5, 5, requires_grad=True)
        sig_x = torch.nn.functional.sigmoid(input)

        def bw_hook(module, grad_input, grad_output):
            for grad in grad_input:
                self.assertTrue(isinstance(grad, torch.Tensor))
            for grad in grad_output:
                self.assertTrue(isinstance(grad, torch.Tensor))
            return tuple(gi * 2 for gi in grad_input)

        nn.modules.module.register_module_full_backward_hook(bw_hook)
        module(input).backward(torch.ones(5, 5))
        expected_grad = sig_x * (1 - sig_x) * 2
        self.assertEqual(input.grad, expected_grad)
//  [python]
def test_module_global_hook_invalid_outputs(self):
        module = nn.Sigmoid()
        input1 = torch.randn(5, 5, requires_grad=True)

        def bw_fail1(self, grad_input, grad_output):
            return grad_input[:-1]

        def bw_fail2(self, grad_input, grad_output):
            return grad_input + (torch.randn(2, 2),)

        with nn.modules.module.register_module_backward_hook(bw_fail1):
            with self.assertRaisesRegex(RuntimeError, 'got 0, but expected 1'):
                module(input1).sum().backward()

        with nn.modules.module.register_module_backward_hook(bw_fail2):
            with self.assertRaisesRegex(RuntimeError, 'got 2, but expected 1'):
                module(input1).sum().backward()
//  [python]
def test_module_global_hook_invalid_outputs(self):
        module = nn.Sigmoid()
        input1 = torch.randn(5, 5, requires_grad=True)

        def bw_fail1(self, grad_input, grad_output):
            return grad_input[:-1]

        def bw_fail2(self, grad_input, grad_output):
            return grad_input + (torch.randn(2, 2),)

        with nn.modules.module.register_module_full_backward_hook(bw_fail1):
            with self.assertRaisesRegex(RuntimeError, 'got 0, but expected 1'):
                module(input1).sum().backward()

        with nn.modules.module.register_module_full_backward_hook(bw_fail2):
            with self.assertRaisesRegex(RuntimeError, 'got 2, but expected 1'):
                module(input1).sum().backward()
//  [python]
def test_module_backward_global_hook_writeable(self):
        module = nn.Sigmoid()
        input1 = torch.randn(5, 5, requires_grad=True)
        sig_x = torch.sigmoid(input1)

        def bw_hook(module, grad_input, grad_output):
            for grad in grad_input:
                self.assertTrue(isinstance(grad, torch.Tensor))
            for grad in grad_output:
                self.assertTrue(isinstance(grad, torch.Tensor))
            return tuple(gi * 2 for gi in grad_input)

        nn.modules.module.register_module_backward_hook(bw_hook)
        module(input1).backward(torch.ones(5, 5))
        expected_grad = sig_x * (1 - sig_x) * 2
        self.assertEqual(input1.grad, expected_grad)
//  [python]
def test_module_backward_global_hook_writeable(self):
        module = nn.Sigmoid()
        input1 = torch.randn(5, 5, requires_grad=True)
        sig_x = torch.sigmoid(input1)

        def bw_hook(module, grad_input, grad_output):
            for grad in grad_input:
                self.assertTrue(isinstance(grad, torch.Tensor))
            for grad in grad_output:
                self.assertTrue(isinstance(grad, torch.Tensor))
            return tuple(gi * 2 for gi in grad_input)

        module.register_full_backward_hook(bw_hook)
        module(input1).backward(torch.ones(5, 5))
        expected_grad = sig_x * (1 - sig_x) * 2
        self.assertEqual(input1.grad, expected_grad)
//  [python]
def test_lu_solve(self, device, dtype):
        def sub_test(pivot):
            for k, n in zip([2, 3, 5], [3, 5, 7]):
                b, A, LU_data, LU_pivots = self.lu_solve_test_helper((n,), (n, k), pivot, device, dtype)
                x = torch.lu_solve(b, LU_data, LU_pivots)
                self.assertEqual(b, A.mm(x))

        sub_test(True)
        if self.device_type == 'cuda':
            sub_test(False)
//  [python]
def test_lu_solve(self, device, dtype):
        def sub_test(pivot):
            for k, n in zip([2, 3, 5], [3, 5, 7]):
                b, A, LU_data, LU_pivots = self.lu_solve_test_helper((n,), (n, k), pivot, device, dtype)
                x = torch.linalg.lu_solve(b, LU_data, LU_pivots)
                self.assertEqual(b, A.mm(x))

        sub_test(True)
        if self.device_type == 'cuda':
            sub_test(False)
//  [python]
def test_lu_solve_batched_many_batches(self, device, dtype):
        def run_test(A_dims, b_dims):
            b, A, LU_data, LU_pivots = self.lu_solve_test_helper(A_dims, b_dims, True, device, dtype)
            x = torch.lu_solve(b, LU_data, LU_pivots)
            Ax = torch.matmul(A, x)
            self.assertEqual(Ax, b.expand_as(Ax))

        run_test((5, 65536), (65536, 5, 10))
        run_test((5, 262144), (262144, 5, 10))
//  [python]
def test_lu_solve_batched_many_batches(self, device, dtype):
        def run_test(A_dims, b_dims):
            b, A, LU_data, LU_pivots = self.lu_solve_test_helper(A_dims, b_dims, True, device, dtype)
            x = torch.linalg.lu_solve(b, LU_data, LU_pivots)
            Ax = torch.matmul(A, x)
            self.assertEqual(Ax, b.expand_as(Ax))

        run_test((5, 65536), (65536, 5, 10))
        run_test((5, 262144), (262144, 5, 10))
//  [python]
def backward(self, y, log_df_dz):
        with torch.no_grad():
            LU = self.L * self.L_mask + self.U * self.U_mask + torch.diag(
                self.sign_s * torch.exp(self.log_s))

            y_reshape = y.view(y.size(0), y.size(1), -1)
            y_reshape = torch.lu_solve(y_reshape, LU.unsqueeze(0), self.pivots.unsqueeze(0))
            y = y_reshape.view(y.size())
            y = y.contiguous()

        num_pixels = np.prod(y.size()) // (y.size(0) * y.size(1))
        log_df_dz -= torch.sum(self.log_s, dim=0) * num_pixels

        return y, log_df_dz
//  [python]
def backward(self, y, log_df_dz):
        with torch.no_grad():
            LU = self.L * self.L_mask + self.U * self.U_mask + torch.diag(
                self.sign_s * torch.exp(self.log_s))

            y_reshape = y.view(y.size(0), y.size(1), -1)
            y_reshape = torch.linalg.lu_solve(y_reshape, LU.unsqueeze(0), self.pivots.unsqueeze(0))
            y = y_reshape.view(y.size())
            y = y.contiguous()

        num_pixels = np.prod(y.size()) // (y.size(0) * y.size(1))
        log_df_dz -= torch.sum(self.log_s, dim=0) * num_pixels

        return y, log_df_dz
//  [python]
def test_module_global_hooks(self):
        module = nn.Sigmoid

        module_1 = module()
        module_2 = module()
        module_3 = module()

        input = torch.ones(5, 5, requires_grad=True)

        counter = {"forwards": 0, "backwards": 0}

        def fw_hook(inc, h_module, input, output):
            self.assertIsInstance(input, tuple)
            self.assertTrue(isinstance(output, torch.Tensor))
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(input[0], torch.ones(5, 5))
            self.assertEqual(output, torch.empty(5, 5).fill_(1 / (1 + 1 / math.e)))
            counter["forwards"] += inc

        def bw_hook(inc, h_module, grad_input, grad_output):
            self.assertIsInstance(grad_input, tuple)
            self.assertIsInstance(grad_output, tuple)
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(grad_output[0], torch.ones(5, 5) * 2)
            counter["backwards"] += inc

        test_fwd = nn.modules.module.register_module_forward_hook(
            lambda *args: fw_hook(1, *args)
        )

        module_1(input)
        module_2(input)
        module_3(input)
        self.assertEqual(counter["forwards"], 3)
        self.assertEqual(counter["backwards"], 0)

        test_bwd = nn.modules.module.register_module_backward_hook(
            lambda *args: bw_hook(1, *args)
        )

        output_1 = module_1(input)
        output_2 = module_2(input)
        output_3 = module_3(input)
        self.assertEqual(counter["forwards"], 6)
        self.assertEqual(counter["backwards"], 0)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        output_2.backward(torch.ones(5, 5) * 2, retain_graph=False)
        output_3.backward(torch.ones(5, 5) * 2, retain_graph=False)
        self.assertEqual(counter["forwards"], 6)
        self.assertEqual(counter["backwards"], 3)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        self.assertEqual(counter["forwards"], 6)
        self.assertEqual(counter["backwards"], 4)

        test2_fwd = nn.modules.module.register_module_forward_hook(
            lambda *args: fw_hook(2, *args)
        )

        output = module_1(input)
        output = module_2(input)
        output = module_3(input)
        self.assertEqual(counter["forwards"], 15)
        self.assertEqual(counter["backwards"], 4)

        test2_bwd = nn.modules.module.register_module_backward_hook(
            lambda *args: bw_hook(2, *args)
        )

        module_1(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter["forwards"], 18)
        self.assertEqual(counter["backwards"], 7)

        test2_bwd.remove()

        module_2(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter["forwards"], 21)
        self.assertEqual(counter["backwards"], 8)

        test2_fwd.remove()

        module_3(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter["forwards"], 22)
        self.assertEqual(counter["backwards"], 9)

        test_fwd.remove()
        test_bwd.remove()
//  [python]
def test_module_global_hooks(self):
        module = nn.Sigmoid

        module_1 = module()
        module_2 = module()
        module_3 = module()

        input = torch.ones(5, 5, requires_grad=True)

        counter = {"forwards": 0, "backwards": 0}

        def fw_hook(inc, h_module, input, output):
            self.assertIsInstance(input, tuple)
            self.assertTrue(isinstance(output, torch.Tensor))
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(input[0], torch.ones(5, 5))
            self.assertEqual(output, torch.empty(5, 5).fill_(1 / (1 + 1 / math.e)))
            counter["forwards"] += inc

        def bw_hook(inc, h_module, grad_input, grad_output):
            self.assertIsInstance(grad_input, tuple)
            self.assertIsInstance(grad_output, tuple)
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(grad_output[0], torch.ones(5, 5) * 2)
            counter["backwards"] += inc

        test_fwd = nn.modules.module.register_module_forward_hook(
            lambda *args: fw_hook(1, *args)
        )

        module_1(input)
        module_2(input)
        module_3(input)
        self.assertEqual(counter["forwards"], 3)
        self.assertEqual(counter["backwards"], 0)

        test_bwd = nn.modules.module.register_module_full_backward_hook(
            lambda *args: bw_hook(1, *args)
        )

        output_1 = module_1(input)
        output_2 = module_2(input)
        output_3 = module_3(input)
        self.assertEqual(counter["forwards"], 6)
        self.assertEqual(counter["backwards"], 0)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        output_2.backward(torch.ones(5, 5) * 2, retain_graph=False)
        output_3.backward(torch.ones(5, 5) * 2, retain_graph=False)
        self.assertEqual(counter["forwards"], 6)
        self.assertEqual(counter["backwards"], 3)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        self.assertEqual(counter["forwards"], 6)
        self.assertEqual(counter["backwards"], 4)

        test2_fwd = nn.modules.module.register_module_forward_hook(
            lambda *args: fw_hook(2, *args)
        )

        output = module_1(input)
        output = module_2(input)
        output = module_3(input)
        self.assertEqual(counter["forwards"], 15)
        self.assertEqual(counter["backwards"], 4)

        test2_bwd = nn.modules.module.register_module_full_backward_hook(
            lambda *args: bw_hook(2, *args)
        )

        module_1(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter["forwards"], 18)
        self.assertEqual(counter["backwards"], 7)

        test2_bwd.remove()

        module_2(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter["forwards"], 21)
        self.assertEqual(counter["backwards"], 8)

        test2_fwd.remove()

        module_3(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter["forwards"], 22)
        self.assertEqual(counter["backwards"], 9)

        test_fwd.remove()
        test_bwd.remove()
//  [python]
def test_module_global_hooks(self):
        module = nn.Sigmoid

        module_1 = module()
        module_2 = module()
        module_3 = module()

        input = torch.ones(5, 5, requires_grad=True)

        counter = {
            'forwards': 0,
            'backwards': 0
        }

        def fw_hook(inc, h_module, input, output):
            self.assertIsInstance(input, tuple)
            self.assertTrue(isinstance(output, torch.Tensor))
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(input[0], torch.ones(5, 5))
            self.assertEqual(output, torch.empty(5, 5).fill_(1 / (1 + 1 / math.e)))
            counter['forwards'] += inc

        def bw_hook(inc, h_module, grad_input, grad_output):
            self.assertIsInstance(grad_input, tuple)
            self.assertIsInstance(grad_output, tuple)
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(grad_output[0], torch.ones(5, 5) * 2)
            counter['backwards'] += inc

        test_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(1, *args))

        module_1(input)
        module_2(input)
        module_3(input)
        self.assertEqual(counter['forwards'], 3)
        self.assertEqual(counter['backwards'], 0)

        test_bwd = nn.modules.module.register_module_backward_hook(
            lambda *args: bw_hook(1, *args))

        output_1 = module_1(input)
        output_2 = module_2(input)
        output_3 = module_3(input)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 0)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        output_2.backward(torch.ones(5, 5) * 2, retain_graph=False)
        output_3.backward(torch.ones(5, 5) * 2, retain_graph=False)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 3)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 4)

        test2_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(2, *args))

        output = module_1(input)
        output = module_2(input)
        output = module_3(input)
        self.assertEqual(counter['forwards'], 15)
        self.assertEqual(counter['backwards'], 4)

        test2_bwd = nn.modules.module.register_module_backward_hook(lambda *args: bw_hook(2, *args))

        module_1(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 18)
        self.assertEqual(counter['backwards'], 7)

        test2_bwd.remove()

        module_2(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 21)
        self.assertEqual(counter['backwards'], 8)

        test2_fwd.remove()

        module_3(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 22)
        self.assertEqual(counter['backwards'], 9)

        test_fwd.remove()
        test_bwd.remove()
//  [python]
def test_module_global_hooks(self):
        module = nn.Sigmoid

        module_1 = module()
        module_2 = module()
        module_3 = module()

        input = torch.ones(5, 5, requires_grad=True)

        counter = {
            'forwards': 0,
            'backwards': 0
        }

        def fw_hook(inc, h_module, input, output):
            self.assertIsInstance(input, tuple)
            self.assertTrue(isinstance(output, torch.Tensor))
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(input[0], torch.ones(5, 5))
            self.assertEqual(output, torch.empty(5, 5).fill_(1 / (1 + 1 / math.e)))
            counter['forwards'] += inc

        def bw_hook(inc, h_module, grad_input, grad_output):
            self.assertIsInstance(grad_input, tuple)
            self.assertIsInstance(grad_output, tuple)
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(grad_output[0], torch.ones(5, 5) * 2)
            counter['backwards'] += inc

        test_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(1, *args))

        module_1(input)
        module_2(input)
        module_3(input)
        self.assertEqual(counter['forwards'], 3)
        self.assertEqual(counter['backwards'], 0)

        test_bwd = nn.modules.module.register_module_full_backward_hook(
            lambda *args: bw_hook(1, *args))

        output_1 = module_1(input)
        output_2 = module_2(input)
        output_3 = module_3(input)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 0)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        output_2.backward(torch.ones(5, 5) * 2, retain_graph=False)
        output_3.backward(torch.ones(5, 5) * 2, retain_graph=False)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 3)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 4)

        test2_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(2, *args))

        output = module_1(input)
        output = module_2(input)
        output = module_3(input)
        self.assertEqual(counter['forwards'], 15)
        self.assertEqual(counter['backwards'], 4)

        test2_bwd = nn.modules.module.register_module_full_backward_hook(lambda *args: bw_hook(2, *args))

        module_1(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 18)
        self.assertEqual(counter['backwards'], 7)

        test2_bwd.remove()

        module_2(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 21)
        self.assertEqual(counter['backwards'], 8)

        test2_fwd.remove()

        module_3(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 22)
        self.assertEqual(counter['backwards'], 9)

        test_fwd.remove()
        test_bwd.remove()
//  [python]
def test_module_global_hooks(self):
        module = nn.Sigmoid

        module_1 = module()
        module_2 = module()
        module_3 = module()

        input = torch.ones(5, 5, requires_grad=True)

        counter = {
            'forwards': 0,
            'backwards': 0
        }

        def fw_hook(inc, h_module, input, output):
            self.assertIsInstance(input, tuple)
            self.assertTrue(isinstance(output, torch.Tensor))
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(input[0], torch.ones(5, 5))
            self.assertEqual(output, torch.Tensor(5, 5).fill_(1 / (1 + 1 / math.e)))
            counter['forwards'] += inc

        def bw_hook(inc, h_module, grad_input, grad_output):
            self.assertIsInstance(grad_input, tuple)
            self.assertIsInstance(grad_output, tuple)
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(grad_output[0], torch.ones(5, 5) * 2)
            counter['backwards'] += inc

        test_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(1, *args))

        module_1(input)
        module_2(input)
        module_3(input)
        self.assertEqual(counter['forwards'], 3)
        self.assertEqual(counter['backwards'], 0)

        test_bwd = nn.modules.module.register_module_backward_hook(
            lambda *args: bw_hook(1, *args))

        output_1 = module_1(input)
        output_2 = module_2(input)
        output_3 = module_3(input)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 0)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        output_2.backward(torch.ones(5, 5) * 2, retain_graph=False)
        output_3.backward(torch.ones(5, 5) * 2, retain_graph=False)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 3)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 4)

        test2_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(2, *args))

        output = module_1(input)
        output = module_2(input)
        output = module_3(input)
        self.assertEqual(counter['forwards'], 15)
        self.assertEqual(counter['backwards'], 4)

        test2_bwd = nn.modules.module.register_module_backward_hook(lambda *args: bw_hook(2, *args))

        module_1(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 18)
        self.assertEqual(counter['backwards'], 7)

        test2_bwd.remove()

        module_2(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 21)
        self.assertEqual(counter['backwards'], 8)

        test2_fwd.remove()

        module_3(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 22)
        self.assertEqual(counter['backwards'], 9)

        test_fwd.remove()
        test_bwd.remove()
//  [python]
def test_module_global_hooks(self):
        module = nn.Sigmoid

        module_1 = module()
        module_2 = module()
        module_3 = module()

        input = torch.ones(5, 5, requires_grad=True)

        counter = {
            'forwards': 0,
            'backwards': 0
        }

        def fw_hook(inc, h_module, input, output):
            self.assertIsInstance(input, tuple)
            self.assertTrue(isinstance(output, torch.Tensor))
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(input[0], torch.ones(5, 5))
            self.assertEqual(output, torch.Tensor(5, 5).fill_(1 / (1 + 1 / math.e)))
            counter['forwards'] += inc

        def bw_hook(inc, h_module, grad_input, grad_output):
            self.assertIsInstance(grad_input, tuple)
            self.assertIsInstance(grad_output, tuple)
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(grad_output[0], torch.ones(5, 5) * 2)
            counter['backwards'] += inc

        test_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(1, *args))

        module_1(input)
        module_2(input)
        module_3(input)
        self.assertEqual(counter['forwards'], 3)
        self.assertEqual(counter['backwards'], 0)

        test_bwd = nn.modules.module.register_module_full_backward_hook(
            lambda *args: bw_hook(1, *args))

        output_1 = module_1(input)
        output_2 = module_2(input)
        output_3 = module_3(input)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 0)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        output_2.backward(torch.ones(5, 5) * 2, retain_graph=False)
        output_3.backward(torch.ones(5, 5) * 2, retain_graph=False)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 3)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        self.assertEqual(counter['forwards'], 6)
        self.assertEqual(counter['backwards'], 4)

        test2_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(2, *args))

        output = module_1(input)
        output = module_2(input)
        output = module_3(input)
        self.assertEqual(counter['forwards'], 15)
        self.assertEqual(counter['backwards'], 4)

        test2_bwd = nn.modules.module.register_module_full_backward_hook(lambda *args: bw_hook(2, *args))

        module_1(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 18)
        self.assertEqual(counter['backwards'], 7)

        test2_bwd.remove()

        module_2(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 21)
        self.assertEqual(counter['backwards'], 8)

        test2_fwd.remove()

        module_3(input).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter['forwards'], 22)
        self.assertEqual(counter['backwards'], 9)

        test_fwd.remove()
        test_bwd.remove()
//  [python]
def xpbatch_lu_solve(lu_and_piv, b):
    """ solve ax = b

    :param lu_and_piv:
    :param b:
    :return:
    """
    LU, piv = lu_and_piv
    # xp = get_array_module(LU)
    b = b.copy()
    '''
    for i in range(len(LU)):
        if cupy_available and xp == cupy:
            b[i] = cupyx.scipy.linalg.lu_solve((LU[i], piv[i]), b[i], overwrite_b=True)
        else:
            b[i] = scipy.linalg.lu_solve((LU[i], piv[i]), b[i], overwrite_b=True)
    '''
    b = torch.Tensor(b)
    b = b.float()
    LU = torch.from_numpy(LU)
    piv = torch.from_numpy(piv)
    LU = LU.float()
    b = torch.lu_solve(b, LU, piv)
    return b.cpu().numpy()
//  [python]
def xpbatch_lu_solve(lu_and_piv, b):
    """ solve ax = b

    :param lu_and_piv:
    :param b:
    :return:
    """
    LU, piv = lu_and_piv
    # xp = get_array_module(LU)
    b = b.copy()
    '''
    for i in range(len(LU)):
        if cupy_available and xp == cupy:
            b[i] = cupyx.scipy.linalg.lu_solve((LU[i], piv[i]), b[i], overwrite_b=True)
        else:
            b[i] = scipy.linalg.lu_solve((LU[i], piv[i]), b[i], overwrite_b=True)
    '''
    b = torch.Tensor(b)
    b = b.float()
    LU = torch.from_numpy(LU)
    piv = torch.from_numpy(piv)
    LU = LU.float()
    b = torch.linalg.lu_solve(b, LU, piv)
    return b.cpu().numpy()
//  [python]
def test_module_hooks(jit):
    def cook_hook(l, name):
        def fn(*args):
            l.append((name, thunder.core.interpreter.is_jitting_with_raise()))

        return fn

    m = torch.nn.Linear(4, 4)
    l = []
    handles = []

    try:
        handles.append(torch.nn.modules.module.register_module_forward_hook(cook_hook(l, "global forward")))
        handles.append(torch.nn.modules.module.register_module_forward_pre_hook(cook_hook(l, "global forward pre")))
        handles.append(m.register_full_backward_hook(cook_hook(l, "global full backward")))
        handles.append(m.register_full_backward_pre_hook(cook_hook(l, "global full backward pre")))
        handles.append(m.register_forward_hook(cook_hook(l, "module forward")))
        handles.append(m.register_forward_pre_hook(cook_hook(l, "module forward pre")))
        handles.append(m.register_full_backward_hook(cook_hook(l, "module full backward")))
        handles.append(m.register_full_backward_pre_hook(cook_hook(l, "module full backward pre")))

        x = torch.randn(3, 4)

        jm = jit(m, record_history=True)
        y = jm(x)
        y.sum().backward()

        # Find the hook registration in the log the normal way
        found = False
        for item in last_interpreter_log(jm):
            if (not isinstance(item, dict)) or (item["kind"] != "Opaque"):
                continue
            _fn = item["fn"]
            if _fn == torch._C._FunctionBase.register_hook.__qualname__:  # type: ignore
                found = True
                break

        assert found

        # Redirect print_last_interpreter_log from stdout to a string, and assert that it's in there.
        buf = io.StringIO()
        with redirect_stdout(buf):
            print_interpreter_log(last_interpreter_log(jm), use_colors=False, indent=False)

        match_against = "Opaque call to _FunctionBase.register_hook()"
        assert match_against in buf.getvalue()
        buf.close()

        jit_l = l[:]
        l.clear()
        y = m(x)
        y.sum().backward()

        assert len(jit_l) == len(l)
        for (jn, jj), (pn, pj) in zip(jit_l, l):
            assert jn == pn
            # we expect forward to be execute via the jit, backward
            # assert bool(jj), f"{jn} {jj=}"
    finally:
        for h in handles:
            h.remove()
//  [python]
def test_module_hooks(jit):
    def cook_hook(l, name):
        def fn(*args):
            l.append((name, thunder.core.interpreter.is_jitting_with_raise()))

        return fn

    m = torch.nn.Linear(4, 4)
    l = []
    handles = []

    try:
        handles.append(torch.nn.modules.module.register_module_forward_hook(cook_hook(l, "global forward")))
        handles.append(torch.nn.modules.module.register_module_forward_pre_hook(cook_hook(l, "global forward pre")))
        handles.append(torch.nn.modules.module.register_module_full_backward_hook(cook_hook(l, "global full backward")))
        handles.append(
            torch.nn.modules.module.register_module_full_backward_pre_hook(cook_hook(l, "global full backward pre"))
        )
        handles.append(m.register_forward_hook(cook_hook(l, "module forward")))
        handles.append(m.register_forward_pre_hook(cook_hook(l, "module forward pre")))
        handles.append(m.register_full_backward_hook(cook_hook(l, "module full backward")))
        handles.append(m.register_full_backward_pre_hook(cook_hook(l, "module full backward pre")))

        x = torch.randn(3, 4)

        jm = jit(m, record_history=True)
        y = jm(x)
        y.sum().backward()

        # Find the hook registration in the log the normal way
        found = False
        for item in last_interpreter_log(jm):
            if (not isinstance(item, dict)) or (item["kind"] != "Opaque"):
                continue
            _fn = item["fn"]
            if _fn == torch._C._FunctionBase.register_hook.__qualname__:  # type: ignore
                found = True
                break

        assert found

        # Redirect print_last_interpreter_log from stdout to a string, and assert that it's in there.
        buf = io.StringIO()
        with redirect_stdout(buf):
            print_interpreter_log(last_interpreter_log(jm), use_colors=False, indent=False)

        match_against = "Opaque call to _FunctionBase.register_hook()"
        assert match_against in buf.getvalue()
        buf.close()

        jit_l = l[:]
        l.clear()
        y = m(x)
        y.sum().backward()

        assert len(jit_l) == len(l)
        for (jn, jj), (pn, pj) in zip(jit_l, l):
            assert jn == pn
            # we expect forward to be execute via the jit, backward
            # assert bool(jj), f"{jn} {jj=}"
    finally:
        for h in handles:
            h.remove()
//  [python]
def test_lu_solve(self, device, dtype):
        def sub_test(pivot):
            for k, n in zip([2, 3, 5], [3, 5, 7]):
                b, A, LU_data, LU_pivots = self.lu_solve_test_helper((n, n), (n, k), pivot, device, dtype)
                x = torch.lu_solve(b, LU_data, LU_pivots)
                self.assertEqual(b, np.matmul(A.cpu(), x.cpu()))

        sub_test(True)
        if self.device_type == 'cuda':
            sub_test(False)
//  [python]
def test_lu_solve(self, device, dtype):
        def sub_test(pivot):
            for k, n in zip([2, 3, 5], [3, 5, 7]):
                b, A, LU_data, LU_pivots = self.lu_solve_test_helper((n, n), (n, k), pivot, device, dtype)
                x = torch.linalg.lu_solve(b, LU_data, LU_pivots)
                self.assertEqual(b, np.matmul(A.cpu(), x.cpu()))

        sub_test(True)
        if self.device_type == 'cuda':
            sub_test(False)
//  [python]
def test_module_global_hooks(self):
        module = nn.Sigmoid

        module_1 = module()
        module_2 = module()
        module_3 = module()

        input1 = torch.ones(5, 5, requires_grad=True)

        counter = {
            'forwards': 0,
            'backwards': 0
        }

        def fw_hook(inc, h_module, input1, output):
            self.assertIsInstance(input1, tuple)
            self.assertTrue(isinstance(output, torch.Tensor))
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(input1[0], torch.ones(5, 5))
            self.assertEqual(output, torch.empty(5, 5).fill_(1 / (1 + 1 / math.e)))
            counter['forwards'] += inc

        def bw_hook(inc, h_module, grad_input, grad_output):
            self.assertIsInstance(grad_input, tuple)
            self.assertIsInstance(grad_output, tuple)
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(grad_output[0], torch.ones(5, 5) * 2)
            counter['backwards'] += inc

        test_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(1, *args))

        module_1(input1)
        module_2(input1)
        module_3(input1)
        self.assertEqual(counter.get('forwards'), 3)
        self.assertEqual(counter.get('backwards'), 0)

        test_bwd = nn.modules.module.register_module_backward_hook(
            lambda *args: bw_hook(1, *args))

        output_1 = module_1(input1)
        output_2 = module_2(input1)
        output_3 = module_3(input1)
        self.assertEqual(counter.get('forwards'), 6)
        self.assertEqual(counter.get('backwards'), 0)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        output_2.backward(torch.ones(5, 5) * 2, retain_graph=False)
        output_3.backward(torch.ones(5, 5) * 2, retain_graph=False)
        self.assertEqual(counter.get('forwards'), 6)
        self.assertEqual(counter.get('backwards'), 3)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        self.assertEqual(counter.get('forwards'), 6)
        self.assertEqual(counter.get('backwards'), 4)

        test2_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(2, *args))

        output = module_1(input1)
        output = module_2(input1)
        output = module_3(input1)
        self.assertEqual(counter.get('forwards'), 15)
        self.assertEqual(counter.get('backwards'), 4)

        test2_bwd = nn.modules.module.register_module_backward_hook(lambda *args: bw_hook(2, *args))

        module_1(input1).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter.get('forwards'), 18)
        self.assertEqual(counter.get('backwards'), 7)

        test2_bwd.remove()

        module_2(input1).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter.get('forwards'), 21)
        self.assertEqual(counter.get('backwards'), 8)

        test2_fwd.remove()

        module_3(input1).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter.get('forwards'), 22)
        self.assertEqual(counter.get('backwards'), 9)

        test_fwd.remove()
        test_bwd.remove()
//  [python]
def test_module_global_hooks(self):
        module = nn.Sigmoid

        module_1 = module()
        module_2 = module()
        module_3 = module()

        input1 = torch.ones(5, 5, requires_grad=True)

        counter = {
            'forwards': 0,
            'backwards': 0
        }

        def fw_hook(inc, h_module, input1, output):
            self.assertIsInstance(input1, tuple)
            self.assertTrue(isinstance(output, torch.Tensor))
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(input1[0], torch.ones(5, 5))
            self.assertEqual(output, torch.empty(5, 5).fill_(1 / (1 + 1 / math.e)))
            counter['forwards'] += inc

        def bw_hook(inc, h_module, grad_input, grad_output):
            self.assertIsInstance(grad_input, tuple)
            self.assertIsInstance(grad_output, tuple)
            self.assertTrue(isinstance(h_module, module))
            self.assertEqual(grad_output[0], torch.ones(5, 5) * 2)
            counter['backwards'] += inc

        test_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(1, *args))

        module_1(input1)
        module_2(input1)
        module_3(input1)
        self.assertEqual(counter.get('forwards'), 3)
        self.assertEqual(counter.get('backwards'), 0)

        test_bwd = nn.modules.module.register_module_full_backward_hook(
            lambda *args: bw_hook(1, *args))

        output_1 = module_1(input1)
        output_2 = module_2(input1)
        output_3 = module_3(input1)
        self.assertEqual(counter.get('forwards'), 6)
        self.assertEqual(counter.get('backwards'), 0)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        output_2.backward(torch.ones(5, 5) * 2, retain_graph=False)
        output_3.backward(torch.ones(5, 5) * 2, retain_graph=False)
        self.assertEqual(counter.get('forwards'), 6)
        self.assertEqual(counter.get('backwards'), 3)

        output_1.backward(torch.ones(5, 5) * 2, retain_graph=True)
        self.assertEqual(counter.get('forwards'), 6)
        self.assertEqual(counter.get('backwards'), 4)

        test2_fwd = nn.modules.module.register_module_forward_hook(lambda *args: fw_hook(2, *args))

        output = module_1(input1)
        output = module_2(input1)
        output = module_3(input1)
        self.assertEqual(counter.get('forwards'), 15)
        self.assertEqual(counter.get('backwards'), 4)

        test2_bwd = nn.modules.module.register_module_full_backward_hook(lambda *args: bw_hook(2, *args))

        module_1(input1).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter.get('forwards'), 18)
        self.assertEqual(counter.get('backwards'), 7)

        test2_bwd.remove()

        module_2(input1).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter.get('forwards'), 21)
        self.assertEqual(counter.get('backwards'), 8)

        test2_fwd.remove()

        module_3(input1).backward(torch.ones(5, 5) * 2)
        self.assertEqual(counter.get('forwards'), 22)
        self.assertEqual(counter.get('backwards'), 9)

        test_fwd.remove()
        test_bwd.remove()
//  [python]
def test_lu_solve_large_matrices(self, device, dtype):
        def run_test(A_dims, b_dims):
            b, A, LU_data, LU_pivots = self.lu_solve_test_helper(A_dims, b_dims, True, device, dtype)
            x = torch.lu_solve(b, LU_data, LU_pivots)
            Ax = torch.matmul(A, x)
            self.assertEqual(Ax, b.expand_as(Ax))

        run_test((1, 1), (1, 1, 1025))
//  [python]
def test_lu_solve_large_matrices(self, device, dtype):
        def run_test(A_dims, b_dims):
            b, A, LU_data, LU_pivots = self.lu_solve_test_helper(A_dims, b_dims, True, device, dtype)
            x = torch.linalg.lu_solve(b, LU_data, LU_pivots)
            Ax = torch.matmul(A, x)
            self.assertEqual(Ax, b.expand_as(Ax))

        run_test((1, 1), (1, 1, 1025))
//  [python]
def backward(ctx, grad_x):
        A_LU, pivots, x = ctx.saved_tensors

        # Math:
        # A * grad_b = grad_x
        # grad_A = -grad_b * x^T

        grad_b = torch.lu_solve(grad_x, A_LU, pivots)
        grad_A = -torch.matmul(grad_b, x.view(1, -1))
        
        return grad_A, grad_b
//  [python]
def backward(ctx, grad_x):
        A_LU, pivots, x = ctx.saved_tensors

        # Math:
        # A * grad_b = grad_x
        # grad_A = -grad_b * x^T

        grad_b = torch.linalg.lu_solve(grad_x, A_LU, pivots)
        grad_A = -torch.matmul(grad_b, x.view(1, -1))
        
        return grad_A, grad_b
//  [python]
def backward(ctx, grad_x):
        A_LU, pivots, x = ctx.saved_tensors
        grad_b = torch.lu_solve(grad_x, A_LU, pivots)
        grad_A = -torch.matmul(grad_b, x.view(1, -1))
        return grad_A, grad_b
//  [python]
def backward(ctx, grad_x):
        A_LU, pivots, x = ctx.saved_tensors
        grad_b = torch.linalg.lu_solve(grad_x, A_LU, pivots)
        grad_A = -torch.matmul(grad_b, x.view(1, -1))
        return grad_A, grad_b
//  [python]
def backward(ctx, dldd: torch.Tensor):
        l, u, d = ctx.saved_tensors
        dldp = torch.lu_solve(dldd, l, u)
        dldq = -dldp.matmul(d.transpose(-2, -1))

        return dldq, dldp
//  [python]
def backward(ctx, dldd: torch.Tensor):
        l, u, d = ctx.saved_tensors
        dldp = torch.linalg.lu_solve(dldd, (l, u))
        dldq = -dldp.matmul(d.transpose(-2, -1))

        return dldq, dldp
//  [python]
def backward(ctx, grad):
        A_lu,pivots,x=ctx.saved_tensors
        grad_b=torch.lu_solve(grad,A_lu,pivots)
        # if (torch.isnan(grad_b)).any().item() or (torch.isinf(grad_b)).any().item():
        #     print('backward is nan')
        #     grad_b=torch.zeros(grad.shape,device=grad.device)
        grad_A=-grad_b.view(-1,1).matmul(x.view(1,-1))
        return grad_A, grad_b.view(-1)
//  [python]
def backward(ctx, grad):
        A_lu,pivots,x=ctx.saved_tensors
        grad_b=torch.linalg.lu_solve(grad,A_lu,pivots)
        # if (torch.isnan(grad_b)).any().item() or (torch.isinf(grad_b)).any().item():
        #     print('backward is nan')
        #     grad_b=torch.zeros(grad.shape,device=grad.device)
        grad_A=-grad_b.view(-1,1).matmul(x.view(1,-1))
        return grad_A, grad_b.view(-1)
//  [python]
def lu_solve(
    lu: Tuple[torch.Tensor, torch.Tensor],
    p: torch.Tensor,
    b: torch.Tensor,
    /,
    *,
    out: Optional[torch.Tensor] = None,
) -> torch.Tensor:
    return torch.solve(b, torch.lu_unpack(*lu, unpack_pivots=True)[0])
//  [python]
def lu_solve(
    lu: Tuple[torch.Tensor, torch.Tensor],
    p: torch.Tensor,
    b: torch.Tensor,
    /,
    *,
    out: Optional[torch.Tensor] = None,
) -> torch.Tensor:
    return torch.linalg.lu_solve(lu, p, b, out=out)
//  [python]
def backward(ctx, grad):
        Graph_extend_batch=ctx.saved_tensors[-1]
        batch_num=Graph_extend_batch[-1].item()+1
        grad_A=torch.zeros(grad.shape[0],grad.shape[0],dtype=grad.dtype,device=grad.device)
        grad_b=torch.zeros(grad.shape[0],dtype=grad.dtype,device=grad.device)
        for bid in range(batch_num):
            Ab_lu=ctx.saved_tensors[2*bid:2*bid+2]
            xb=ctx.saved_tensors[2*batch_num+bid]
            mask=Graph_extend_batch==bid
            Mask=mask[:,None]&mask[None,:]
            grad_bb=torch.lu_solve(grad[mask],*Ab_lu)
            grad_Ab=-grad_bb.matmul(xb.view(1,-1))
            grad_A[Mask]=grad_Ab.view(-1)
            grad_b[mask]=grad_bb.view(-1)
        return grad_A, grad_b, None
//  [python]
def backward(ctx, grad):
        Graph_extend_batch=ctx.saved_tensors[-1]
        batch_num=Graph_extend_batch[-1].item()+1
        grad_A=torch.zeros(grad.shape[0],grad.shape[0],dtype=grad.dtype,device=grad.device)
        grad_b=torch.zeros(grad.shape[0],dtype=grad.dtype,device=grad.device)
        for bid in range(batch_num):
            Ab_lu=ctx.saved_tensors[2*bid:2*bid+2]
            xb=ctx.saved_tensors[2*batch_num+bid]
            mask=Graph_extend_batch==bid
            Mask=mask[:,None]&mask[None,:]
            grad_bb=torch.linalg.lu_solve(grad[mask],*Ab_lu)
            grad_Ab=-grad_bb.matmul(xb.view(1,-1))
            grad_A[Mask]=grad_Ab.view(-1)
            grad_b[mask]=grad_bb.view(-1)
        return grad_A, grad_b, None
//  [python]
def dot(self, x):
        """
        Batched matrix-vector product

        This object does the backsolves to calculate (LU)^-1 * x

        Args:
            x (torch.tensor):       input to linear operator

        Returns:
            y (torch.tensor):       result of the linear operator
        """
        return torch.solve(x.unsqueeze(-1), self.LU).solution.squeeze(-1)
//  [python]
def dot(self, x):
        """
        Batched matrix-vector product

        This object does the backsolves to calculate (LU)^-1 * x

        Args:
            x (torch.tensor):       input to linear operator

        Returns:
            y (torch.tensor):       result of the linear operator
        """
        return torch.linalg.lu_solve(self.LU, self.pivots, x.unsqueeze(-1)).squeeze(-1)
//  [python]
def apply(self, pc, x, y):
        X = dlpack.from_dlpack(x.toDLPack(mode="r")).reshape(self._m, self._n)
        Y = dlpack.from_dlpack(y).reshape(self._m, self._n)
        LU, pivots = self.get_factor()
        torch.solve(X, LU, out=Y)