def minimal_strata_spin_diff(gmax, rational=False): r""" Return the differences of volumes between even and odd components in H(2g-2) for the genus `g` going from ``1`` up to ``gmax-1``. If there are no even/odd components, the corresponding total volume is 0. Formulas are from [CheMoeSauZag20]_. EXAMPLES:: sage: from surface_dynamics.flat_surfaces.masur_veech_volumes import minimal_strata_spin_diff sage: minimal_strata_spin_diff(5) [-1/3*pi^2, -1/120*pi^4, -143/544320*pi^6, -15697/1959552000*pi^8] sage: minimal_strata_spin_diff(5, rational=True) [-2, -3/4, -143/576, -15697/207360] """ n = 2 * gmax R = QQ['u'] u = R.gen() # B(u) = formula (15) in [CMSZ20] B = (2 * (u/2)._sinh_series(n).shift(-1)).inverse_series_trunc(n) # Pz and a in section 6.3 of [CMSZ20] Pz = (sum(-bernoulli(2*j) * u**(2*j) / (2*j) / 2**j for j in range(1, n // 2)))._exp_series(n) a = ((u*Pz.inverse_series_trunc(n)).revert_series(n).shift(-1) ).inverse_series_trunc(n) # theorem 6.11 in [CMSZ20], normalized volume v(2g-2)=(2g-1)*Vol(2g-2), note the missing factor 2 if rational: return [2* (-2) * a[2*g] * 2 * g / (2*g - 1) / bernoulli(2*g) for g in range(1, gmax)] else: return [2* (-1)**(g) * (2*pi)**(2*g) * a[2 * g] /(2*g - 1) / factorial(2*g - 1) for g in range(1, gmax)]
def zeta_no_pi(k): r""" zeta(2m+2) = (-1)^m B_{2m+2} (2pi)^(2m+2) / (2 (2m+2)!) EXAMPLES:: sage: from surface_dynamics.topological_recursion.no_pi import zeta_no_pi sage: zeta_no_pi(2) 1/6 sage: zeta_no_pi(4) 1/90 sage: zeta_no_pi(6) 1/945 sage: zeta(2) 1/6*pi^2 sage: zeta(4) 1/90*pi^4 sage: zeta(6) 1/945*pi^6 """ k = ZZ(k) if k % 2: raise ValueError m = (k - 2) // 2 return ZZ(-1)**m * bernoulli(k) * ZZ_2**(k - 1) / k.factorial()
def eisenstein_series(self, k, prec): r""" Compute the Hilbert Eisenstein series E_k(tau1, tau2). This is a simple algorithm based on the theta lift. We do not use a closed formula for Eisenstein series coefficients. INPUT: - ``k`` -- the weight (an even integer >= 2) - ``prec`` -- the precision of the output OUTPUT: HilbertModularForm EXAMPLES:: sage: from weilrep import * sage: x = var('x') sage: K.<sqrt5> = NumberField(x^2 - 5) sage: HMF(K).eisenstein_series(2, 6) 1 + 120*q1^(-1/10*sqrt5 + 1/2)*q2^(1/10*sqrt5 + 1/2) + 120*q1^(1/10*sqrt5 + 1/2)*q2^(-1/10*sqrt5 + 1/2) + 120*q1^(-2/5*sqrt5 + 1)*q2^(2/5*sqrt5 + 1) + 600*q1^(-1/5*sqrt5 + 1)*q2^(1/5*sqrt5 + 1) + 720*q1*q2 + 600*q1^(1/5*sqrt5 + 1)*q2^(-1/5*sqrt5 + 1) + 120*q1^(2/5*sqrt5 + 1)*q2^(-2/5*sqrt5 + 1) + 720*q1^(-1/2*sqrt5 + 3/2)*q2^(1/2*sqrt5 + 3/2) + 1200*q1^(-3/10*sqrt5 + 3/2)*q2^(3/10*sqrt5 + 3/2) + 1440*q1^(-1/10*sqrt5 + 3/2)*q2^(1/10*sqrt5 + 3/2) + 1440*q1^(1/10*sqrt5 + 3/2)*q2^(-1/10*sqrt5 + 3/2) + 1200*q1^(3/10*sqrt5 + 3/2)*q2^(-3/10*sqrt5 + 3/2) + 720*q1^(1/2*sqrt5 + 3/2)*q2^(-1/2*sqrt5 + 3/2) + 600*q1^(-4/5*sqrt5 + 2)*q2^(4/5*sqrt5 + 2) + 1440*q1^(-3/5*sqrt5 + 2)*q2^(3/5*sqrt5 + 2) + 2520*q1^(-2/5*sqrt5 + 2)*q2^(2/5*sqrt5 + 2) + 2400*q1^(-1/5*sqrt5 + 2)*q2^(1/5*sqrt5 + 2) + 3600*q1^2*q2^2 + 2400*q1^(1/5*sqrt5 + 2)*q2^(-1/5*sqrt5 + 2) + 2520*q1^(2/5*sqrt5 + 2)*q2^(-2/5*sqrt5 + 2) + 1440*q1^(3/5*sqrt5 + 2)*q2^(-3/5*sqrt5 + 2) + 600*q1^(4/5*sqrt5 + 2)*q2^(-4/5*sqrt5 + 2) + 120*q1^(-11/10*sqrt5 + 5/2)*q2^(11/10*sqrt5 + 5/2) + 1440*q1^(-9/10*sqrt5 + 5/2)*q2^(9/10*sqrt5 + 5/2) + 2400*q1^(-7/10*sqrt5 + 5/2)*q2^(7/10*sqrt5 + 5/2) + 3720*q1^(-1/2*sqrt5 + 5/2)*q2^(1/2*sqrt5 + 5/2) + 3600*q1^(-3/10*sqrt5 + 5/2)*q2^(3/10*sqrt5 + 5/2) + 3840*q1^(-1/10*sqrt5 + 5/2)*q2^(1/10*sqrt5 + 5/2) + 3840*q1^(1/10*sqrt5 + 5/2)*q2^(-1/10*sqrt5 + 5/2) + 3600*q1^(3/10*sqrt5 + 5/2)*q2^(-3/10*sqrt5 + 5/2) + 3720*q1^(1/2*sqrt5 + 5/2)*q2^(-1/2*sqrt5 + 5/2) + 2400*q1^(7/10*sqrt5 + 5/2)*q2^(-7/10*sqrt5 + 5/2) + 1440*q1^(9/10*sqrt5 + 5/2)*q2^(-9/10*sqrt5 + 5/2) + 120*q1^(11/10*sqrt5 + 5/2)*q2^(-11/10*sqrt5 + 5/2) + O(q1, q2)^6 """ w = self.weilrep() try: return (-((k + k) / bernoulli(k)) * w.eisenstein_series( k, ceil(prec * prec / 4) + 1)).theta_lift(prec) except (TypeError, ValueError, ZeroDivisionError): raise ValueError('Invalid weight')
def minimal_strata_CMSZ(gmax, rational=False): r""" Return the volumes of `\cH(2g-2)` for the genus `g` going from ``1`` up to ``gmax-1``. The algorithm is the one from Sauvaget [Sau18]_ involving an implicit equation. As explained in [CheMoeSauZag20]_, one could go through Lagrange inversion. Note that they miss factor 2 in their theorem 4.1. EXAMPLES:: sage: from surface_dynamics.flat_surfaces.masur_veech_volumes import minimal_strata_CMSZ sage: minimal_strata_CMSZ(6, True) [2, 3/4, 305/576, 87983/207360, 1019547/2867200] sage: minimal_strata_CMSZ(6, False) [1/3*pi^2, 1/120*pi^4, 61/108864*pi^6, 12569/279936000*pi^8, 12587/3311616000*pi^10] sage: from surface_dynamics import AbelianStratum sage: from surface_dynamics.flat_surfaces.masur_veech_volumes import masur_veech_volume sage: for rat in [True, False]: ....: V0, V2, V4, V6 = minimal_strata_CMSZ(5, rational=rat) ....: MV0 = masur_veech_volume(AbelianStratum(0), rat, 'table') ....: assert V0 == MV0, (V0, MV0, rat) ....: MV2 = masur_veech_volume(AbelianStratum(2), rat, 'table') ....: assert V2 == MV2, (V2, MV2, rat) ....: MV4 = masur_veech_volume(AbelianStratum(4), rat, 'table') ....: assert V4 == MV4, (V4, MV4, rat) ....: MV6 = masur_veech_volume(AbelianStratum(6), rat, 'table') ....: assert V6 == MV6, (V6, MV6, rat) """ n = 2 * gmax - 1 R = QQ['u'] u = R.gen() # B(u) = formula (15) in [CMSZ20] B = (2 * (u/2)._sinh_series(n+1).shift(-1)).inverse_series_trunc(n+1) Q = u * (sum(factorial(j-1) * B[j] * u**(j) for j in range(1,n)))._exp_series(n+1) # A = formula (14) in [CSMZ20] tA = Q.revert_series(n+1).shift(-1).inverse_series_trunc(n) # normalized values of volumes in [CMSZ20] are # v(m_1, ..., m_n) = (2m_1+1) (2m_2+1) ... (2m_n+1) Vol(m_1, m_2, ..., m_n) if rational: return [-4 * (2*g) / ZZ(2*g-1) / bernoulli(2*g) * tA[2*g] for g in range(1,gmax)] else: return [2 * (2*pi)**(2*g) * (-1)**g / ZZ(2*g-1) / factorial(2*g - 1) * tA[2*g] for g in range(1,gmax)]
def eisenstein_series(self, k, prec, allow_small_weight=False): r""" Compute the Eisenstein series. (i.e. the theta lift of a vector-valued Eisenstein series) INPUT: - ``k`` -- the weight (an even integer) - ``prec`` -- the output precision OUTPUT: OrthogonalModularFormLorentzian EXAMPLES:: sage: from weilrep import * sage: OrthogonalModularForms(diagonal_matrix([-2, 2, 2])).eisenstein_series(4, 5) 1 + 480*t + (240*x^-2 + (2880*r_0^-1 + 7680 + 2880*r_0)*x^-1 + (240*r_0^-2 + 7680*r_0^-1 + 18720 + 7680*r_0 + 240*r_0^2) + (2880*r_0^-1 + 7680 + 2880*r_0)*x + 240*x^2)*t^2 + ((480*r_0^-2 + 15360*r_0^-1 + 28800 + 15360*r_0 + 480*r_0^2)*x^-2 + (15360*r_0^-2 + 76800*r_0^-1 + 92160 + 76800*r_0 + 15360*r_0^2)*x^-1 + (28800*r_0^-2 + 92160*r_0^-1 + 134400 + 92160*r_0 + 28800*r_0^2) + (15360*r_0^-2 + 76800*r_0^-1 + 92160 + 76800*r_0 + 15360*r_0^2)*x + (480*r_0^-2 + 15360*r_0^-1 + 28800 + 15360*r_0 + 480*r_0^2)*x^2)*t^3 + (2160*x^-4 + (7680*r_0^-2 + 44160*r_0^-1 + 61440 + 44160*r_0 + 7680*r_0^2)*x^-3 + (7680*r_0^-3 + 112320*r_0^-2 + 207360*r_0^-1 + 312960 + 207360*r_0 + 112320*r_0^2 + 7680*r_0^3)*x^-2 + (44160*r_0^-3 + 207360*r_0^-2 + 380160*r_0^-1 + 430080 + 380160*r_0 + 207360*r_0^2 + 44160*r_0^3)*x^-1 + (2160*r_0^-4 + 61440*r_0^-3 + 312960*r_0^-2 + 430080*r_0^-1 + 656160 + 430080*r_0 + 312960*r_0^2 + 61440*r_0^3 + 2160*r_0^4) + (44160*r_0^-3 + 207360*r_0^-2 + 380160*r_0^-1 + 430080 + 380160*r_0 + 207360*r_0^2 + 44160*r_0^3)*x + (7680*r_0^-3 + 112320*r_0^-2 + 207360*r_0^-1 + 312960 + 207360*r_0 + 112320*r_0^2 + 7680*r_0^3)*x^2 + (7680*r_0^-2 + 44160*r_0^-1 + 61440 + 44160*r_0 + 7680*r_0^2)*x^3 + 2160*x^4)*t^4 + O(t^5) """ w = self.__weilrep try: return (-((k + k) / bernoulli(k)) * w.eisenstein_series( k + self.input_wt(), ceil(prec * prec / 4) + 1, allow_small_weight=allow_small_weight)).theta_lift(prec) except (TypeError, ValueError, ZeroDivisionError): raise ValueError('Invalid weight') from None
def bch_iterator(X=None, Y=None): r""" A generator function which returns successive terms of the Baker-Campbell-Hausdorff formula. INPUT: - ``X`` -- (optional) an element of a Lie algebra - ``Y`` -- (optional) an element of a Lie algebra The BCH formula is an expression for `\log(\exp(X)\exp(Y))` as a sum of Lie brackets of ``X`` and ``Y`` with rational coefficients. In arbitrary Lie algebras, the infinite sum is only guaranteed to converge for ``X`` and ``Y`` close to zero. If the elements ``X`` and ``Y`` are not given, then the iterator will return successive terms of the abstract BCH formula, i.e., the BCH formula for the generators of the free Lie algebra on 2 generators. If the Lie algebra containing ``X`` and ``Y`` is not nilpotent, the iterator will output infinitely many elements. If the Lie algebra is nilpotent, the number of elements outputted is equal to the nilpotency step. EXAMPLES: The terms of the abstract BCH formula up to fifth order brackets:: sage: from sage.algebras.lie_algebras.bch import bch_iterator sage: bch = bch_iterator() sage: next(bch) X + Y sage: next(bch) 1/2*[X, Y] sage: next(bch) 1/12*[X, [X, Y]] + 1/12*[[X, Y], Y] sage: next(bch) 1/24*[X, [[X, Y], Y]] sage: next(bch) -1/720*[X, [X, [X, [X, Y]]]] + 1/180*[X, [X, [[X, Y], Y]]] + 1/360*[[X, [X, Y]], [X, Y]] + 1/180*[X, [[[X, Y], Y], Y]] + 1/120*[[X, Y], [[X, Y], Y]] - 1/720*[[[[X, Y], Y], Y], Y] For nilpotent Lie algebras the BCH formula only has finitely many terms:: sage: L = LieAlgebra(QQ, 2, step=3) sage: L.inject_variables() Defining X_1, X_2, X_12, X_112, X_122 sage: [Z for Z in bch_iterator(X_1, X_2)] [X_1 + X_2, 1/2*X_12, 1/12*X_112 + 1/12*X_122] sage: [Z for Z in bch_iterator(X_1 + X_2, X_12)] [X_1 + X_2 + X_12, 1/2*X_112 - 1/2*X_122, 0] The elements ``X`` and ``Y`` don't need to be elements of the same Lie algebra if there is a coercion from one to the other:: sage: L = LieAlgebra(QQ, 3, step=2) sage: L.inject_variables() Defining X_1, X_2, X_3, X_12, X_13, X_23 sage: S = L.subalgebra(X_1, X_2) sage: bch1 = [Z for Z in bch_iterator(S(X_1), S(X_2))]; bch1 [X_1 + X_2, 1/2*X_12] sage: bch1[0].parent() == S True sage: bch2 = [Z for Z in bch_iterator(S(X_1), X_3)]; bch2 [X_1 + X_3, 1/2*X_13] sage: bch2[0].parent() == L True The BCH formula requires a coercion from the rationals:: sage: L.<X,Y,Z> = LieAlgebra(ZZ, 2, step=2) sage: bch = bch_iterator(X, Y); next(bch) Traceback (most recent call last): ... TypeError: the BCH formula is not well defined since Integer Ring has no coercion from Rational Field TESTS: Compare to the BCH formula up to degree 5 given by wikipedia:: sage: from sage.algebras.lie_algebras.bch import bch_iterator sage: bch = bch_iterator() sage: L.<X,Y> = LieAlgebra(QQ) sage: L = L.Lyndon() sage: computed_BCH = L.sum(next(bch) for k in range(5)) sage: wikiBCH = X + Y + 1/2*L[X,Y] + 1/12*(L[X,[X,Y]] + L[Y,[Y,X]]) sage: wikiBCH += -1/24*L[Y,[X,[X,Y]]] sage: wikiBCH += -1/720*(L[Y,[Y,[Y,[Y,X]]]] + L[X,[X,[X,[X,Y]]]]) sage: wikiBCH += 1/360*(L[X,[Y,[Y,[Y,X]]]] + L[Y,[X,[X,[X,Y]]]]) sage: wikiBCH += 1/120*(L[Y,[X,[Y,[X,Y]]]] + L[X,[Y,[X,[Y,X]]]]) sage: computed_BCH == wikiBCH True ALGORITHM: The BCH formula `\log(\exp(X)\exp(Y)) = \sum_k Z_k` is computed starting from `Z_1 = X + Y`, by the recursion .. MATH:: (m+1)Z_{m+1} = \frac{1}{2}[X - Y, Z_m] + \sum_{2\leq 2p \leq m}\frac{B_{2p}}{(2p)!}\sum_{k_1+\cdots+k_{2p}=m} [Z_{k_1}, [\cdots [Z_{k_{2p}}, X + Y]\cdots], where `B_{2p}` are the Bernoulli numbers, see Lemma 2.15.3. in [Var1984]_. .. WARNING:: The time needed to compute each successive term increases exponentially. For example on one machine iterating through `Z_{11},...,Z_{18}` for a free Lie algebra, computing each successive term took 4-5 times longer, going from 0.1s for `Z_{11}` to 21 minutes for `Z_{18}`. """ if X is None or Y is None: L = LieAlgebra(QQ, ['X', 'Y']).Lyndon() X, Y = L.lie_algebra_generators() else: X, Y = canonical_coercion(X, Y) L = X.parent() R = L.base_ring() if not R.has_coerce_map_from(QQ): raise TypeError("the BCH formula is not well defined since %s " "has no coercion from %s" % (R, QQ)) xdif = X - Y Z = [0, X + Y] # 1-based indexing for convenience m = 1 yield Z[1] while True: m += 1 if L in LieAlgebras.Nilpotent and m > L.step(): return # apply the recursion formula of [Var1984] Zm = ~QQ(2 * m) * xdif.bracket(Z[-1]) for p in range(1, (m - 1) // 2 + 1): partitions = IntegerListsLex(m - 1, length=2 * p, min_part=1) coeff = bernoulli(2 * p) / QQ(m * factorial(2 * p)) for kvec in partitions: W = Z[1] for k in kvec: W = Z[k].bracket(W) Zm += coeff * W Z.append(Zm) yield Zm
def minimal_strata_hyp(g, rational=False): r""" Return the volume of the hyperelliptic component H^{hyp}(2g-2). The explicit formula appears in section 6.5 of [CheMoeSauZag20]_. EXAMPLES:: sage: from surface_dynamics.flat_surfaces.masur_veech_volumes import minimal_strata_hyp sage: minimal_strata_hyp(2) 1/120*pi^4 sage: minimal_strata_hyp(4) 1/580608*pi^8 sage: minimal_strata_hyp(10) 1/137733277917118464000*pi^20 sage: minimal_strata_hyp(10, rational=True) 668525/10499279483305984 """ if rational: return (-1)**(g+1) * 4 * factorial(2*g) / ( (2*g-1)*2*g*(2*g+1) * 2**(4*g-2) * bernoulli(2*g) * factorial(g-1)**2 ) else: return 2*pi**(2*g) / ( (2*g-1)*2*g*(2*g+1) * 2**(2*g-2) * factorial(g-1)**2 )