def FormsRing(analytic_type, group=3, base_ring=ZZ, red_hom=False): r""" Return the FormsRing with the given ``analytic_type``, ``group`` ``base_ring`` and variable ``red_hom``. INPUT: - ``analytic_type`` -- An element of ``AnalyticType()`` describing the analytic type of the space. - ``group`` -- The index of the (Hecke triangle) group of the space (default: 3`). - ``base_ring`` -- The base ring of the space (default: ``ZZ``). - ``red_hom`` -- The (boolean= variable ``red_hom`` of the space (default: ``False``). For the variables ``group``, ``base_ring``, ``red_hom`` the same arguments as for the class ``FormsRing_abstract`` can be used. The variables will then be put in canonical form. OUTPUT: The FormsRing with the given properties. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.constructor import FormsRing sage: FormsRing("cusp", group=5, base_ring=CC) CuspFormsRing(n=5) over Complex Field with 53 bits of precision sage: FormsRing("holo") ModularFormsRing(n=3) over Integer Ring sage: FormsRing("weak", group=6, base_ring=ZZ, red_hom=True) WeakModularFormsRing(n=6) over Integer Ring sage: FormsRing("mero", group=7, base_ring=ZZ) MeromorphicModularFormsRing(n=7) over Integer Ring sage: FormsRing(["quasi", "cusp"], group=5, base_ring=CC) QuasiCuspFormsRing(n=5) over Complex Field with 53 bits of precision sage: FormsRing(["quasi", "holo"]) QuasiModularFormsRing(n=3) over Integer Ring sage: FormsRing(["quasi", "weak"], group=6, base_ring=ZZ, red_hom=True) QuasiWeakModularFormsRing(n=6) over Integer Ring sage: FormsRing(["quasi", "mero"], group=7, base_ring=ZZ, red_hom=True) QuasiMeromorphicModularFormsRing(n=7) over Integer Ring sage: FormsRing(["quasi", "cusp"], group=infinity) QuasiCuspFormsRing(n=+Infinity) over Integer Ring """ from graded_ring import canonical_parameters (group, base_ring, red_hom, n) = canonical_parameters(group, base_ring, red_hom) from analytic_type import AnalyticType AT = AnalyticType() analytic_type = AT(analytic_type) if analytic_type <= AT("mero"): if analytic_type <= AT("weak"): if analytic_type <= AT("holo"): if analytic_type <= AT("cusp"): if analytic_type <= AT([]): raise ValueError( "Analytic type Zero is not valid for forms rings.") else: from graded_ring import CuspFormsRing return CuspFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from graded_ring import ModularFormsRing return ModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from graded_ring import WeakModularFormsRing return WeakModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from graded_ring import MeromorphicModularFormsRing return MeromorphicModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) elif analytic_type <= AT(["mero", "quasi"]): if analytic_type <= AT(["weak", "quasi"]): if analytic_type <= AT(["holo", "quasi"]): if analytic_type <= AT(["cusp", "quasi"]): if analytic_type <= AT(["quasi"]): raise ValueError( "Analytic type Zero is not valid for forms rings.") else: from graded_ring import QuasiCuspFormsRing return QuasiCuspFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from graded_ring import QuasiModularFormsRing return QuasiModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from graded_ring import QuasiWeakModularFormsRing return QuasiWeakModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: from graded_ring import QuasiMeromorphicModularFormsRing return QuasiMeromorphicModularFormsRing(group=group, base_ring=base_ring, red_hom=red_hom) else: raise NotImplementedError("Analytic type not implemented.")
def FormsSpace(analytic_type, group=3, base_ring=ZZ, k=QQ(0), ep=None): r""" Return the FormsSpace with the given ``analytic_type``, ``group`` ``base_ring`` and degree (``k``, ``ep``). INPUT: - ``analytic_type`` -- An element of ``AnalyticType()`` describing the analytic type of the space. - ``group`` -- The index of the (Hecke triangle) group of the space (default: `3`). - ``base_ring`` -- The base ring of the space (default: ``ZZ``). - ``k`` -- The weight of the space, a rational number (default: ``0``). - ``ep`` -- The multiplier of the space, `1`, `-1` or ``None`` (in case ``ep`` should be determined from ``k``). Default: ``None``. For the variables ``group``, ``base_ring``, ``k``, ``ep`` the same arguments as for the class ``FormsSpace_abstract`` can be used. The variables will then be put in canonical form. In particular the multiplier ``ep`` is calculated as usual from ``k`` if ``ep == None``. OUTPUT: The FormsSpace with the given properties. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.constructor import FormsSpace sage: FormsSpace([]) ZeroForms(n=3, k=0, ep=1) over Integer Ring sage: FormsSpace(["quasi"]) # not implemented sage: FormsSpace("cusp", group=5, base_ring=CC, k=12, ep=1) CuspForms(n=5, k=12, ep=1) over Complex Field with 53 bits of precision sage: FormsSpace("holo") ModularForms(n=3, k=0, ep=1) over Integer Ring sage: FormsSpace("weak", group=6, base_ring=ZZ, k=0, ep=-1) WeakModularForms(n=6, k=0, ep=-1) over Integer Ring sage: FormsSpace("mero", group=7, base_ring=ZZ, k=2, ep=-1) MeromorphicModularForms(n=7, k=2, ep=-1) over Integer Ring sage: FormsSpace(["quasi", "cusp"], group=5, base_ring=CC, k=12, ep=1) QuasiCuspForms(n=5, k=12, ep=1) over Complex Field with 53 bits of precision sage: FormsSpace(["quasi", "holo"]) QuasiModularForms(n=3, k=0, ep=1) over Integer Ring sage: FormsSpace(["quasi", "weak"], group=6, base_ring=ZZ, k=0, ep=-1) QuasiWeakModularForms(n=6, k=0, ep=-1) over Integer Ring sage: FormsSpace(["quasi", "mero"], group=7, base_ring=ZZ, k=2, ep=-1) QuasiMeromorphicModularForms(n=7, k=2, ep=-1) over Integer Ring sage: FormsSpace(["quasi", "cusp"], group=infinity, base_ring=ZZ, k=2, ep=-1) QuasiCuspForms(n=+Infinity, k=2, ep=-1) over Integer Ring """ from space import canonical_parameters (group, base_ring, k, ep, n) = canonical_parameters(group, base_ring, k, ep) from analytic_type import AnalyticType AT = AnalyticType() analytic_type = AT(analytic_type) if analytic_type <= AT("mero"): if analytic_type <= AT("weak"): if analytic_type <= AT("holo"): if analytic_type <= AT("cusp"): if analytic_type <= AT([]): from space import ZeroForm return ZeroForm(group=group, base_ring=base_ring, k=k, ep=ep) else: from space import CuspForms return CuspForms(group=group, base_ring=base_ring, k=k, ep=ep) else: from space import ModularForms return ModularForms(group=group, base_ring=base_ring, k=k, ep=ep) else: from space import WeakModularForms return WeakModularForms(group=group, base_ring=base_ring, k=k, ep=ep) else: from space import MeromorphicModularForms return MeromorphicModularForms(group=group, base_ring=base_ring, k=k, ep=ep) elif analytic_type <= AT(["mero", "quasi"]): if analytic_type <= AT(["weak", "quasi"]): if analytic_type <= AT(["holo", "quasi"]): if analytic_type <= AT(["cusp", "quasi"]): if analytic_type <= AT(["quasi"]): raise ValueError( "There should be only non-quasi ZeroForms. That could be changed but then this exception should be removed." ) from space import ZeroForm return ZeroForm(group=group, base_ring=base_ring, k=k, ep=ep) else: from space import QuasiCuspForms return QuasiCuspForms(group=group, base_ring=base_ring, k=k, ep=ep) else: from space import QuasiModularForms return QuasiModularForms(group=group, base_ring=base_ring, k=k, ep=ep) else: from space import QuasiWeakModularForms return QuasiWeakModularForms(group=group, base_ring=base_ring, k=k, ep=ep) else: from space import QuasiMeromorphicModularForms return QuasiMeromorphicModularForms(group=group, base_ring=base_ring, k=k, ep=ep) else: raise NotImplementedError("Analytic type not implemented.")
class FormsRingFunctor(ConstructionFunctor): r""" Construction functor for forms rings. NOTE: When the base ring is not a ``BaseFacade`` the functor is first merged with the ConstantFormsSpaceFunctor. This case occurs in the pushout constructions. (when trying to find a common parent between a forms ring and a ring which is not a ``BaseFacade``). """ from analytic_type import AnalyticType AT = AnalyticType() rank = 10 def __init__(self, analytic_type, group, red_hom): r""" Construction functor for the forms ring with the given ``analytic_type``, ``group`` and variable ``red_hom`` See :meth:`__call__` for a description of the functor. INPUT: - ``analytic_type`` -- An element of ``AnalyticType()``. - ``group`` -- The index of a Hecke Triangle group. - ``red_hom`` -- A boolean variable for the parameter ``red_hom`` (also see ``FormsRing_abstract``). OUTPUT: The construction functor for the corresponding forms ring. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import FormsRingFunctor sage: FormsRingFunctor(["quasi", "mero"], group=6, red_hom=False) QuasiMeromorphicModularFormsRingFunctor(n=6) sage: FormsRingFunctor(["quasi", "mero"], group=6, red_hom=True) QuasiMeromorphicModularFormsRingFunctor(n=6, red_hom=True) """ Functor.__init__(self, Rings(), Rings()) from graded_ring import canonical_parameters (self._group, R, red_hom, n) = canonical_parameters(group, ZZ, red_hom) self._red_hom = bool(red_hom) self._analytic_type = self.AT(analytic_type) def __call__(self, R): r""" If ``R`` is a ``BaseFacade(S)`` then return the corresponding forms ring with base ring ``_get_base_ring(S)``. If not then we first merge the functor with the ConstantFormsSpaceFunctor. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import (FormsRingFunctor, BaseFacade) sage: F = FormsRingFunctor(["quasi", "mero"], group=6, red_hom=False) sage: F(BaseFacade(ZZ)) QuasiMeromorphicModularFormsRing(n=6) over Integer Ring sage: F(BaseFacade(CC)) QuasiMeromorphicModularFormsRing(n=6) over Complex Field with 53 bits of precision sage: F(CC) QuasiMeromorphicModularFormsRing(n=6) over Complex Field with 53 bits of precision sage: F(CC).has_reduce_hom() False """ if (isinstance(R, BaseFacade)): R = _get_base_ring(R._ring) return FormsRing(self._analytic_type, self._group, R, self._red_hom) else: R = BaseFacade(_get_base_ring(R)) merged_functor = self.merge(ConstantFormsSpaceFunctor(self._group)) return merged_functor(R) def __str__(self): r""" Return the string representation of ``self``. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import FormsRingFunctor sage: str(FormsRingFunctor(["quasi", "mero"], group=6, red_hom=True)) 'QuasiMeromorphicModularFormsRingFunctor(n=6, red_hom=True)' sage: FormsRingFunctor(["quasi", "mero"], group=6, red_hom=False) QuasiMeromorphicModularFormsRingFunctor(n=6) """ if (self._red_hom): red_arg = ", red_hom=True" else: red_arg = "" return "{}FormsRingFunctor(n={}{})".format( self._analytic_type.analytic_space_name(), self._group.n(), red_arg) def merge(self, other): r""" Return the merged functor of ``self`` and ``other``. It is only possible to merge instances of ``FormsSpaceFunctor`` and ``FormsRingFunctor``. Also only if they share the same group. An ``FormsSubSpaceFunctors`` is replaced by its ambient space functor. The analytic type of the merged functor is the extension of the two analytic types of the functors. The ``red_hom`` parameter of the merged functor is the logical ``and`` of the two corresponding ``red_hom`` parameters (where a forms space is assumed to have it set to ``True``). Two ``FormsSpaceFunctor`` with different (k,ep) are merged to a corresponding ``FormsRingFunctor``. Otherwise the corresponding (extended) ``FormsSpaceFunctor`` is returned. A ``FormsSpaceFunctor`` and ``FormsRingFunctor`` are merged to a corresponding (extended) ``FormsRingFunctor``. Two ``FormsRingFunctors`` are merged to the corresponding (extended) ``FormsRingFunctor``. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import (FormsSpaceFunctor, FormsRingFunctor) sage: functor1 = FormsRingFunctor("mero", group=6, red_hom=True) sage: functor2 = FormsRingFunctor(["quasi", "cusp"], group=6, red_hom=False) sage: functor3 = FormsSpaceFunctor("weak", group=6, k=0, ep=1) sage: functor4 = FormsRingFunctor("mero", group=5, red_hom=True) sage: functor1.merge(functor1) is functor1 True sage: functor1.merge(functor4) is None True sage: functor1.merge(functor2) QuasiMeromorphicModularFormsRingFunctor(n=6) sage: functor1.merge(functor3) MeromorphicModularFormsRingFunctor(n=6, red_hom=True) """ if (self == other): return self if isinstance(other, FormsSubSpaceFunctor): other = other._ambient_space_functor if isinstance(other, FormsSpaceFunctor): if not (self._group == other._group): return None red_hom = self._red_hom analytic_type = self._analytic_type + other._analytic_type return FormsRingFunctor(analytic_type, self._group, red_hom) elif isinstance(other, FormsRingFunctor): if not (self._group == other._group): return None red_hom = self._red_hom & other._red_hom analytic_type = self._analytic_type + other._analytic_type return FormsRingFunctor(analytic_type, self._group, red_hom) def __eq__(self, other): r""" Compare ``self`` and ``other``. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import FormsRingFunctor sage: functor1 = FormsRingFunctor("holo", group=4, red_hom=True) sage: functor2 = FormsRingFunctor("holo", group=4, red_hom=False) sage: functor1 == functor2 False """ if ( type(self) == type(other)\ and self._group == other._group\ and self._analytic_type == other._analytic_type\ and self._red_hom == other._red_hom ): return True else: return False
def rational_type(f, n=ZZ(3), base_ring=ZZ): r""" Return the basic analytic properties that can be determined directly from the specified rational function ``f`` which is interpreted as a representation of an element of a FormsRing for the Hecke Triangle group with parameter ``n`` and the specified ``base_ring``. In particular the following degree of the generators is assumed: `deg(1) := (0, 1)` `deg(x) := (4/(n-2), 1)` `deg(y) := (2n/(n-2), -1)` `deg(z) := (2, -1)` The meaning of homogeneous elements changes accordingly. INPUT: - ``f`` -- A rational function in ``x,y,z,d`` over ``base_ring``. - ``n`` -- An integer greater or equal to `3` corresponding to the ``HeckeTriangleGroup`` with that parameter (default: `3`). - ``base_ring`` -- The base ring of the corresponding forms ring, resp. polynomial ring (default: ``ZZ``). OUTPUT: A tuple ``(elem, h**o, k, ep, analytic_type)`` describing the basic analytic properties of `f` (with the interpretation indicated above). - ``elem`` -- ``True`` if `f` has a homogeneous denominator. - ``h**o`` -- ``True`` if `f` also has a homogeneous numerator. - ``k`` -- ``None`` if `f` is not homogeneneous, otherwise the weight of `f` (which is the first component of its degree). - ``ep`` -- ``None`` if `f` is not homogeneous, otherwise the multiplier of `f` (which is the second component of its degree) - ``analytic_type`` -- The ``AnalyticType`` of `f`. For the zero function the degree `(0, 1)` is choosen. This function is (heavily) used to determine the type of elements and to check if the element really is contained in its parent. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.constructor import rational_type sage: (x,y,z,d) = var("x,y,z,d") sage: rational_type(0, n=4) (True, True, 0, 1, zero) sage: rational_type(1, n=12) (True, True, 0, 1, modular) sage: rational_type(x^3 - y^2) (True, True, 12, 1, cuspidal) sage: rational_type(x * z, n=7) (True, True, 14/5, -1, quasi modular) sage: rational_type(1/(x^3 - y^2) + z/d) (True, False, None, None, quasi weakly holomorphic modular) sage: rational_type(x^3/(x^3 - y^2)) (True, True, 0, 1, weakly holomorphic modular) sage: rational_type(1/(x + z)) (False, False, None, None, None) sage: rational_type(1/x + 1/z) (True, False, None, None, quasi meromorphic modular) sage: rational_type(d/x, n=10) (True, True, -1/2, 1, meromorphic modular) sage: rational_type(1.1 * z * (x^8-y^2), n=8, base_ring=CC) (True, True, 22/3, -1, quasi cuspidal) sage: rational_type(x-y^2, n=infinity) (True, True, 4, 1, modular) sage: rational_type(x*(x-y^2), n=infinity) (True, True, 8, 1, cuspidal) sage: rational_type(1/x, n=infinity) (True, True, -4, 1, weakly holomorphic modular) """ from analytic_type import AnalyticType AT = AnalyticType() # Determine whether f is zero if (f == 0): # elem, h**o, k, ep, analytic_type return (True, True, QQ(0), ZZ(1), AT([])) analytic_type = AT(["quasi", "mero"]) R = PolynomialRing(base_ring, 'x,y,z,d') F = FractionField(R) (x, y, z, d) = R.gens() R2 = PolynomialRing(PolynomialRing(base_ring, 'd'), 'x,y,z') dhom = R.hom(R2.gens() + (R2.base().gen(), ), R2) f = F(f) num = R(f.numerator()) denom = R(f.denominator()) ep_num = set([ ZZ(1) - 2 * ((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(num).monomials() ]) ep_denom = set([ ZZ(1) - 2 * ((sum([g.exponents()[0][m] for m in [1, 2]])) % 2) for g in dhom(denom).monomials() ]) if (n == infinity): hom_num = R(num.subs(x=x**4, y=y**2, z=z**2)) hom_denom = R(denom.subs(x=x**4, y=y**2, z=z**2)) else: n = ZZ(n) hom_num = R(num.subs(x=x**4, y=y**(2 * n), z=z**(2 * (n - 2)))) hom_denom = R(denom.subs(x=x**4, y=y**(2 * n), z=z**(2 * (n - 2)))) # Determine whether the denominator of f is homogeneous if (len(ep_denom) == 1 and dhom(hom_denom).is_homogeneous()): elem = True else: # elem, h**o, k, ep, analytic_type return (False, False, None, None, None) # Determine whether f is homogeneous if (len(ep_num) == 1 and dhom(hom_num).is_homogeneous()): h**o = True if (n == infinity): weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) else: weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) / (n - 2) ep = ep_num.pop() / ep_denom.pop() # TODO: decompose f (resp. its degrees) into homogeneous parts else: h**o = False weight = None ep = None # Note that we intentially leave out the d-factor! if (n == infinity): finf_pol = (x - y**2) else: finf_pol = x**n - y**2 # Determine whether f is modular if not ((num.degree(z) > 0) or (denom.degree(z) > 0)): analytic_type = analytic_type.reduce_to("mero") # Determine whether f is holomorphic if (dhom(denom).is_constant()): analytic_type = analytic_type.reduce_to(["quasi", "holo"]) # Determine whether f is cuspidal in the sense that finf divides it... # Bug in singular: finf_pol.dividess(1.0) fails over RR if (not dhom(num).is_constant() and finf_pol.divides(num)): if (n != infinity or x.divides(num)): analytic_type = analytic_type.reduce_to(["quasi", "cusp"]) else: # -> Because of a bug with singular in some cases try: while (finf_pol.divides(denom)): # a simple "denom /= finf_pol" is strangely not enough for non-exact rings # and dividing would/may result with an element of the quotient ring of the polynomial ring denom = denom.quo_rem(finf_pol)[0] denom = R(denom) if (n == infinity): while (x.divides(denom)): # a simple "denom /= x" is strangely not enough for non-exact rings # and dividing would/may result with an element of the quotient ring of the polynomial ring denom = denom.quo_rem(x)[0] denom = R(denom) except TypeError: pass # Determine whether f is weakly holomorphic in the sense that at most powers of finf occur in denom if (dhom(denom).is_constant()): analytic_type = analytic_type.reduce_to(["quasi", "weak"]) return (elem, h**o, weight, ep, analytic_type)
class FormsSpaceFunctor(ConstructionFunctor): r""" Construction functor for forms spaces. NOTE: When the base ring is not a ``BaseFacade`` the functor is first merged with the ConstantFormsSpaceFunctor. This case occurs in the pushout constructions (when trying to find a common parent between a forms space and a ring which is not a ``BaseFacade``). """ from analytic_type import AnalyticType AT = AnalyticType() rank = 10 def __init__(self, analytic_type, group, k, ep): r""" Construction functor for the forms space (or forms ring, see above) with the given ``analytic_type``, ``group``, weight ``k`` and multiplier ``ep``. See :meth:`__call__` for a description of the functor. INPUT: - ``analytic_type`` -- An element of ``AnalyticType()``. - ``group`` -- The index of a Hecke Triangle group. - ``k`` -- A rational number, the weight of the space. - ``ep`` -- `1` or `-1`, the multiplier of the space. OUTPUT: The construction functor for the corresponding forms space/ring. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import FormsSpaceFunctor sage: FormsSpaceFunctor(["holo", "weak"], group=4, k=0, ep=-1) WeakModularFormsFunctor(n=4, k=0, ep=-1) """ Functor.__init__(self, Rings(), CommutativeAdditiveGroups()) from space import canonical_parameters (self._group, R, self._k, self._ep, n) = canonical_parameters(group, ZZ, k, ep) self._analytic_type = self.AT(analytic_type) def __call__(self, R): r""" If ``R`` is a ``BaseFacade(S)`` then return the corresponding forms space with base ring ``_get_base_ring(S)``. If not then we first merge the functor with the ConstantFormsSpaceFunctor. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import (FormsSpaceFunctor, BaseFacade) sage: F = FormsSpaceFunctor(["holo", "weak"], group=4, k=0, ep=-1) sage: F(BaseFacade(ZZ)) WeakModularForms(n=4, k=0, ep=-1) over Integer Ring sage: F(BaseFacade(CC)) WeakModularForms(n=4, k=0, ep=-1) over Complex Field with 53 bits of precision sage: F(CC) WeakModularFormsRing(n=4) over Complex Field with 53 bits of precision sage: F(CC).has_reduce_hom() True """ if (isinstance(R, BaseFacade)): R = _get_base_ring(R._ring) return FormsSpace(self._analytic_type, self._group, R, self._k, self._ep) else: R = BaseFacade(_get_base_ring(R)) merged_functor = self.merge(ConstantFormsSpaceFunctor(self._group)) return merged_functor(R) def __str__(self): r""" Return the string representation of ``self``. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import FormsSpaceFunctor sage: F = FormsSpaceFunctor(["cusp", "quasi"], group=5, k=10/3, ep=-1) sage: str(F) 'QuasiCuspFormsFunctor(n=5, k=10/3, ep=-1)' sage: F QuasiCuspFormsFunctor(n=5, k=10/3, ep=-1) """ return "{}FormsFunctor(n={}, k={}, ep={})".format( self._analytic_type.analytic_space_name(), self._group.n(), self._k, self._ep) def merge(self, other): r""" Return the merged functor of ``self`` and ``other``. It is only possible to merge instances of ``FormsSpaceFunctor`` and ``FormsRingFunctor``. Also only if they share the same group. An ``FormsSubSpaceFunctors`` is replaced by its ambient space functor. The analytic type of the merged functor is the extension of the two analytic types of the functors. The ``red_hom`` parameter of the merged functor is the logical ``and`` of the two corresponding ``red_hom`` parameters (where a forms space is assumed to have it set to ``True``). Two ``FormsSpaceFunctor`` with different (k,ep) are merged to a corresponding ``FormsRingFunctor``. Otherwise the corresponding (extended) ``FormsSpaceFunctor`` is returned. A ``FormsSpaceFunctor`` and ``FormsRingFunctor`` are merged to a corresponding (extended) ``FormsRingFunctor``. Two ``FormsRingFunctors`` are merged to the corresponding (extended) ``FormsRingFunctor``. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import (FormsSpaceFunctor, FormsRingFunctor) sage: functor1 = FormsSpaceFunctor("holo", group=5, k=0, ep=1) sage: functor2 = FormsSpaceFunctor(["quasi", "cusp"], group=5, k=10/3, ep=-1) sage: functor3 = FormsSpaceFunctor(["quasi", "mero"], group=5, k=0, ep=1) sage: functor4 = FormsRingFunctor("cusp", group=5, red_hom=False) sage: functor5 = FormsSpaceFunctor("holo", group=4, k=0, ep=1) sage: functor1.merge(functor1) is functor1 True sage: functor1.merge(functor5) is None True sage: functor1.merge(functor2) QuasiModularFormsRingFunctor(n=5, red_hom=True) sage: functor1.merge(functor3) QuasiMeromorphicModularFormsFunctor(n=5, k=0, ep=1) sage: functor1.merge(functor4) ModularFormsRingFunctor(n=5) """ if (self == other): return self if isinstance(other, FormsSubSpaceFunctor): other = other._ambient_space_functor if isinstance(other, FormsSpaceFunctor): if not (self._group == other._group): return None analytic_type = self._analytic_type + other._analytic_type if (self._k == other._k) and (self._ep == other._ep): return FormsSpaceFunctor(analytic_type, self._group, self._k, self._ep) else: return FormsRingFunctor(analytic_type, self._group, True) elif isinstance(other, FormsRingFunctor): if not (self._group == other._group): return None red_hom = other._red_hom analytic_type = self._analytic_type + other._analytic_type return FormsRingFunctor(analytic_type, self._group, red_hom) def __eq__(self, other): r""" Compare ``self`` and ``other``. EXAMPLES:: sage: from sage.modular.modform_hecketriangle.functors import FormsSpaceFunctor sage: functor1 = FormsSpaceFunctor("holo", group=4, k=12, ep=1) sage: functor2 = FormsSpaceFunctor("holo", group=4, k=12, ep=-1) sage: functor1 == functor2 False """ if (type(self) is type(other) and self._group == other._group and self._analytic_type == other._analytic_type and self._k == other._k and self._ep == other._ep): return True else: return False