//  [python]
def prune(self, mode, sparsity=None, n=None, m=None, blocksize=128, percdamp=0.01):
        # pylint: disable=not-callable
        W = self.get_W()
        H = self.H
        del self.H

        # set zero on the diagonal to 1
        dead = torch.diag(H) == 0
        H[dead, dead] = 1
        # set corresponding column of W to 0 to ignore it
        W[:, dead] = 0

        # dampen the Hessian
        assert 0 <= percdamp <= 1
        damp = percdamp * torch.mean(torch.diag(H))
        diag = torch.arange(self.columns, device=self.device)
        H[diag, diag] += damp
        # use Cholesky decomposition to get the inverse
        H = torch.cholesky(H)
        H = torch.cholesky_inverse(H)
        H = torch.cholesky(H, upper=True)
        Hinv = H

        # placeholder for losses per row
        Losses = torch.zeros(self.rows, device=self.device)

        # loop over blocks of columns
        for start in range(0, self.columns, blocksize):
            end = min(start + blocksize, self.columns)
            num_cols = end - start

            # get submatrices
            W1 = W[:, start:end].clone()  # weights for the block
            Q1 = torch.zeros_like(W1)  # matrix to store new weights, updated column by column
            Err1 = torch.zeros_like(W1)  # block error
            Losses1 = torch.zeros_like(W1)  # losses
            Hinv1 = Hinv[start:end, start:end]  # Hessian inverse

            if mode == "unstructured":
                # chose the bottom sparsity% weights to prune (True)
                # lower magnitude = higher importance
                magnitude = W1**2 / (torch.diag(Hinv1).reshape((1, -1))) ** 2
                threshold = torch.sort(magnitude.flatten())[0][int(magnitude.numel() * sparsity)]
                mask1 = magnitude <= threshold
            else:
                # placeholder for mask
                mask1 = torch.zeros_like(W1) == 1

            # loop over columns in the block
            for col in range(num_cols):
                w = W1[:, col]
                hinv = Hinv1[col, col]

                if mode == "structured" and col % m == 0:
                    # every mth column, set bottom n weights to True (prune)
                    magnitude = (
                        W1[:, col : (col + m)] ** 2  # noqa: E203, RUF100
                        / (torch.diag(Hinv1)[col : (col + m)].reshape((1, -1))) ** 2  # noqa: E203, RUF100
                    )
                    mask1.scatter_(1, col + torch.topk(magnitude, n, dim=1, largest=False)[1], True)

                # freeze weights in current column
                q = w.clone()
                q[mask1[:, col]] = 0
                Q1[:, col] = q

                # save losses
                Losses1[:, col] = (w - q) ** 2 / hinv**2

                # pruning error
                err1 = (w - q) / hinv
                # update weights for remaining columns in block
                W1[:, col:] -= err1.unsqueeze(1).matmul(Hinv1[col, col:].unsqueeze(0))
                # save error for lazy update
                Err1[:, col] = err1

            # copy new weights for current block
            W[:, start:end] = Q1
            Losses += torch.sum(Losses1, 1) / 2

            # lazy update rest of the weights
            W[:, end:] -= Err1.matmul(Hinv[start:end, end:])

        if "cuda" in str(self.device):
            torch.cuda.synchronize()

        # set new weights
        if isinstance(self.layer, transformers.Conv1D):
            W = W.t()
        self.layer.weight.data = W.reshape(self.layer.weight.shape).to(self.layer.weight.data.dtype)

        return torch.sum(Losses).item()