Modular Functions and their Action

Some Modular Functions and their Actions

This file implements (the numerical evaluation of) the modular functions

  • \(\gamma_2\) – the cube root of the \(j\)-invariant satisfying \(\gamma_2(i) = 12\), which is a modular function of level \(3\);

  • \(\mathfrak{f}\) – Weber’s modular \(\mathfrak{f}\) function of level \(48\);

  • \(\mathfrak{f_1}\) – Weber’s modular \(\mathfrak{f_1}\) function of level \(48\);

  • \(\mathfrak{f_2}\) – Weber’s modular \(\mathfrak{f_2}\) function of level \(48\).

We also implement functions printing the action of \(GL_2(\ZZ/3\ZZ)\) on \(\gamma_2\) and the action of \(GL_2(\ZZ/48\ZZ)\) on \(\mathfrak{f}\) and \(\mathfrak{f_2}\).

REFERENCES:

[Her2021] Mathé Hertogh, Computing with adèles and idèles, master’s thesis, Leiden University, 2021.

This file is part of the master’s thesis [Her2021]. See Chapter 9 for context on the utility of these functions, in particular Section 9.3.4.

AUTHORS:

  • Mathé Hertogh (2021-07): initial version based on [Her2021]

adeles.modular.ST_factor(A, return_homomorphism=False)

Factor \(A \in SL_2(\ZZ/N\ZZ)\) into a product of the standard generators \(S\) and \(T\)

Here we have \(S = (0, -1; 1, 0)\) and \(T = (1, 1; 0, 1)\). Together they generate \(SL_2(\ZZ)\) and hence also \(SL_2(\ZZ/N\ZZ)\) for any integer \(N\).

INPUT:

  • A – a matrix in \(SL_2(\ZZ/N\ZZ)\) for some integer \(N\)

  • return_homomorphism – boolean (default: False); whether or not to return the homomorphism \(f\) described below as well

OUPUT:

An element of the free multiplicative group G generated by \(S\) and \(T\) which is mapped to A by the homomorphism \(f: G \to SL_2(\ZZ/N\ZZ)\) that maps S to (0, -1; 1, 0) and T to (1, 1; 0, 1).

If return_homomorphism is True, also returns \(f\).

EXAMPLES:

sage: G = SL(2, Zmod(10))
sage: A = G([7, 5, 8, 3]); A
[7 5]
[8 3]
sage: STs, f = ST_factor(A, True); STs
T^7*(T*(S^3*T^-1*S)^2)^2
sage: STs.parent()
Free Group on generators {S, T}
sage: f
Group morphism:
  From: Free Group on generators {S, T}
  To:   Special Linear Group of degree 2 over Ring of integers modulo 10
sage: f(STs) == A
True

TESTS:

sage: A = G.random_element()
sage: STs, f = ST_factor(A, True)
sage: f(STs) == A
True
adeles.modular.apply_fractional_linear_transformation(M, tau)

Apply the fractional linear transformation given by M to tau

INPUT:

  • M – a matrix in \(GL_2(\QQ)\) with positive determinant

  • tau – a non-zero field element

OUTPUT:

Writing M = (a, b; c, d), return the element (a*tau+b)/(c*tau+d).

EXAMPLES:

sage: M = matrix([[1, 0], [0, 2]])
sage: apply_fractional_linear_transformation(M, I)
1/2*I
sage: N = matrix([[1, 2], [3, 4]])
sage: apply_fractional_linear_transformation(N, I)
-2/25*I + 11/25
adeles.modular.gamma_2(x, prec=53)

Evaluate the modular function \(\gamma_2\) of level \(3\) in x

The function \(\gamma_2\) is the cube root of the \(j\)-invariant satisfying \(\gamma_2(i) = 12\). It can be given in terms of Weber’s \(f\) function (cf. weber_f()) as follows, for \(z \in \CC\) with \(Im(z)>0\):

\[\gamma_2(z) = (f(z)^{24} - 16) / f(z)^8.\]

INPUT:

  • x – complex point in the upper half plane

  • prec – positive integer (default: 53); number of bits of precision to use

OUTPUT:

The value \(\gamma_2(x)\) as an element of ComplexField(prec).

EXAMPLES:

sage: gamma_2(I)
12.0000000000000 + 6.72179444308389e-15*I
sage: gamma_2(1+I, prec=20)
-6.0000 - 10.392*I
sage: gamma_2(-1.2345+10*I, prec=100)
-1.0590687206704318964160589464e9 + 6.5818683636617232191130875508e8*I
adeles.modular.print_action_on_gamma_2(B)

Print the action of \(B \in GL_2(\ZZ/3\ZZ)\) on the function \(\gamma_2\)

See gamma_2() for information on the modular function \(\gamma_2\) of level \(3\).

INPUT:

  • B – a \(GL_2(\ZZ/3\ZZ)\)-matrix

ALGORITHM:

We factor \(B\) as \(B = (1, 0; 0, d) \cdot U\) where with \(d = \det(B)\) and \(U \in SL_2(\ZZ)\). Next we write \(U\) on the standard generators \(S = (0, -1; 1, 0)\) and \(T = (1, 1; 0, 1)\) of \(SL_2(\ZZ)\). Then we use the fact that \((\ZZ/3\ZZ)^*\) and \(S\) act trivially on \(\gamma_2\), while \(T\) acts as multiplication by \(\zeta_3 = \exp(2 \pi i/3)\).

EXAMPLES:

sage: S = matrix(Zmod(3), [[0, -1], [-1, 0]])
sage: print_action_on_gamma_2(S)
  gamma_2 ]--> gamma_2
sage: T = matrix(Zmod(3), [[1, 1], [0, 1]])
sage: print_action_on_gamma_2(T)
  gamma_2 ]--> zeta_3^2 * gamma_2
sage: B = matrix(Zmod(3), [[0, 1], [1, 2]])
sage: print_action_on_gamma_2(B)
  gamma_2 ]--> zeta_3 * gamma_2

TESTS:

sage: B = matrix(Zmod(3), [[1, 1], [2, 2]])
sage: print_action_on_gamma_2(B)
Traceback (most recent call last):
...
ValueError: B does not lie in GL_2(ZZ/48ZZ)
adeles.modular.print_action_on_weber_f(B)

Print the action of \(B \in GL_2(\ZZ/48\ZZ)\) on Weber’s \(f\) function

See weber_f() for information on Weber’s \(f\) function.

INPUT:

  • B – a \(GL_2(\ZZ/48\ZZ)\)-matrix

ALGORITHM:

We factor \(B\) as \(B = (1, 0; 0, d) \cdot U\) where with \(d = \det(B)\) and \(U \in SL_2(\ZZ)\). Next we write \(U\) on the standard generators \(S = (0, -1; 1, 0)\) and \(T = (1, 1; 0, 1)\) of \(SL_2(\ZZ)\). Then we use the following (hard-coded) knowledge.

Writing \(\zeta_{48} = exp(2 \pi i/48)\), the generators \(S\) and \(T\) act as follows on \(\QQ(\zeta_{48}, f, f_1, f_2)\):

  • \(S: (f, f_1, f_2) \mapsto (f, f_2, f_1)\);

  • \(T: (f, f_1, f_2) \mapsto (\zeta_{48}^{-1} f_1, \zeta_{48}^{-1} f, \zeta_{48}^2 f_2)\).

and \((\ZZ/48\ZZ)^*\) acts trivially on \(f\).

EXAMPLES:

sage: S = matrix(Zmod(48), [[0, -1], [-1, 0]])
sage: print_action_on_weber_f(S)
  f       ]--> f
sage: T = matrix(Zmod(48), [[1, 1], [0, 1]])
sage: print_action_on_weber_f(T)
  f       ]--> zeta48^-1*f1
sage: B = matrix(Zmod(48), [[-1, 4], [3, 7]])
sage: print_action_on_weber_f(B)
  f       ]--> zeta48^-23*f2

TESTS:

sage: B = matrix(Zmod(48), [[1, 0], [0, 2]])
sage: print_action_on_weber_f(B)
Traceback (most recent call last):
...
ValueError: B does not lie in GL_2(ZZ/48ZZ)
adeles.modular.print_action_on_weber_f2(B)

Print the action of \(B \in GL_2(\ZZ/48\ZZ)\) on Weber’s \(f_2\) function

See weber_f2() for information on Weber’s \(f_2\) function.

INPUT:

  • B – a \(GL_2(\ZZ/48\ZZ)\)-matrix

ALGORITHM:

We factor \(B\) as \(B = (1, 0; 0, d) \cdot U\) where with \(d = \det(B)\) and \(U \in SL_2(\ZZ)\). Next we write \(U\) on the standard generators \(S = (0, -1; 1, 0)\) and \(T = (1, 1; 0, 1)\) of \(SL_2(\ZZ)\). Then we use the following (hard-coded) knowledge.

Writing \(\zeta_{48} = exp(2 \pi i/48)\), the generators \(S\) and \(T\) act as follows on \(\QQ(\zeta_{48}, f, f_1, f_2)\):

  • \(S: (f, f_1, f_2) \mapsto (f, f_2, f_1)\);

  • \(T: (f, f_1, f_2) \mapsto (\zeta_{48}^{-1} f_1, \zeta_{48}^{-1} f, \zeta_{48}^2 f_2)\).

and the action of \((\ZZ/48\ZZ)^*\) is given by \(f_2^d = -f_2\) for \(d \equiv 3, 5 \mod 8\) and \(f_2\) is invariant under all other \(d \in (\ZZ/48\ZZ)^*\).

EXAMPLES:

sage: S = matrix(Zmod(48), [[0, -1], [-1, 0]])
sage: print_action_on_weber_f2(S)
  f2    ]--> f1
sage: T = matrix(Zmod(48), [[1, 1], [0, 1]])
sage: print_action_on_weber_f2(T)
  f2    ]--> zeta48^2*f2
sage: B = matrix(Zmod(48), [[8, 3], [-33, 5]])
sage: print_action_on_weber_f2(B)
  f2    ]--> zeta48^21*f

TESTS:

sage: B = matrix(Zmod(48), [[10, 33], [-21, 9]])
sage: print_action_on_weber_f2(B)
Traceback (most recent call last):
...
ValueError: B does not lie in GL_2(ZZ/48ZZ)
adeles.modular.weber_f(x, prec=53)

Evaluate Weber’s \(f\) function in x

Weber’s \(f\) function is a modular function of level 48 given for \(z \in \CC\) with \(Im(z)>0\) by

\[f(z) = \zeta_{48}^{-1} \eta((z+1)/2) / \eta(z)\]

where \(\zeta_{48} = \exp(2 \pi i/48)\) and \(\eta\) denotes the Dedekind \(\eta\)-function (cf. sage.misc.functional.eta()).

INPUT:

  • x – complex point in the upper half plane

  • prec – positive integer (default: 53); number of bits of precision to use

OUTPUT:

The value \(f(x)\) as an element of ComplexField(prec).

EXAMPLES:

sage: weber_f(I)
1.18920711500272 + 2.77555756156289e-17*I
sage: weber_f(1+I, prec=20)
1.0812 - 0.14234*I
sage: weber_f(-1.2345+10*I, prec=100)
3.6542217197057340054214271813 + 0.59570067343661179281710012847*I
adeles.modular.weber_f1(x, prec=53)

Evaluate Weber’s \(f_1\) function in x

Weber’s \(f_1\) function is a modular function of level 48 given for \(z \in \CC\) with \(Im(z)>0\) by

\[f_1(z) = \eta(x/2) / \eta(x)\]

where \(\eta\) denotes the Dedekind \(\eta\)-function (cf. sage.misc.functional.eta()).

INPUT:

  • x – complex point in the upper half plane

  • prec – positive integer (default: 53); number of bits of precision to use

OUTPUT:

The value \(f_1(x)\) as an element of ComplexField(prec).

EXAMPLES:

sage: weber_f1(I)
1.09050773266526
sage: weber_f1(1+I, prec=20)
1.1790 - 0.15522*I
sage: weber_f1(-1.2345+10*I, prec=100)
3.6542217197058751251562566155 + 0.59570067343652031920472325046*I
adeles.modular.weber_f2(x, prec=53)

Evaluate Weber’s \(f_2\) function in x

Weber’s \(f_2\) function is a modular function of level 48 given for \(z \in \CC\) with \(Im(z)>0\) by

\[f_2(x) = \sqrt{2} \eta(2x) / \eta(x)\]

where \(\eta\) denotes the Dedekind \(\eta\)-function (cf. sage.misc.functional.eta()).

INPUT:

  • x – complex point in the upper half plane

  • prec – positive integer (default: 53); number of bits of precision to use

OUTPUT:

The value \(f_2(x)\) as an element of ComplexField(prec).

EXAMPLES:

sage: weber_f2(I)
1.09050773266526
sage: weber_f2(1+I, prec=20)
1.0533 + 0.28224*I
sage: weber_f2(-1.2345+10*I, prec=100)
0.097824329747547433152328660118 - 0.032764790050361566443041641916*I