Repository: sympy/sympy
File: sympy/combinatorics/homomorphisms.py (Python)

Code before:
        '''
        if self._kernel is None:
            self._kernel = self._compute_kernel()
        return self._kernel

    def _compute_kernel(self):
        G = self.domain
        H = self.codomain
        Ginf = G.order() is S.Infinity
        if Ginf and isinstance(H, (FpGroup, FreeGroup)):
            if isinstance(H, FreeGroup):
                H = FpGroup(H, [])
            preimages = self._is_surjective_cert()
            if preimages is not None:
                symbol_to_preimage = {
                    g.ext_rep[0]: preimages[g] for g in H.generators
                }

                def _lift_to_domain(word):
                    lifted = G.identity
                    for symbol, power in word.array_form:
                        lifted = lifted * symbol_to_preimage[symbol]**power
                    return lifted

                kernel_gens = []
                for relator in H.relators:
                    word = _lift_to_domain(relator)
                    kernel_gens.append(word)

                for generator in G.generators:
                    lifted_image = _lift_to_domain(self(generator))
                    word = generator * lifted_image**-1
                    kernel_gens.append(word)

                if isinstance(G, PermutationGroup):
                    if not kernel_gens:
                        return PermutationGroup([G.identity])
                    return G.normal_closure(kernel_gens)
                return FpSubgroup(G, kernel_gens, normal=True)
            else:
                return self.factor()[0].kernel()

        if Ginf:
            raise NotImplementedError(
                "Kernel computation is not implemented for this group type")

        if isinstance(G, FpGroup):
            P, T = G._to_perm_group()
            perm_images = {g: self(T.invert(g)) for g in P.generators}
            perm_hom = GroupHomomorphism(P, H, perm_images)
            perm_kernel = perm_hom._compute_kernel()

Review comment (performance):
Because none of this code has type annotations it is a bit hard for me to tell sometimes exactly what all the types are.

If the word is long then is it the case that it would be more efficient to have a `prod` function that can efficiently multiply many words?

Code after:
        '''
        Compute the kernel of `self`.

        '''
        if self._kernel is None:
            self._kernel = self._compute_kernel()
        return self._kernel

    def _compute_kernel(self):
        G = self.domain
        H = self.codomain
        Ginf = G.order() is S.Infinity
        if Ginf and isinstance(H, (FpGroup, FreeGroup)):
            if isinstance(H, FreeGroup):
                H = FpGroup(H, [])
            preimages = self._is_surjective_cert()
            if preimages is not None:
                symbol_to_preimage = {
                    g.ext_rep[0]: preimages[g] for g in H.generators
                }

                def _lift_to_domain(word):
                    lifted = G.identity
                    for symbol, power in word.array_form:
                        lifted = lifted * symbol_to_preimage[symbol]**power
                    return lifted

                kernel_gens = []
                for relator in H.relators:
                    word = _lift_to_domain(relator)
                    if not word.is_identity:
                        kernel_gens.append(word)

                for generator in G.generators:
                    lifted_image = _lift_to_domain(self.images[generator])
                    word = generator * lifted_image**-1
                    if not word.is_identity:
                        kernel_gens.append(word)

                if isinstance(G, PermutationGroup):
                    if not kernel_gens:
                        return PermutationGroup([G.identity])
                    return G.normal_closure(kernel_gens)
                return FpSubgroup(G, kernel_gens, normal=True)
            else:
                return self.factor()[0].kernel()

        if Ginf:
            raise NotImplementedError(
                "Kernel computation is not implemented for this group type")