<commit_before>import torch
from typing import List
from typing import Union

import syft as sy
from syft.frameworks.torch.tensors.interpreters.abstract import AbstractTensor
from syft.frameworks.torch.tensors.interpreters import AdditiveSharingTensor
from syft.workers import BaseWorker
from syft.frameworks.torch.overload_torch import overloaded

from syft.workers import AbstractWorker


class MultiPointerTensor(AbstractTensor):
    ""

    def __init__(
        self,
        location: BaseWorker = None,
        id_at_location: Union[str, int] = None,
        register: bool = False,
        owner: BaseWorker = None,
        id: Union[str, int] = None,
        garbage_collect_data: bool = True,
        point_to_attr: str = None,
        tags: List[str] = None,
        description: str = None,
        children: List[AbstractTensor] = [],
    ):

        super().__init__(tags, description)

        self.location = location
        self.id_at_location = id_at_location
        self.owner = owner
        self.id = id
        self.garbage_collect_data = garbage_collect_data
        self.point_to_attr = point_to_attr

        self.child = {}
        for c in children:
            assert c.shape == children[0].shape
            self.child[c.location.id] = c

    def __str__(self):
        type_name = type(self).__name__
        out = f"[" f"{type_name}]"
        for v in self.child.values():
            out += "\n\t-> " + str(v)
        return out

    def __eq__(self, other):
        return torch.eq(self, other)

    def __add__(self, other):
        """
        Adding a MultiPointer (MPT) and an AdditiveShared Tensor (AST) should return an
        AdditiveShared Tensor, so if we have this configuration, we permute self and
        other to use the fact that other.__add__(...) return an object of type other

        Else, we just redirect to .add which works well
        """
        if isinstance(other, AdditiveSharingTensor):
            return other.__add__(self)<commit_msg>Fix .grad for multipointertensor<commit_after>import torch
from typing import List
from typing import Union

import syft as sy
from syft.frameworks.torch.tensors.interpreters.abstract import AbstractTensor
from syft.frameworks.torch.tensors.interpreters import AdditiveSharingTensor
from syft.workers import BaseWorker
from syft.frameworks.torch.overload_torch import overloaded

from syft.workers import AbstractWorker


class MultiPointerTensor(AbstractTensor):
    ""

    def __init__(
        self,
        location: BaseWorker = None,
        id_at_location: Union[str, int] = None,
        register: bool = False,
        owner: BaseWorker = None,
        id: Union[str, int] = None,
        garbage_collect_data: bool = True,
        point_to_attr: str = None,
        tags: List[str] = None,
        description: str = None,
        children: List[AbstractTensor] = [],
    ):

        super().__init__(tags, description)

        self.location = location
        self.id_at_location = id_at_location
        self.owner = owner
        self.id = id
        self.garbage_collect_data = garbage_collect_data
        self.point_to_attr = point_to_attr

        self.child = {}
        for c in children:
            assert c.shape == children[0].shape
            self.child[c.location.id] = c

    def __str__(self):
        type_name = type(self).__name__
        out = f"[" f"{type_name}]"
        for v in self.child.values():
            out += "\n\t-> " + str(v)
        return out

    @property
    @overloaded.method
    def grad(self, self_):
        results = {}
        all_none = True
        for worker, pointer in self_.items():
            pointer_grad = pointer.grad

            if pointer_grad is None:
                results[worker] = None
            else:
                results[worker] = pointer_grad
                all_none = False

        return results if not all_none else None

    def __eq__(self, other):
        return torch.eq(self, other)

    def __add__(self, other):
        """
        Adding a MultiPointer (MPT) and an AdditiveShared Tensor (AST) should return an
        AdditiveShared Tensor, so if we have this configuration, we permute self and
        other to use the fact that other.__add__(...) return an object of type other

        Else, we just redirect to .add which works well
        """
        if isinstance(other, AdditiveSharingTensor):
            return other.__add__(self)
{'fraction_non_alphanumeric': 0.08457040035987404, 'fraction_numerical': 0.000449842555105713, 'mean_word_length': 2.3261032161555724, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6645354', 'n_tokens_mistral': 1254, 'n_tokens_neox': 1234, 'n_words': 375}