<commit_before>from ..PermSetDescribed import PermSetDescribed
from permuta import Perm
from permuta.descriptors import Basis
from permuta._perm_set.finite import PermSetFiniteSpecificLength
#from permuta._perm_set.finite import PermSetStatic


# PermSet.avoiding([(0, 2, 1), (1, 2, 3, 4, 0)])


class Avoiding(PermSetDescribed):
    descriptor = Basis
    __CLASS_CACHE = {}  # Empty basis is dispatched to correct class (AvoidingEmpty)

    def __new__(cls, basis):
        if basis in Avoiding.__CLASS_CACHE:
            return Avoiding.__CLASS_CACHE[basis]
        else:
            instance = super(Avoiding, cls).__new__(cls)
            instance.cache = [set([Perm()])]  # Generic case includes empty permutation
            instance.basis = basis
            Avoiding.__CLASS_CACHE[basis] = instance
            return instance


    def assure_length(self, length):
        while len(self.cache) <= length:
            next_level = set()
            total_indices = len(self.cache)  # really: len(perm) + 1
            #new_element = indices - 1  # TODO Performance without insert method
            for perm in self.cache[-1]:
                for index in range(total_indices):
                    new_perm = perm.insert(index)
                    if new_perm.avoids(*self.basis.perms):
                        next_level.add(new_perm)
            self.cache.append(next_level)

    def up_to(self, perm):
        # Should return a PermSetAllRange
        raise NotImplementedError

    def of_length(self, length):
        # TODO: Cache of instances
        return AvoidingSpecificLength(length, self)

    def range(self, stop):
        raise NotImplementedError

    def __getitem__(self, key):
        level = 0
        while True:
            self.assure_length(level)
            level_size = len(self.cache[level])
            if level_size <= key:
                key -= level_size
            else:  # TODO: So dumb
                return list(self.cache[level])[key]
            level += 1

    def __next__(self):
        if self._iter is None:
            self._iter = iter(self.of_length(self._iter_number))
        try:
            return next(self._iter)
        except StopIteration:
            self._iter = None
            self._iter_number += 1
            return self.__next__()

    def __iter__(self):
        self._iter = None
        self._iter_number = 0
        return self

    def __contains__(self, perm): # TODO: Raggi, are we happy with this?
        level = len(perm)
        self.assure_length(level)
        return perm in self.cache[level]
        # naive implementation
        # return perm.avoids(*self.basis.perms)


    def __repr__(self):
        return "<The set of all perms avoiding {}>".format(repr(self.basis))


class AvoidingSpecificLength(PermSetFiniteSpecificLength):
    """Class for iterating through all perms of a specific length avoiding a basis."""

    __slots__ = ("_length")

    def __init__(self, length, supervisor):
        self._length = length
        self._supervisor = supervisor
        self._basis = supervisor.basis
        self._iter = None

    @property
    def length(self):
        return self._length

    @property
    def basis(self):
        return self._basis

    @property
    def supervisor(self):
        return self._supervisor

    def random(self):
        raise NotImplementedError<commit_msg>Small fix to contains<commit_after>from ..PermSetDescribed import PermSetDescribed
from permuta import Perm
from permuta.descriptors import Basis
from permuta._perm_set.finite import PermSetFiniteSpecificLength
#from permuta._perm_set.finite import PermSetStatic


# PermSet.avoiding([(0, 2, 1), (1, 2, 3, 4, 0)])


class Avoiding(PermSetDescribed):
    descriptor = Basis
    __CLASS_CACHE = {}  # Empty basis is dispatched to correct class (AvoidingEmpty)

    def __new__(cls, basis):
        if basis in Avoiding.__CLASS_CACHE:
            return Avoiding.__CLASS_CACHE[basis]
        else:
            instance = super(Avoiding, cls).__new__(cls)
            instance.cache = [set([Perm()])]  # Generic case includes empty permutation
            instance.basis = basis
            Avoiding.__CLASS_CACHE[basis] = instance
            return instance


    def assure_length(self, length):
        while len(self.cache) <= length:
            next_level = set()
            total_indices = len(self.cache)  # really: len(perm) + 1
            #new_element = indices - 1  # TODO Performance without insert method
            for perm in self.cache[-1]:
                for index in range(total_indices):
                    new_perm = perm.insert(index)
                    if new_perm.avoids(*self.basis.perms):
                        next_level.add(new_perm)
            self.cache.append(next_level)

    def up_to(self, perm):
        # Should return a PermSetAllRange
        raise NotImplementedError

    def of_length(self, length):
        # TODO: Cache of instances
        return AvoidingSpecificLength(length, self)

    def range(self, stop):
        raise NotImplementedError

    def __getitem__(self, key):
        level = 0
        while True:
            self.assure_length(level)
            level_size = len(self.cache[level])
            if level_size <= key:
                key -= level_size
            else:  # TODO: So dumb
                return list(self.cache[level])[key]
            level += 1

    def __next__(self):
        if self._iter is None:
            self._iter = iter(self.of_length(self._iter_number))
        try:
            return next(self._iter)
        except StopIteration:
            self._iter = None
            self._iter_number += 1
            return self.__next__()

    def __iter__(self):
        self._iter = None
        self._iter_number = 0
        return self

    def __contains__(self, perm):
        # TODO: Think about heuristics for switching to avoiding the patterns in the basis instead
        level = len(perm)
        self.assure_length(level)
        return perm in self.cache[level]

    def __repr__(self):
        return "<The set of all perms avoiding {}>".format(repr(self.basis))


class AvoidingSpecificLength(PermSetFiniteSpecificLength):
    """Class for iterating through all perms of a specific length avoiding a basis."""

    __slots__ = ("_length")

    def __init__(self, length, supervisor):
        self._length = length
        self._supervisor = supervisor
        self._basis = supervisor.basis
        self._iter = None

    @property
    def length(self):
        return self._length

    @property
    def basis(self):
        return self._basis

    @property
    def supervisor(self):
        return self._supervisor

    def random(self):
        raise NotImplementedError
{'fraction_non_alphanumeric': 0.08535144713526285, 'fraction_numerical': 0.004430005906674543, 'mean_word_length': 2.1693963500233973, 'pattern_counts': {'":': 0, '<': 9, '<?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': '2889395', 'n_tokens_mistral': 1946, 'n_tokens_neox': 1822, 'n_words': 515}