# Path: permuta/enumeration_strategies/abstract_strategy.py
# class EnumerationStrategy(ABC):
#     """Abstract class for a strategy to enumerate a permutation classes."""
# 
#     def __init__(self, basis: Iterable[Perm]) -> None:
#         self._basis = frozenset(basis)
# 
#     @property
#     def basis(self) -> FrozenSet[Perm]:
#         """Getter for basis."""
#         return self._basis
# 
#     @classmethod
#     def reference(cls) -> str:
#         """A reference for the strategy."""
#         raise NotImplementedError
# 
#     @abstractmethod
#     def applies(self) -> bool:
#         """Return True if the strategy can be used for the basis."""
# 
# Path: permuta/permutils/insertion_encodable.py
# class InsertionEncodablePerms:
#     """A static container of functions fortesting
#     if a basis has a regular insertion encoding.
#     """
# 
#     _ALL_PROPERTIES: ClassVar[int] = 15
#     _CACHE: ClassVar[Dict[Tuple, int]] = {}
# 
#     @staticmethod
#     def _is_incr_next_incr(perm: Perm) -> bool:
#         n = len(perm)
#         return not any(
#             curr < prev and any(perm[j + 1] < perm[j] for j in range(i + 1, n - 1))
#             for i, (prev, curr) in enumerate(zip(perm, islice(perm, 1, None)))
#         )
# 
#     @staticmethod
#     def _is_incr_next_decr(perm: Perm) -> bool:
#         n = len(perm)
#         return not any(
#             curr < prev and any(perm[j + 1] > perm[j] for j in range(i + 1, n - 1))
#             for i, (prev, curr) in enumerate(zip(perm, islice(perm, 1, None)))
#         )
# 
#     @staticmethod
#     def _is_decr_next_incr(perm: Perm) -> bool:
#         n = len(perm)
#         return not any(
#             curr > prev and any(perm[j + 1] < perm[j] for j in range(i + 1, n - 1))
#             for i, (prev, curr) in enumerate(zip(perm, islice(perm, 1, None)))
#         )
# 
#     @staticmethod
#     def _is_decr_next_decr(perm: Perm) -> bool:
#         n = len(perm)
#         return not any(
#             curr > prev and any(perm[j + 1] > perm[j] for j in range(i + 1, n - 1))
#             for i, (prev, curr) in enumerate(zip(perm, islice(perm, 1, None)))
#         )
# 
#     @staticmethod
#     def _insertion_encodable_properties(perm: Perm) -> int:
#         properties = InsertionEncodablePerms._CACHE.get(perm, -1)
#         if properties < 0:
#             properties = sum(
#                 val << shift
#                 for shift, val in enumerate(
#                     (
#                         InsertionEncodablePerms._is_incr_next_decr(perm),
#                         InsertionEncodablePerms._is_incr_next_incr(perm),
#                         InsertionEncodablePerms._is_decr_next_decr(perm),
#                         InsertionEncodablePerms._is_decr_next_incr(perm),
#                     )
#                 )
#             )
#             InsertionEncodablePerms._CACHE[perm] = properties
#         return properties
# 
#     @staticmethod
#     def is_insertion_encodable_rightmost(basis: Iterable[Perm]) -> bool:
#         """Check if basis is insertion encodable by rightmost."""
#         curr = 0
#         for perm in basis:
#             curr = curr | InsertionEncodablePerms._insertion_encodable_properties(perm)
#             if curr == InsertionEncodablePerms._ALL_PROPERTIES:
#                 return True
#         return False
# 
#     @staticmethod
#     def is_insertion_encodable_maximum(basis: Iterable[Perm]) -> bool:
#         """Check if basis is insertion encodable by maximum."""
#         curr = 0
#         for perm in basis:
#             curr = curr | InsertionEncodablePerms._insertion_encodable_properties(
#                 perm.rotate()
#             )
#             if curr == InsertionEncodablePerms._ALL_PROPERTIES:
#                 return True
#         return False
# 
#     @staticmethod
#     def is_insertion_encodable(basis: Iterable[Perm]) -> bool:
#         """Check if basis is insertion encodable."""
#         return InsertionEncodablePerms.is_insertion_encodable_rightmost(
#             basis
#         ) or InsertionEncodablePerms.is_insertion_encodable_maximum(basis)
# 
# Path: permuta/permutils/symmetry.py
# def rotate_90_clockwise_set(perms: Iterable[Perm]) -> Iterator[Perm]:
#     """Rotate all perms by 90 degrees."""
#     return (perm.rotate() for perm in perms)


from permuta.enumeration_strategies.abstract_strategy import EnumerationStrategy
from permuta.permutils.insertion_encodable import InsertionEncodablePerms
from permuta.permutils.symmetry import rotate_90_clockwise_set


class InsertionEncodingStrategy(EnumerationStrategy):
    """Enumeration strategies related to the insertion encoding."""

    def applies(self) -> bool:
        return InsertionEncodablePerms.is_insertion_encodable(
            self.basis

# Path: permuta/enumeration_strategies/abstract_strategy.py
# class EnumerationStrategy(ABC):
#     """Abstract class for a strategy to enumerate a permutation classes."""
# 
#     def __init__(self, basis: Iterable[Perm]) -> None:
#         self._basis = frozenset(basis)
# 
#     @property
#     def basis(self) -> FrozenSet[Perm]:
#         """Getter for basis."""
#         return self._basis
# 
#     @classmethod
#     def reference(cls) -> str:
#         """A reference for the strategy."""
#         raise NotImplementedError
# 
#     @abstractmethod
#     def applies(self) -> bool:
#         """Return True if the strategy can be used for the basis."""
# 
# Path: permuta/permutils/insertion_encodable.py
# class InsertionEncodablePerms:
#     """A static container of functions fortesting
#     if a basis has a regular insertion encoding.
#     """
# 
#     _ALL_PROPERTIES: ClassVar[int] = 15
#     _CACHE: ClassVar[Dict[Tuple, int]] = {}
# 
#     @staticmethod
#     def _is_incr_next_incr(perm: Perm) -> bool:
#         n = len(perm)
#         return not any(
#             curr < prev and any(perm[j + 1] < perm[j] for j in range(i + 1, n - 1))
#             for i, (prev, curr) in enumerate(zip(perm, islice(perm, 1, None)))
#         )
# 
#     @staticmethod
#     def _is_incr_next_decr(perm: Perm) -> bool:
#         n = len(perm)
#         return not any(
#             curr < prev and any(perm[j + 1] > perm[j] for j in range(i + 1, n - 1))
#             for i, (prev, curr) in enumerate(zip(perm, islice(perm, 1, None)))
#         )
# 
#     @staticmethod
#     def _is_decr_next_incr(perm: Perm) -> bool:
#         n = len(perm)
#         return not any(
#             curr > prev and any(perm[j + 1] < perm[j] for j in range(i + 1, n - 1))
#             for i, (prev, curr) in enumerate(zip(perm, islice(perm, 1, None)))
#         )
# 
#     @staticmethod
#     def _is_decr_next_decr(perm: Perm) -> bool:
#         n = len(perm)
#         return not any(
#             curr > prev and any(perm[j + 1] > perm[j] for j in range(i + 1, n - 1))
#             for i, (prev, curr) in enumerate(zip(perm, islice(perm, 1, None)))
#         )
# 
#     @staticmethod
#     def _insertion_encodable_properties(perm: Perm) -> int:
#         properties = InsertionEncodablePerms._CACHE.get(perm, -1)
#         if properties < 0:
#             properties = sum(
#                 val << shift
#                 for shift, val in enumerate(
#                     (
#                         InsertionEncodablePerms._is_incr_next_decr(perm),
#                         InsertionEncodablePerms._is_incr_next_incr(perm),
#                         InsertionEncodablePerms._is_decr_next_decr(perm),
#                         InsertionEncodablePerms._is_decr_next_incr(perm),
#                     )
#                 )
#             )
#             InsertionEncodablePerms._CACHE[perm] = properties
#         return properties
# 
#     @staticmethod
#     def is_insertion_encodable_rightmost(basis: Iterable[Perm]) -> bool:
#         """Check if basis is insertion encodable by rightmost."""
#         curr = 0
#         for perm in basis:
#             curr = curr | InsertionEncodablePerms._insertion_encodable_properties(perm)
#             if curr == InsertionEncodablePerms._ALL_PROPERTIES:
#                 return True
#         return False
# 
#     @staticmethod
#     def is_insertion_encodable_maximum(basis: Iterable[Perm]) -> bool:
#         """Check if basis is insertion encodable by maximum."""
#         curr = 0
#         for perm in basis:
#             curr = curr | InsertionEncodablePerms._insertion_encodable_properties(
#                 perm.rotate()
#             )
#             if curr == InsertionEncodablePerms._ALL_PROPERTIES:
#                 return True
#         return False
# 
#     @staticmethod
#     def is_insertion_encodable(basis: Iterable[Perm]) -> bool:
#         """Check if basis is insertion encodable."""
#         return InsertionEncodablePerms.is_insertion_encodable_rightmost(
#             basis
#         ) or InsertionEncodablePerms.is_insertion_encodable_maximum(basis)
# 
# Path: permuta/permutils/symmetry.py
# def rotate_90_clockwise_set(perms: Iterable[Perm]) -> Iterator[Perm]:
#     """Rotate all perms by 90 degrees."""
#     return (perm.rotate() for perm in perms)


# Path: permuta/enumeration_strategies/insertion_encodable.py
from permuta.enumeration_strategies.abstract_strategy import EnumerationStrategy
from permuta.permutils.insertion_encodable import InsertionEncodablePerms
from permuta.permutils.symmetry import rotate_90_clockwise_set



class InsertionEncodingStrategy(EnumerationStrategy):
    """Enumeration strategies related to the insertion encoding."""

    def applies(self) -> bool:
        return InsertionEncodablePerms.is_insertion_encodable(
            self.basis

        ) or InsertionEncodablePerms.is_insertion_encodable(