(self, other, k=10)
r"""Return the normal closure of a subgroup/set of permutations.

        If ``S`` is a subset of a group ``G``, the normal closure of ``A`` in ``G``
        is defined as the intersection of all normal subgroups of ``G`` that
        contain ``A`` ([1], p.14). Alternatively, it is the group generated by
        the conjugates ``x^{-1}yx`` for ``x`` a generator of ``G`` and ``y`` a
        generator of the subgroup ``\left\langle S\right\rangle`` generated by
        ``S`` (for some chosen generating set for ``\left\langle S\right\rangle``)
        ([1], p.73).

        Parameters
        ==========

        other
            a subgroup/list of permutations/single permutation
        k
            an implementation-specific parameter that determines the number
            of conjugates that are adjoined to ``other`` at once

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import (SymmetricGroup,
        ... CyclicGroup, AlternatingGroup)
        >>> S = SymmetricGroup(5)
        >>> C = CyclicGroup(5)
        >>> G = S.normal_closure(C)
        >>> G.order()
        60
        >>> G.is_subgroup(AlternatingGroup(5))
        True

        See Also
        ========

        commutator, derived_subgroup, random_pr

        Notes
        =====

        The algorithm is described in [1], pp. 73-74; it makes use of the
        generation of random elements for permutation groups by the product
        replacement algorithm.
r"""Return the normal closure of a subgroup/set of permutations.
r Return the normal closure of a subgroup / set of permutations .
def normal_closure(self, other, k=10):
        r"""Return the normal closure of a subgroup/set of permutations.

        If ``S`` is a subset of a group ``G``, the normal closure of ``A`` in ``G``
        is defined as the intersection of all normal subgroups of ``G`` that
        contain ``A`` ([1], p.14). Alternatively, it is the group generated by
        the conjugates ``x^{-1}yx`` for ``x`` a generator of ``G`` and ``y`` a
        generator of the subgroup ``\left\langle S\right\rangle`` generated by
        ``S`` (for some chosen generating set for ``\left\langle S\right\rangle``)
        ([1], p.73).

        Parameters
        ==========

        other
            a subgroup/list of permutations/single permutation
        k
            an implementation-specific parameter that determines the number
            of conjugates that are adjoined to ``other`` at once

        Examples
        ========

        >>> from sympy.combinatorics.named_groups import (SymmetricGroup,
        ... CyclicGroup, AlternatingGroup)
        >>> S = SymmetricGroup(5)
        >>> C = CyclicGroup(5)
        >>> G = S.normal_closure(C)
        >>> G.order()
        60
        >>> G.is_subgroup(AlternatingGroup(5))
        True

        See Also
        ========

        commutator, derived_subgroup, random_pr

        Notes
        =====

        The algorithm is described in [1], pp. 73-74; it makes use of the
        generation of random elements for permutation groups by the product
        replacement algorithm.

        """
        if hasattr(other, 'generators'):
            degree = self.degree
            identity = _af_new(list(range(degree)))

            if all(g == identity for g in other.generators):
                return other
            Z = PermutationGroup(other.generators[:])
            base, strong_gens = Z.schreier_sims_incremental()
            strong_gens_distr = _distribute_gens_by_base(base, strong_gens)
            basic_orbits, basic_transversals = \
                _orbits_transversals_from_bsgs(base, strong_gens_distr)

            self._random_pr_init(r=10, n=20)

            _loop = True
            while _loop:
                Z._random_pr_init(r=10, n=10)
                for i in range(k):
                    g = self.random_pr()
                    h = Z.random_pr()
                    conj = h^g
                    res = _strip(conj, base, basic_orbits, basic_transversals)
                    if res[0] != identity or res[1] != len(base) + 1:
                        gens = Z.generators
                        gens.append(conj)
                        Z = PermutationGroup(gens)
                        strong_gens.append(conj)
                        temp_base, temp_strong_gens = \
                            Z.schreier_sims_incremental(base, strong_gens)
                        base, strong_gens = temp_base, temp_strong_gens
                        strong_gens_distr = \
                            _distribute_gens_by_base(base, strong_gens)
                        basic_orbits, basic_transversals = \
                            _orbits_transversals_from_bsgs(base,
                                strong_gens_distr)
                _loop = False
                for g in self.generators:
                    for h in Z.generators:
                        conj = h^g
                        res = _strip(conj, base, basic_orbits,
                                     basic_transversals)
                        if res[0] != identity or res[1] != len(base) + 1:
                            _loop = True
                            break
                    if _loop:
                        break
            return Z
        elif hasattr(other, '__getitem__'):
            return self.normal_closure(PermutationGroup(other))
        elif hasattr(other, 'array_form'):
            return self.normal_closure(PermutationGroup([other]))
def normal_closure ( self , other , k = 10 ) : if hasattr ( other , 'generators' ) : degree = self . degree identity = _af_new ( list ( range ( degree ) ) ) if all ( g == identity for g in other . generators ) : return other Z = PermutationGroup ( other . generators [ : ] ) base , strong_gens = Z . schreier_sims_incremental ( ) strong_gens_distr = _distribute_gens_by_base ( base , strong_gens ) basic_orbits , basic_transversals = _orbits_transversals_from_bsgs ( base , strong_gens_distr ) self . _random_pr_init ( r = 10 , n = 20 ) _loop = True while _loop : Z . _random_pr_init ( r = 10 , n = 10 ) for i in range ( k ) : g = self . random_pr ( ) h = Z . random_pr ( ) conj = h ^ g res = _strip ( conj , base , basic_orbits , basic_transversals ) if res [ 0 ] != identity or res [ 1 ] != len ( base ) + 1 : gens = Z . generators gens . append ( conj ) Z = PermutationGroup ( gens ) strong_gens . append ( conj ) temp_base , temp_strong_gens = Z . schreier_sims_incremental ( base , strong_gens ) base , strong_gens = temp_base , temp_strong_gens strong_gens_distr = _distribute_gens_by_base ( base , strong_gens ) basic_orbits , basic_transversals = _orbits_transversals_from_bsgs ( base , strong_gens_distr ) _loop = False for g in self . generators : for h in Z . generators : conj = h ^ g res = _strip ( conj , base , basic_orbits , basic_transversals ) if res [ 0 ] != identity or res [ 1 ] != len ( base ) + 1 : _loop = True break if _loop : break return Z elif hasattr ( other , '__getitem__' ) : return self . normal_closure ( PermutationGroup ( other ) ) elif hasattr ( other , 'array_form' ) : return self . normal_closure ( PermutationGroup ( [ other ] ) )