$ \newcommand{\setC}{\mathbb{C}} \newcommand{\setH}{\mathbb{H}} \newcommand{\setN}{\mathbb{N}} \newcommand{\setQ}{\mathbb{Q}} \newcommand{\setZ}{\mathbb{Z}} \newcommand{\modularOrbit}[1]{\mathcal{O}_{#1}} \newcommand{\qPochhammer}[3][\infty]{\left( #2;#3 \right)_{#1}} $ Via jupytext this file can be shown as a jupyter notebook.
)cd ..
)read input/jfricas-test-support.input )quiet
The current FriCAS default directory is /home/hemmecke/backup/git/qeta All user variables and function definitions have been cleared. All )browse facility databases have been cleared. Internally cached functions and constructors have been cleared. )clear completely is finished. The current FriCAS default directory is /home/hemmecke/backup/git/qeta/tmp
)set output formatted off
)set output algebra on
QEta Tutorial¶
This file contains a short tutorial of some of the features of QEta.
Follow the instructions on the QEta website in order to install it.
This notebook itself is available in a text form as
QEtaTutorial.input-test.
You just have to rename the file extension to .input
in order to run it through the computer algebra system
FriCAS.
If you have installed FriCAS, together with jFriCAS and JupyText (see the FriCAS installation guide), you can load and run this QEtaTutorial inside a Jupyther notebook.
In order to test the commands appearing here,
the tutorial contains a number of commands like
assertTrue
or assertEquals
, that can be run
automatically as a testsuite check.
Init¶
-------------------------------------------------------------------
--setup
-------------------------------------------------------------------
To work with QEta, you first have to compile and load it.
Compilation must only be done once from a terminal, inside
the directory where the QEta source code resides.
In the following we assume that the QEta source code lives
in the fricas/qeta
subdirectory of your home directory.
cd $HOME/fricas/qeta
make compile-spad
That will compile everything into fricas/qeta/tmp
.
To load QEta, do the following inside a Jupyter notebook (running the FriCAS kernel).
)cd
)cd fricas/qeta/tmp
)set message time off
)set message type off
)read projectlibs.input )quiet
)read qetamacros.input )quiet
If you want the output look nicer in the Jupyter notebook, then issue the following commands.
)set output algebra off
setFormat!(FormatMathJax)$JFriCASSupport
In qetamacros.input quite a number of macros are defined that make working with QEta functions a bit simpler. Inside this notebook, we use the abbreviations defined there.
C ==> QQ
RKI ==> QEtaRamanujanKolbergIdentity(C)
oo ==> infinity()$Cusp
)set stream calc 2
-------------------------------------------------------------------
--endsetup
-------------------------------------------------------------------
The following cell should only be evaluated, if you want the traditional 2D ASCII output of FriCAS.
Ramanujan congruences¶
-------------------------------------------------------------------
--test:RamanujanCongruences
-------------------------------------------------------------------
Ramanujan discovered that \begin{align} p(5n+4) &\equiv 0 \pmod{5}\label{eq:p5}\\ p(7n+5) &\equiv 0 \pmod{7}\label{eq:p7}\\ p(11n+6) &\equiv 0 \pmod{11}\label{eq:p11} \end{align} for all natural numbers $n\in\setN$ where $p(n)$ denotes the number of partitions of $n$.
In QEta a sequence $(a(n))_{n\geq0}$ given by its generating series as \begin{align*} \sum_{n=0}^\infty a(n)q^n &= \prod_{\delta|M} \qPochhammer{q^\delta}{q^\delta}^{r_\delta} \end{align*} can be specified by the $(\delta, r_\delta)$ pairs.
For the partition function we have $M=1$ and $r_1=-1$, so we specify the following.
mm := 1; rspec := eqSPEC [[1,-1]]
In our treatise we always use that $q=\exp(2\pi i \tau)$.
$p(5n+4) \equiv 0 \pmod{5}$¶
We want an expansion in terms of eta-functions $\eta(\tau)$ and $\eta(5\tau)$, so we use the following indices.
idxs := [[1],[5]];
We compute an identities for \begin{gather*} \sum_{n=0}^\infty a(mn+k)q^n \end{gather*} in terms of eta-quotients. This identity is an identity of modular functions for $\Gamma_0(5)$.
The function to call is findIdM0
as specified in
qetamacros.input
. It takes 5 parameters
- the $N$ from $\Gamma_0(N)$,
- the specification of the generating series
rspec
, - the dissection factor $m$,
- the dissection offset $k$,
- the indices
idxs
for the eta-functions to be used.
The variable id
will contain all relevant data, but
this data structure is usually rather big and uninteresting
as a whole, so we add a semicolon at the end of the command
in order to prevent its printing.
id := findIdM0(5, rspec, 5, 4, idxs);
-- numOfGaps:=[0, 0]
The actual relation can be shown by the following command.
pretty(id, formatExpanded() + formatAsExpression())
Note that findIdM0
is a macro.
It is refers to a function findIdentity
from
the package QEtaRamanujanKolberg(C,QMOD0)
.
The package implements Radu's algorithm
genericaly over various coefficient domains
and for $\Gamma_0(M)$ and $\Gamma_1(M)$ which
have to be given as concrete arguments to QEtaRamanujanKolberg
.
Usage of the macro findIdM0
shortens the
otherwise quite lengthy function call.
Note that the 0 in the name corresponds to $\Gamma_0(N)$.
$p(7n+5) \equiv 0 \pmod{7}$¶
We can do similar steps for the Ramanujan congruence modulo 7.
idxs := [[1],[7]];
id := findIdM0(7, rspec, 7, 5, idxs);
pretty(id, formatExpanded() + formatAsExpression())
-- == z:=[zinhom=[[1]], zhom=[], zfree=[]] -- numOfGaps:=[0, 0]
The variable id
, in fact, contains all the data to show
the identity in different formats.
For example, adding the formatAsNonModular()
option, brings the
cofactor of the generating function to the right-hand side.
pretty(id, formatExpanded() + formatAsExpression() + formatAsNonModular())
The option formatWithQFactor()
shows $q$-Pochhammer symbols
instead of Dedekind eta-functions.
pretty(id, formatExpanded() + formatAsExpression() + formatAsNonModular() _
+ formatWithQFactor())
Since this might sometimes be a too lengthy expression, we can
remove the formatAsExpression()
option and show the identity with
variables where $u_\delta$ stands for
$\qPochhammer{q^\delta}{q^\delta}$.
pretty(id, formatExpanded() + formatAsNonModular() + formatWithQFactor())
pretty(id, formatExpanded() + formatAsNonModular() + formatWithQFactor()_
+ formatWithSubscript())
Of course, any combination of these options work.
pretty(id, formatExpanded() + formatAsNonModular() + formatWithSubscript())
In the above formula, $E_\delta$ stands for $\eta(\delta\tau)$.
If you need the output for further computation in another system, you can temporarily switch to one-dimensional output.
setFormat!(Format1D)$JFriCASSupport
pretty(id, formatExpanded() + formatAsNonModular())
setDefault!(defaultPrologue$Format1D,defaultEpilogue$Format1D)$Formatter(Format1D);
setFormat!(FormatMathJax)$JFriCASSupport
sum(a(7*n+5)*q^n, n=0 .. %Infinity)=7*q^(-17/24)*E7^3/E1^4+49*q^(-17/24)*E7^7/E1^8
Or you can define a macro and then use it.
print1D x ==> display((x::OutputForm)::Formatter(Format1D))
print1D pretty(id, formatExpanded() + formatAsNonModular())
sum(a(7*n+5)*q^n, n=0 .. %Infinity)=7*q^(-17/24)*E7^3/E1^4+49*q^(-17/24)*E7^7/E1^8
$p(11n+6) \equiv 0 \pmod{11}$ (with $\Gamma_0(22)$)¶
The modulo 11 case is a bit more complicated, since for $\Gamma_0(11)$ we cannot find an identity
idxs := [[1],[11]];
id := findIdM0(11, rspec, 11, 6, idxs);
-- == z:=[zinhom=[[0]], zhom=[], zfree=[]] -- numOfGaps:=[120, 1]
This fact is encoded in QEta by returning the trivial identity $0=0$.
pretty(id, formatWithQFactor() + formatExpanded() + formatAsNonModular()_
+ formatWithSubscript())
assertEquals(identityPolynomial id, 0);
If one needs this in another procedure, one can ask for the
idenityPolynomial(id)
. If this is 0, then there is no identity
for the respective parameter, i.e. here for $\Gamma_0(11)$
and in terms of eta-functions $\eta(\tau)$ and $\eta(11\tau)$.
zero? identityPolynomial id
We can, however, resort to level 22 and then an identity can be found.
idxs := [[1],[2],[11],[22]];
id := findIdM0(22, rspec, 11, 6, idxs);
-- == z:=[zinhom=[], zhom=[], zfree=[]] -- >= z:=[zinhom=[[4, -1, 1], [5, -1, 2], [4, -1, 2]], zhom=[[3, -1, 0], [4, -1, 1], [1, -1, 1], [2, -1, 1], [3, -1, 1], [0, -1, 1], [2, 0, 1]], zfree=[]] -- numOfGaps:=[216, 2] -- numOfGaps:=[162, 2] -- numOfGaps:=[108, 2] -- numOfGaps:=[55, 2] -- numOfGaps:=[55, 2] -- numOfGaps:=[2, 2]
pretty(id, formatWithQFactor() + formatExpanded() + formatAsNonModular()_
+ formatAsExpression())
Even though there are denominators of 4 and 8 in this representation, it clearly shows that the left-hand side is divisible by 11.
In fact, the original generating series multiplied by some cofactor gives a modular function for $\Gamma_0(22)$, (left-hand side).
It can be represented by a linear combination of eta-quotients with coefficients in $\setQ$, (right-hand side).
pretty(id, formatExpanded() + formatWithSubscript())
In fact,
Radu's original algorithm
AB
, as well as
the
samba
algorithm
(which is implemented in QEta)
return a representation as a linear combination of
finitely many eta-quotients over $\setQ[t]$ where $t$
itself is an eta-quotient.
pretty(id, formatWithSubscript())
From the identity polynomial, we see that $p(11n+6)$ is divisible by 11, i.e. all terms not involving $F$ are divisible by 11.
Here $F$ corresponds to the left-hand side from above.
11^4*identityPolynomial(id)=0
$M_1$ corresponds to the $t$ and the $M_i$ are eta-quotients with the following specifications.
mspecs := monoidSpecifications id
So $M_1=t$ stands for $\frac{\eta(2\tau)^8 \eta(11\tau)^4}{\eta(\tau)^4\eta(22\tau)^8}$, etc. It can be shown easily by functions from QEta.
[etaQuotient(x, varEta) for x in mspecs]
[qEtaQuotient(x, varPochhammer) for x in mspecs]
QEta also contains a special type, namely QEtaSpecificationRing, that enables to deal with linear combinations of eta-quotients. It can be used to print the eta-quotients as above.
srs := [x::QEtaSpecificationRing(ZZ) for x in mspecs];
[pretty(x, formatWithSubscript()) for x in srs]
[pretty(x, formatWithQFactor()+formatWithSubscript()) for x in srs]
$p(11n+6) \equiv 0 \pmod{11}$ (with $\Gamma_1(11)$)¶
QEta allows to find an identity for the generating function of $p(11n+6)$ in term of generalized eta-quotients by an implementation of ideas of Chen, Du, and Zhao. This also yields a witness identity for the divisibility by 11.
idxs := [[1],[11],[11,1],[11,2],[11,3],[11,4]];
id := findIdM1(11, rspec, 11, 6, idxs);
pretty(id, formatWithQFactor() + formatExpanded() + formatAsNonModular()_
+ formatAsExpression())
-- == z:=[zinhom=[[2, 2, -7, 5, 2]], zhom=[], zfree=[]] -- numOfGaps:=[75, 1] -- numOfGaps:=[75, 1] -- numOfGaps:=[1, 1]
identityPolynomial id
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
Kolberg identity for $p(5n+1)$¶
-------------------------------------------------------------------
--test:KolbergIdentity
-------------------------------------------------------------------
Kolberg (1957) found an identity for the generating function of $p(5n+1)$. That, however, also involves the generating function for $p(5n+2)$.
mm := 1; rspec := eqSPEC [[1,-1]];
idxs := [[1],[5]];
id := findIdM0(5, rspec, 5, 1, idxs);
pretty(id, formatWithQFactor() + formatExpanded() + formatAsNonModular()_
+ formatAsExpression())
-- == z:=[zinhom=[[1]], zhom=[], zfree=[]] -- numOfGaps:=[0, 0]
The above identity is based on transformations with respect to $\Gamma_0(5)$. In such transformations $\sum_{n=0}^\infty a(5n+1)q^n$ and $\sum_{n=0}^\infty a(5n+2)q^n$ cannot be considered separately. Since they lie in the same orbit with respect to $\Gamma_0(5)$, only their product can be turned into a modular function for $\Gamma_0(5)$.
If we consider $\Gamma_1(5)$ and allow generalized eta-quotients, we get the following identity.
id1 := findIdM1(5, rspec, 5, 1, [[1],[5],[5,1]]);
pretty(id1, formatWithQFactor() + formatExpanded() + formatAsNonModular()_
+ formatAsExpression())
-- == z:=[zinhom=[[1, 0]], zhom=[], zfree=[]] -- numOfGaps:=[0, 0]
Let us take this example for an explanation of what the
variable id
actually contains.
id
pretty(id,0)
definingSpecification
describes the generating function
for $(a(n))_{n\ge0}$.
multiplier
is the factor $m$ of the dissection $a(m n + k)$.
orbit
gives the list of offsets $k'$ that must be
considered together with the initially given offset $l$.
coSpecification
describes the (generalized) eta-quotient
that must be multiplied to the dissected generating series
in order to arrive at a modular function.
coefficient
is the constant coefficient of the left hand side.
QEta does not generally divide by this coefficient, since
QEta can work with coefficient rings that are not fields.
monoidSpecifications
describe the eta-quotients that can
potentially appear of the right-hand side of the identity,
where the first element can appear in any non-negative power
while the others may only appear linearly.
identityPolynomial
is a condensed version of the identity
where $F$ stands for the modular function on the left-hand side
and the $M_i$ are the eta-quotients given by monoidSpecifications
.
alphaInfinity
gives the order of $q$ of the left-hand side
when expanded as a $q$-series while alphaOrbitInfinity
only
gives the part of the $q$ exponent that is (technically) connected
to the orbit product of the dissected generating series.
In the output of pretty
the symbol t
stands for M1
.
We can extract that information also individually from
the id
variable.
coSpecification id
definingSpecification id
multiplier id
orbit id
monoidSpecifications id
identityPolynomial id
coefficient id
alphaInfinity id
alphaOrbitInfinity id
There are more function available that you can apply
to the id
variable.
For example, we can transform the identity into an equation of FriCAS expressions that can then be manipulated further.
)set message type on
eexpr1 := equationX(id, 'p)
uexpr1 := qequationX(id, 'p)
)set message type off
We can do the same for the generating series of $p(5n+3)$.
id3 := findIdM0(5, rspec, 5, 3, idxs);
eexpr3 := equationX(id3, 'p)
uexpr3 := qequationX(id3, 'p)
-- == z:=[zinhom=[[1]], zhom=[], zfree=[]] -- numOfGaps:=[0, 0]
From looking at the right-hand side we easily see that we can eliminate the $M1$ variable.
eq1 := 25*q*u[5]^10/u[1]^12 * (3*uexpr1 - 2*uexpr3)
Let us compare this with the identity for the generating series of $p(5n+4)$.
id4 := findIdM0(5, rspec, 5, 4, idxs);
uexpr4 := qequationX(id4, 'p)
-- numOfGaps:=[0, 0]
With a few manipulation we find an identity that already appears as equation (4.4) in Kolberg (1957).
eq1 - q*((u[5]^5/u[1]^6)*uexpr4)^2
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
Relations among 5-dissections of $p(n)$¶
-------------------------------------------------------------------
--test:time140-RelationsAmong5Dissections
-------------------------------------------------------------------
Setting up¶
The above relation can also be found automatically by QEta. The idea is to find a relation for the involved generating functions in terms of (generalized) eta-quotients.
Whereas the relation given in the previous section can be computed while working with ordinary Dedekind eta-functions, for other relations of this type, we must employ generalized eta-functions and their transformations with respect to $\Gamma_1(N)$.
Let us first setup a few helpers, i.e. compute
the identities for the generating functions of
$p(5n+k)$ into the list ids
.
idxs := [[1],[5],[5,1]]; rspec := eqSPEC [[1,-1]];
id := findIdM1(5, idxs, rspec, 5, 0, idxs);
ids := [findIdM1(5, idxs, rspec, 5, k, id) for k in 0..4];
-- == z:=[zinhom=[[1, 0]], zhom=[], zfree=[]] -- numOfGaps:=[0, 0] -- == z:=[zinhom=[[1, 0]], zhom=[], zfree=[]] -- == z:=[zinhom=[[1, 0]], zhom=[], zfree=[]] -- == z:=[zinhom=[[1, 0]], zhom=[], zfree=[]] -- == z:=[zinhom=[[1, 0]], zhom=[], zfree=[]]
Generators for relations ideal¶
sspec:=coSpecification(ids.1)
mon := f * monomial(sspec, "E", "Y")
ipol := inv coefficient id * identityPolynomial id - 'F::Pol(ZZ)
QEtaIdeal ==> QEtaIdealHemmecke
QI1 ==> QEtaIdeal(QMOD1)
idpol(id: RKI, f: Symbol): Pol ZZ == (_
sspec := coSpecification id;_
mon: Pol(ZZ) := f * monomial(sspec, "E", "Y");_
ipol: Pol(ZZ) := (inv coefficient id * identityPolynomial id - 'F)::Pol(ZZ);_
mon+ipol)
Function declaration idpol : (QEtaRamanujanKolbergIdentity(Fraction(Integer)) , Symbol) -> Polynomial(Integer) has been added to workspace.
In the following relations we can replace $M1$ by its corresponding eta-quotient.
[equationX(ids.k,'p) for k in 1..5]
We have
mspecs := monoidSpecifications ids.1
[etaQuotient(x, varEta) for x in mspecs]
Then we introduce $Y_k$ to replace $1/E_k$ and replace the (fractional) $q$-factor together with the generating series for $p(5n+k)$ by the variable $f_k$.
fs := [concat("f",string(k-1))::Symbol_
= q^alphaOrbitInfinity(ids.k) * orbitProductX(ids.k,'p)_
for k in 1..5]
With that substitution and bringing everything to one side. we obtain the following set of polynomials that represent the relations among the $f_k$ and eta-functions.
fsyms := [lhs x for x in fs];
mps := [idpol(id,f) for id in ids for f in fsyms]
Compiling function idpol with type (QEtaRamanujanKolbergIdentity(Fraction( Integer)), Symbol) -> Polynomial(Integer)
mspecs := monoidSpecifications first ids;
eqrels := etaLaurentIdealGenerators(idxs, mspecs, mps)$QI1
assertEquals(eqrels, [_
E1*Y1-1, E5*Y5-1, E5_1*Y5_1-1,_
E1^7*Y5^6*Y5_1^2*f0 - E1^5*Y5^5*Y5_1^10 + 3,_
E1^8*Y5^7*Y5_1^4*f1 - E1^5*Y5^5*Y5_1^10 - 2,_
E1^9*Y5^8*Y5_1^6*f2 - 2*E1^5*Y5^5*Y5_1^10 + 1,_
E1^10*Y5^9*Y5_1^8*f3 - 3*E1^5*Y5^5*Y5_1^10 - 1,_
E1^6*Y5^5*f4 - 5])
Eliminate generalized eta-quotients¶
The following computation takes about 200 sec and eliminates the variables $E_k$ and $Y_k$ so that only the relations among the $f_k$ survive.
)set message time on
algrels := algebraicRelations(idxs, eqrels, char "f")$QI1;
)set message time off
assertEquals(algrels, [_
10*f0^2*f3^2-9*f0^2*f2*f4-9*f1*f3^2*f4+4*f0*f3*f4^2+4*f4^4,_
5*f0*f1*f3-3*f0^2*f4-6*f2*f3*f4+4*f1*f4^2,_
5*f0*f2*f3-6*f0*f1*f4-3*f3^2*f4+4*f2*f4^2,_
2*f1^2-f0*f2-f3*f4, 3*f1*f2-2*f0*f3-f4^2, 2*f2^2-f1*f3-f0*f4])
-- numOfGaps:=[0, -1] -- numOfGaps:=[0, -1] -- TIME:=0.49
Selected results¶
Among the relations is relation (4.4) of a paper of Kolberg (1957) that we have found manually in the previous section.
algrels.5 = 0
Shown as a relation among the generating series, it is as follows.
simplify(eval(algrels.5, fs)) * q^(-7/12) = 0
The following identities involve other pairs. See congruence at bottom of page 86 in Kolberg (1957).
simplify(eval(algrels.4, fs)) * q^(-23/60) = 0
simplify(eval(algrels.6, fs)) * q^(-47/60) = 0
simplify(eval(algrels.3, fs)) * q^(-39/40) = 0
simplify(eval(algrels.2, fs)) * q^(-31/40) = 0
simplify(eval(algrels.1, fs)) * q^(-7/6) = 0
Altogether, algrels
is a Gröbner basis for the
ideal of all relations among these generating series.
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
Check Eta-quotient identities¶
-------------------------------------------------------------------
--test:CheckEtaQuotientIdentity
-------------------------------------------------------------------
Let us check the validity of an eta-quotient identity from Lemma 13 of "Elementary Proofs of Congruences for Pond and Pend Partitions" by James Sellers, namely \begin{gather*} \frac{f_3^3}{f_1} - q \frac{f_{12}^3}{f_4} = \frac{f_4^3 f_6^2}{f_2^2 f_{12}}, \end{gather*} which appears as equation (22.7.5) in "The Power of q" by Michael D. Hirschhorn.
In eta-uotients. this equation looks as follows: \begin{gather*} \frac{E_3^3}{E_1} - \frac{E_{12}^3}{E_4} = \frac{E_4^3 E_6^2}{E_2^2 E_{12}}. \end{gather*}
We can enter it in QEta via the QEtaSpecificationRing,
nn := 12
lemma13 := f3^3/f1 - q*f12^3/f4 - f4^3*f6^2/(f2^2*f12);
lemma13eta := fromQPochhammerToEta(nn, lemma13, "f", "E").frf
specpol := lemma13eta::SPECR(ZZ)
As can be seen from the following output, the expression in eta-functions is actually only the same as the initial expression up to a factor of $q^\frac{-1}{3}$.
pretty(specpol, formatAsExpression() + formatWithQFactor())
Internally, QEta always works with eta-functions, but to beautify
the output, a third parameter can be given to the pretty
function
that specifies an extra multiplication by a $q$ power.
Note that QEta abbreviates the $q$-Pochhammer symbol $(q^k;q^k)$ by the variable $u_k$
pretty(specpol, formatWithQFactor() + formatWithSubscript(), -1/3)
That this expression corresponds to the zero function can be shown in two ways.
- We find an eta-quotient factor that after multiplying with it turns each term of the expression into a modular function for $\Gamma_0(12)$ with only a pole at $\infty$. If all the respective $q$-expansion then sum to a $q$-series of positive order, it proves that that this series is identically 0.
- Expand each eta-quotient in the expression into a vector of $q$-series (one for each cusp of $\Gamma_0(12)$) and sum these vectors. If that give a vector whose entries have all positive orders, it proves that the expression is identically 0.
Below we show both ways.
First method¶
Let us start with computing a eta-quotient that (after multiplication)
turns each term of the expression into a modular function with only
a pole at $\infty$.
The QEta functionn etaCofactorInfinity
even works with the
non-modular eta-quotients of the original expression.
specs := [leadingSupport x for x in monomials specpol];
idxs := etaFunctionIndices(nn);
sspec := etaCofactorInfinity(nn,idxs,specs)$QEtaModularPackage(QMOD0)
-- == z:=[zinhom=[[-2, -2, 5, -2, -1]], zhom=[], zfree=[]]
sspecpol := sspec * specpol; pretty(sspecpol, formatWithSubscript())
The corresponding series of each term are given below.
sers := [specM0A1(ZZ)(leadingSupport x) for x in monomials sspecpol]
coefs := [leadingCoefficient(x) for x in monomials sspecpol]
Summing them accordingly, gives indeed 0.
reduce(+, [c*s for c in coefs for s in sers])
Second method¶
Unfortunately, the original expression does not correspond to a modular function for $\Gamma_0(12)$.
modularGamma0? specpol
It can be turned into one by dividing by one of the involved eta-quotients.
invE33E1 := inv leadingSupport last monomials specpol
mspecpol := invE33E1 * specpol; pretty(mspecpol, formatWithSubscript())
modularGamma0? mspecpol
Let us determine the orders at each of the cusps for each of the terms.
cusps()$GAMMA0(nn)
ys := [specYM0EQ leadingSupport m for m in monomials mspecpol];
[orders y for y in ys]
Obviously there are poles at the cusp $\frac{1}{3}$.
In the most general case the expansion involve an extension of
the coefficient ring by a certain root of unity. The order of
the root of unity can be determined from the datastructure stored
in the list ys
. See also Section "Expansion at cusps" below.
xiord := lcm [minimalRootOfUnity y for y in ys]
Only a second root of unity, i.e. -1 is needed. We can do the expansion over rational numbers. Nevertheless, we demonstrate here the general case.
C ==> QQ
EXTENDEDCOEFFICIENTRING(C, xiord, CX, xi);
trfs := transformationMatrices(first ys)
)read convenience.input )quiet
We compute the expansions at each cusps either from the
symbolic datastructure stored in the list ys
or directly
from the respective terms.
vs := [expandM0An(CX)(y) for y in ys]
[specM0An(CX)(leadingSupport x) for x in monomials mspecpol]
cs := [leadingCoefficient x for x in monomials mspecpol]
Indeed, we get positive orders at all cusps. That proves that we are dealing with the modular function 0.
reduce(+, [c*v for c in cs for v in vs])
Relations among eta-functions¶
QEta can even do more. It can compute a Gröbner basis of all relations among eta-functions of a certain level and then represent the original expression by a linear combination of Gröbner basis elements divided by the common denominator of the original expression.
rf := etaRationalFunction(specpol,"E")
pol := numer rf
We first compute the the monoid basis $\{M_1,\ldots,M_5\}$ of all eta-quotients of $\Gamma_0(12)$ that only have a pole at the cusp $\infty$.
idxs := etaFunctionIndices nn;
mspecs := mSPECSInfM0(nn, idxs);
[etaQuotient(x, varEta) for x in mspecs]
These eta-quotients have the following $q$-expansion.
)set stream calc 4
[specM0A1(QQ)(x) for x in mspecs]
From these expansions the samba algorithm (see “Dancing Samba with Ramanujan Partition Congruences”) is used to compute an algebra basis of $\setQ[M_1,\ldots,M_5]$ where the $M_k$ represent the eta-quotients above.
egens := [specMA1(C,QMOD0) mspec for mspec in mspecs]
msyms: List Symbol := indexedSymbols("M", #mspecs)$QAuxiliaryTools
xgens := [toX1(C, x, sym::Pol(C)) for x in egens for sym in msyms]
gen := genus(nn)$QMOD0
xab := samba(xgens, gen, oneVerboseStep!(1,1,1,1))$QSAMBA(C,X1,QTOPRED)
-- numOfGaps:=[0, 0]
We find, that $\setQ[M_1,\ldots,M_5]=\setQ[M_1]$.
With this information we can express each of the $M_i$ by a polynomial in $M_1$ with rational coefficients. The following polynomials vanish if the $M_i$ are replaced by there respective eta-quotients.
)expose QAuxiliaryTools
eqigens := [integerPrimitivePart(second(reduce(x,xab)$QTOPRED(C,X1))::Pol(QQ))_
for x in rest xgens]
assertEquals(eqigens, [M2 - M1 + 2, M3 - M1 + 3, M4 - M1 + 4, M5 - M1 + 6])
QAuxiliaryTools is already explicitly exposed in frame initial
We can turn the above polynomials on a linear combination of eta-quotients (represented by their specifications.
specpols := [specificationPolynomial(x,"M",mspecs) for x in eqigens];
Theses expressions can be shown nicely.
pretty(specpols.1, formatWithSubscript())
pretty(specpols.1, formatWithQFactor() + formatAsExpression())
There are now two ways to translate the information into polynomials...
[etaPolynomial(x, mspecs) for x in eqigens]
[etaPolynomial(x) for x in specpols]
... or rational functions.
[etaRationalFunction(x, mspecs) for x in eqigens]
[etaRationalFunction(x) for x in specpols]
We take the first representation where the $Y_i$ represent $\frac{1}{E_i}$ and then eliminate the $Y_i$ by the Gröber basis method modulo the relations $E_i Y_1 = 1$. The result is a Gröbner basis (here with respect to a degrevlex order) of the ideal of all relations amont eta-functions.
In QEta the whole process in encoded in the function etaRelation
.
)read projectdir )quiet
basedir := PROJECTDIR "/data/etafiles/Hemmecke/Gamma0"
nn
idxs
erels := etaRelations(nn, idxs, basedir) $ QEtaIdealHemmecke(QMOD0)
We find that the relation from Lemma 13 is (up to a factor of eta-quotients identical to the last-but-one element in the above Gröbner basis of eta-relations of level 12.
dim := #idxs;
syms := indexedSymbols("E", idxs)$QAuxiliaryTools;
D ==> HomogeneousDirectProduct(dim, NN);
E ==> Monomials(dim, NN, D, syms)
R ==> PolynomialRing(ZZ, E)
xnf ==> extendedNormalForm$QEtaGroebner(ZZ, E);
nlemma13eta := numer lemma13eta;
assertEquals(xnf(nlemma13eta, erels, syms, 'F, "G"), G97+F)
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
Ideal of relations among eta-functions¶
-------------------------------------------------------------------
--test:time19-EtaRelations
-------------------------------------------------------------------
With similar ideas as above, we can also compute the ideal of all relations among eta-functions. The corresponding theory is described in “Construction of all Polynomial Relations among Dedekind Eta Functions of Level N”.
In QEta there exists the functions etaRelations
to
do the computation.
idxs := etaFunctionIndices 6;
er := etaRelations(idxs) $ QEtaIdealHemmecke(QMOD0)
-- numOfGaps:=[0, 0] -- TIME:=0.13
For bigger levels $N$ the computation becomes increasingly more involved since it is based on
- computing a monoid basis for the monoid of all eta-quotients with the help of the program 4ti2,
- setting up relations in variables $E_\delta$ and $Y_\delta$ ($\delta$ ranging over all divisors of $N$, and $E_\delta$ and $Y_\delta$ representing $\eta(\delta\tau)$ and $1/\eta(\delta\tau)$, respectively),
- eliminating the $Y_\delta$ variables from the system.
Let us consider the case $N=16$.
We first compute the the monoid basis.
nn := 16
idxs := etaFunctionIndices nn
mspecs := mSPECSInfM0(nn, idxs);
[etaQuotient(x, varEta) for x in mspecs]
These eta-quotients have the following $q$-expansion.
)set stream calc 4
[specM0A1(QQ)(x) for x in mspecs]
From these expansions the samba algorithm (see “Dancing Samba with Ramanujan Partition Congruences”) is used to compute an algebra basis of $\setQ[M_1,\ldots,M_4]$ where the $M_k$ represent the eta-quotients above.
QEtaIdeal ==> QEtaIdealHemmecke
QI0 ==> QEtaIdeal(QMOD0)
eqigens := etaQuotientIdealGenerators(mspecs)$QI0
-- numOfGaps:=[0, 0]
Let the elements in the above list be denoted by $z_1,z_2,z_3$. In terms of the $q$-series we have \begin{gather*} \setQ[M_1,\ldots,M_4] = \{p_0 + p_1 z_1 + p_2 z_2 + p_3 z_3 \mid p_0,p_1,p_2,p_3\in \setQ[M_1] \} \end{gather*}
By substituting the $M_k$ variables with the respective eta-functions $E_\delta$, and their inverses $Y_\delta$, we arrive at the following system.
eligens := etaLaurentIdealGenerators(idxs, mspecs, eqigens)$QI0
Now, we must "only" eliminate the $Y_\delta$ variables. For that we can use the QEta interface to some Gröbner engine.
ysyms := indexedSymbols("Y", idxs)$QAuxiliaryTools;
esyms := indexedSymbols("E", idxs)$QAuxiliaryTools;
We compute the Gröbner basis for that order.
gb := groebnerEliminate(eligens, ysyms, esyms)$QEtaGroebnerBasisTools
-- TIME:=0.76
Clearly, we are not restricted to pure Dedekind eta-functions, but can also consider relations among generalized eta-functions.
For simplicity, let us consider level 5.
idxs := generalizedEtaFunctionIndices 5
ger := etaRelations(idxs) $ QEtaIdealHemmecke(QMOD1);
-- numOfGaps:=[0, -1] -- numOfGaps:=[0, -1] -- TIME:=0.0
Naturally, we find the relation \begin{align*} \eta(\tau) = \eta(5\tau) \, \eta_{5,1}(\tau) \, \eta_{5,2}(\tau) \end{align*} as the last expression in the above list.
If we take the last-but-one polynomial from the above list and divide every term by $E_{5,1}^5 E_{5,2}^5 E_5^6$ we get the following list of terms.
[x/(E5_1*E5_2*E5)^6 for x in monomials(ger(#ger-1))]
[x/(E5_1*E5_2*E5) for x in monomials(ger(#ger))]
By the relation, we have presented before, the last element in the above list is equal to 11.
In fact, we have computed, the relation for the Rogers-Ramanujan continued fraction.
\begin{align*} \frac{1}{R(q)^5} - R(q)^5 = \frac{\eta_{5;2}(\tau)^5}{\eta_{5;1}(\tau)^5} - \frac{\eta_{5;1}(\tau)^5}{\eta_{5;2}(\tau)^5} &= 11 + \frac{\eta(\tau)^6}{\eta(5\tau)^6} %\tag{1.5} \end{align*}
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
Rogers-Ramanujan Continued Fraction¶
Identiity for 5-dissection of $R(q)$¶
-------------------------------------------------------------------
--test:RogersRamanujanContinuedFraction
-------------------------------------------------------------------
Define \begin{align} G(q) &= \sum_{n=0}^\infty \frac{q^{n^2}}{(q;q)_n} = \prod_{n=0}^\infty \frac{1}{(1-q^{5n+1})(1-q^{5n+4})} = \frac{1}{\qPochhammer{q,q^4}{q^5}} \\ H(q) &= \sum_{n=0}^\infty \frac{q^{n(n+1)}}{(q;q)_n} = \prod_{n=0}^\infty \frac{1}{(1-q^{5n+2})(1-q^{5n+3})} = \frac{1}{\qPochhammer{q^2,q^3}{q^5}} \end{align}
and Rogers-Ramanujan continued fraction. \begin{gather*} R(q) = q^{\frac15} \dfrac{1}{1+\dfrac{q}{1+\dfrac{q^2}{1+\dfrac{q^3}{1+\ddots}}}} = q^{\frac15} \frac{\qPochhammer{q,q^4}{q^5}} {\qPochhammer{q^2,q^3}{q^5}} = \frac{\eta_{5,1}(\tau)}{\eta_{5,2}(\tau)} \end{gather*}
Let us consider 5-dissections of $\frac{R(q)^5}{q} = \frac{H(q)^5}{G(q)^5} = \frac{\qPochhammer{q,q^4}{q^5}^5} {\qPochhammer{q^2,q^3}{q^5}^5}$ and $\frac{q}{R(q)^5} = \frac{G(q)^5}{H(q)^5} = \frac{\qPochhammer{q^2,q^3}{q^5}^5} {\qPochhammer{q,q^4}{q^5}^5}$.
For the input into the algorithms of QEta they are specified as follows.
idxs := [[5,1],[5,2]];
rrspec := eqSPEC [[5,1,1],[5,2,-1]];
r5spec := rrspec^5
ir5spec := inv r5spec
A relation for the 5-dissection of $\frac{\qPochhammer{q,q^4}{q^5}^5} {\qPochhammer{q^2,q^3}{q^5}^5}$ is
idrp := findIdM1(5,r5spec,5,0,idxs);
e1 := inv(coefficient idrp)*qequationX(idrp,a[1])
-- == z:=[zinhom=[[1, 1]], zhom=[], zfree=[]] -- numOfGaps:=[0, 0]
and for the 5-dissection of $\frac{\qPochhammer{q^2,q^3}{q^5}^5} {\qPochhammer{q,q^4}{q^5}^5}$ it is the following.
idrn := findIdM1(5,ir5spec,5,0,idxs);
e2 := inv(coefficient idrn)*qequationX(idrn,a[2])
-- == z:=[zinhom=[[1, 1]], zhom=[], zfree=[]] -- numOfGaps:=[0, 0]
Interestingly, the right-hand side of the above equations look equal. However, the have different cofactors. And since they were done by different computations, the $M_1$ may stand for different eta-quotients. In the above case, it turns out, they are same.
(monoidSpecifications(idrp) = monoidSpecifications(idrn))@Boolean
Thus, both left-hand sides must be equal. Note that in QEta $u_{5,1}$ and $u_{5,2}$ stand for the $q$-Pochhammer symbols $\qPochhammer{q,q^4}{q^5}$ and $\qPochhammer{q^2,q^3}{q^5}$.
Therefore, after multiplying with some variables, we get the following.
rhs(e1-e2)
q^2 * u[5,1]^(-1) * u[5,2]^(-11) * (lhs(e1)=lhs(e2))
Compiling function G7225 with type Integer -> Boolean
It says that \begin{align*} \frac{G(q)}{H(q)} \, U_5\!\left(\frac{H(q)^5}{G(q)^5}\right) &= \frac{H(q)}{G(q)} \, U_5\!\left(\frac{G(q)^5}{H(q)^5}\right) \end{align*} or \begin{align*} U_5\!\left(\frac{R(q)^5}{R(q^5)}\right) &= U_5\!\left(\frac{R(q^5)}{R(q)^5}\right) \end{align*}
where $U_5$ is the operator that acts as follows: \begin{gather*} U_5\left(\sum_{n=k}^\infty a(n)q^n\right) = \sum_{n=\lceil k/5 \rceil}^\infty a(5n)q^n. \end{gather*}
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
Find Relation for $R(q)^5$ and $R(q^5)$¶
-------------------------------------------------------------------
--test:RogersRamanujanContinuedFraction-modpol
-------------------------------------------------------------------
In Ramanujan's notebook Ramanujan, S.: Notebooks, 2 volumes. Tata Institute of Fundamenmtal Research, Bombay (1957) there is a relation \begin{align*} R(q)^5 &= R(q^5)\cdot \frac{1 - 2 R(q^5) + 4 R(q^5)^2 - 3 R(q^5)^3 + R(q^5)^4} {1 + 3 R(q^5) + 4 R(q^5)^2 + 2 R(q^5)^3 + R(q^5)^4}, \end{align*} where $R(q)$ is defined by \begin{gather*} R(q) = \frac{\eta_{5,1}(\tau)}{\eta_{5,2}(\tau)}. \end{gather*} This relation involves only $R(q)^5$ and $R(q^5)$, which are both modular functions for $\Gamma_1(25)$. Let us compute the modular polynomial between the two.
rspec := eqSPEC(25, [[5,1,1],[5,2,-1]]);
rspec5 := rspec^5;
r5spec := eqSPEC(25, [[25,5,1],[25,10,-1]]);
specrx := rspec5::SPECR(ZZ);
specry := r5spec::SPECR(ZZ);
[pretty(specrx, formatAsExpression()), pretty(specry, formatAsExpression())]
[level specrx, level specry]
[modularGamma1? specrx, modularGamma1? specry]
We compute a datastructure that contains enough information
to compute the pole orders (qetaGrades
) of the respective
$q$-expansions at the cusps without computing the actual
series.
gammas := cuspMatrices(25)$QMOD1
rspecs := [rspec5, r5spec];
yauxs := [specYM1EQ(spec,gammas) for spec in rspecs];
qgrdss := [qetaGrades x for x in yauxs]
Cusps that correspond to non-poles in the series expansions for both $R(q)^5$ and $R(q^5)$ can be excluded for the computation of the modular polynomial between the two.
trfs := [gammas.i for i in 1..#qgrdss.1 | qgrdss.1.i > 0 or qgrdss.2.i > 0]
spitzen := map(cusp, trfs)
For the expansions at the remaining cusps, the coefficient ring must be extended. From the data we have, we conclude that an extension by a 10-th root of unity (we call it $\xi$) is enough.
ys := [specYM1EQ(spec,trfs) for spec in rspecs];
xiord := lcm [minimalRootOfUnity(y)::PP for y in ys]
EXTENDEDCOEFFICIENTRING(C, xiord, CX, xi);
)read convenience.input )quiet
ans := [specM1An(CX)(x) for x in rspecs]
a1 := ans.1
a2 := ans.2
modPolynomial ==> modularPolynomial$QEtaModularEquation(CX, An CX)
The modular polynomial between $x=R(q)^5$ and $y=R(q^5)$ can easily be computed and agrees with the equation given above.
mp := modPolynomial([a1,a2],[x,y],[])
c0 := coefficient(mp,x,0); c1 := -coefficient(mp,x,1);
x = c0/c1
assertEquals(c0/c1, y * ((1-2*y+4*y^2-3*y^3+y^4)) / (1+3*y+4*y^2+2*y^3+y^4))
Note that $\xi$ is a primitive 10-th root of unity.
factor c0
factor c1
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
More functions¶
-------------------------------------------------------------------
--test:Specification
-------------------------------------------------------------------
Specification of eta-quotients¶
Let $M$ be a positive integer and $\delta$ be a positive divisor of $M$.
The Dedekind eta-function is defined as \begin{align*} \eta: \setH \to \setC, \quad \tau \mapsto q^{\frac{1}{24}} \prod_{n=1}^{\infty}(1-q^n) &= q^{\frac{1}{24}} \qPochhammer{q}{q} \end{align*} where $\setH=\{\tau\in \setC \mid \mathrm{Im}(\tau)>0 \}$ denotes the complex upper half-plane and $q=\exp(2\pi i\tau)$.
Furthermore let $0 \le g \le \delta$.
With $P_2(x) = \{x\}^2 - \{x\} + \frac{1}{6}$ (where $\{x\}= x-\lfloor x \rfloor$ is the fractional part of x) define the generalized eta-function \begin{align*} \eta_{\delta,g}(\tau) &:= q^{\frac{\delta}{2}P_2(\frac{g}{\delta})} % \prod_{\substack{n>0\\n\equiv g\ (\mathrm{mod}\ \delta)}} (1-q^n) \prod_{\substack{n>0\\n\equiv -g\ (\mathrm{mod}\ \delta)}} (1-q^n) \end{align*} For $0<g<\delta$ we have \begin{align} \eta_{\delta,g}(\tau) &= q^{\frac{\delta}{2}P_2(\frac{g}{\delta})} % \prod_{n=1}^\infty (1-q^{\delta (n-1)+g})(1-q^{\delta n-g}) \notag\\ &= q^{\frac{\delta}{2}P_2(\frac{g}{\delta})} % \qPochhammer{q^{g}}{q^\delta} \qPochhammer{q^{\delta-g}}{q^\delta} = q^{\frac{\delta}{2}P_2(\frac{g}{\delta})} % \qPochhammer{q^{g},q^{\delta-g}}{q^\delta}. \end{align}
Note that \begin{gather} \eta_{\delta,0}(\tau) = \eta_{\delta,\delta}(\tau) = \eta(\delta\tau)^2 \qquad\text{and}\qquad \eta_{\delta,\frac{\delta}{2}}(\tau) = \frac{\eta(\frac{\delta}{2}\tau)^2}{\eta(\delta\tau)^2}. \label{eq:purify-eta} \end{gather}
Let a generating series be defined as follows. \begin{gather*} \sum_{n=0}^\infty a(n)q^n = \prod_{\delta|M} \qPochhammer{q^\delta}{q^\delta}^{r_\delta} \prod_{\substack{\delta | M \\ 0 < g < \delta/2}} \qPochhammer{q^g, q^{\delta-g}}{q^\delta}^{r_{\delta,g}} \end{gather*}
QEta finds an identities for \begin{gather*} \sum_{n=0}^\infty a(mn+k)q^n \end{gather*} in terms of generalized eta-quotients.
In QEta such a sequence $(a(n))_{n\geq0}$ is specified by the respective list of pairs $(\delta, r_\delta)$ and triples $(\delta,g,r_{\delta,g})$.
In fact, we call such a list an eta-specification, since it specifices a product of eta functions as \begin{align*} g_r(\tau) &= \prod_{i\in I} \eta_i(\tau)^{r_i} = \prod_{\delta\in I^{(1)}} \eta(\delta\tau)^{r_\delta} \prod_{(\delta,g)\in I^{(2)}} \eta_{\delta,g}(\tau)^{r_{\delta,g}} % \label{eq:g_r(tau)} \end{align*} where $I$, $I^{(1)}$ and $I^{(2)}$ denote the respective index part from the pairs and triples of the above list.
To simplify input in QEta, whenever a series like
\begin{gather*}
\sum_{n=0}^\infty a(mn+k)q^n
\end{gather*}
is to be specified, then it is done by
(rspec, m, k)
where rspec
is an eta-specification and
$k<m$ are natural numbers.
QEta takes care of the additional fractional
$q$-powers that are actually also involved.
So, the specification [[1,-5],[3,7],[5,1,-2],[15,3,1]]
means the following.
rspec := eqSPEC [[1,-5],[3,7],[5,1,-2],[15,3,1]];
level rspec
etaQuotient(rspec, varEta) = qEtaQuotient(rspec, varPochhammer)
We can check whether this eta-quotient is actually a modular function.
Since that specification involves generalized eta-functions, QEta refuses to check for modularity with respect to $\Gamma_0(15)$, i.e. if we remove the comment sign (two minuses) from the following line and evaluate, we get an error.
-- modular?(rspec)$QMOD0
It is also not a modular function for $\Gamma_1(15)$.
assertEquals(modular?(rspec)$QMOD1, false)
QEta can find a cofactor eta-quotient such that
(when multiplied to rspec
) the result is
a modular function for $\Gamma_1(15)$.
idxs := [[1],[3],[5],[15],[15,1],[15,2],[15,3]];
sspec:=cofactInfM1(15, idxs, rspec, 1, 0)
-- == z:=[zinhom=[], zhom=[], zfree=[]] -- >= z:=[zinhom=[[-1, 1, 1, 0, 2, -2], [-2, 2, 1, 0, 3, -3], [-1, 2, 1, 0, 2, -2], [0, 1, 1, 0, 1, -1], [-2, 3, 1, 0, 3, -3], [-2, 2, 2, 0, 4, -2], [0, 1, 1, -1, 2, -2], [-2, 2, 1, 0, 2, -2], [-1, 1, 1, 0, 1, -1], [-3, 3, 1, 0, 3, -3], [-3, 2, 2, 0, 4, -2], [-1, 1, 1, -1, 2, -2], [-1, 1, 1, 0, 2, -1], [-3, 3, 1, 1, 3, -3], [-1, 1, 1, 1, 1, -1], [-2, 2, 1, 1, 2, -2], [-4, 4, 1, 1, 4, -4], [-1, 1, 1, 0, 3, -3], [-2, 2, 1, 0, 3, -2]], zhom=[[-3, 2, 1, 2, 2, -2], [-2, 1, 1, 2, 1, -1], [-2, 2, 1, 1, 2, -2], [-1, 1, 1, 1, 1, -1], [-2, 1, 1, 1, 2, -2], [0, 1, 1, 0, 1, -1], [-3, 2, 1, 1, 2, -2], [-2, 1, 1, 1, 1, -1], [-1, 1, 1, 0, 1, -1], [-2, 1, 1, 0, 1, -1], [-4, 3, 1, 2, 3, -3], [-2, 1, 1, 1, 2, -1], [-3, 2, 2, 2, 4, -4], [-4, 2, 2, 3, 4, -4], [-5, 3, 2, 3, 5, -5], [-6, 3, 3, 4, 7, -7]], zfree=[]]
Note that in QEta the specifications themselves form a (multiplicative) group, just like the corresponding eta-quotients do. Thus, we can multiply and divide them.
spec := sspec * rspec
etaQuotient(spec, varEta)
modular?(spec)$QMOD1
In particular when dealing with dissections we should expect that we must consider eta-functions with bigger indices. QEta suggests that to find an eta-quotient cofactor $c$ (and a certain fractional $q$-power) to make \begin{gather*} q^\beta c \sum_{n=0}^\infty a(mn+k)q^n \end{gather*} modular for $\Gamma_1(N)$ where \begin{align*} \sum_{n=0}^\infty a(n)q^n &= \qPochhammer{q^2,q^5}{q^7}^{-1} \qPochhammer{q^3, q^4}{q^7}^{-2}, \end{align*} we need at least $N=21$. See Section 2 of Chen, Du, Zhao: "Finding Modular Functions for Ramanujan-Type Identities".
rspec := eqSPEC [[7,2,-1],[7,3,-2]]
m := 9; k := 5;
nn := minLevelM1(rspec, m, k)
However, even if we find a cofactor eta-quotient so that we arrive at a modular function, there might not be enough eta-quotients in that level to find a $\setQ$-linear combination of those for this modular function.
rspec := eqSPEC [[1,-1]]; m := 11; t := 6;
nn := minLevelM1(rspec, m, t)
idxs := etaFunctionIndices nn
sspec := cofactInfM0(nn, idxs, rspec, m, t)
-- == z:=[zinhom=[[0]], zhom=[], zfree=[]]
At least, we know that this is a modular function for $\Gamma_0(11)$ with only a pole at $\infty$.
sump := sum('p(11*n+6)*q^n,n=0,%Infinity);
ai := alphaInfinity(sspec,rspec,m,[t]);
e := ai-rhoInfinity(sspec);
qQuotient(sspec, varEta, e) * sump =_
qQuotient(sspec, varPochhammer, ai) * sump
As a $q$-expansion it looks like this.
specM0A1(QQ)(sspec, rspec, m, t)
The monoid of modular eta-quotients of level 11 having at most a pole at $\infty$ is generated by only one element with the following expansion.
mspecs := mSPECSInfM0(level sspec, idxs)
[etaQuotient(x, varEta) for x in mspecs]
[specM0A1(QQ)(x) for x in mspecs]
From that is clear that we are not able to represent a function with a 4-fold pole by a function with a 5-fold pole at infinity.
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
Expansion into $q$-series¶
-------------------------------------------------------------------
--test:qseries-expansion
-------------------------------------------------------------------
Any specification of a (generalized) eta-quotient can be expanded (at $\infty$) into a $q$-series (with possibly fractional exponents according to the definition of the (generalized) Dedekind eta-function given in the previous section.
rspec := eqSPEC [[7,2,-1],[7,3,-2]]
specEQI(QQ)(rspec)
rspec := eqSPEC [[1,-1]]
specEQI(QQ)(rspec)
QEta can also deal with $q$-Pochhammer symbols, since it just means to ignore the respective fractional $q$-power prefactor of an eta-quotient.
rspec := eqSPEC [[7,2,-1],[7,3,-2]]
qQuotient(rspec, varPochhammer, 0) =_
eulerExpansion specEQI(QQ)(rspec)
To arrive at the $q$ expansion of the generating series for $p(7n+5)$, we can enter the following.
rspec := eqSPEC [[1,-1]]; m := 7; t := 5;
sump := sum('p(7*n+5)*q^n,n=0,%Infinity);
sump = choose(m, t, eulerExpansion specEQI(QQ)(rspec))
If the specification happens to be a modular function,
then QEta offers another way to compute the
series expansion at $\infty$, namely by the function
specM1A1
.
rspec := eqSPEC [[5,1,-1],[5,2,-11]];
etaQuotient(rspec, varEta)
modular?(rspec)$QMOD1
specM1A1(QQ)(rspec)
specEQI(QQ)(rspec)
Note that this function corresponding to rspec
,
obviously must have poles at cusps
different from $\infty$.
cusps(5)$QMOD1
If we want to investigate \begin{gather*} \sum_{n=0}^\infty a(mn+k)q^n \end{gather*} for the sequence $(a(n))_{n\in\setN}$ given by \begin{gather*} \sum_{n=0}^\infty a(n)q^n = \qPochhammer{q,q^4}{q^5}^{-1} \qPochhammer{q^2, q^3}{q^5}^{-11}, \end{gather*} we first compute an eta-quotient cofactor to turn the product into a modular function for $\Gamma_1(5)$ with only a pole at $\infty$.
As said above the tuple (sspec, rspec, m, k)
actually (implicityly) involves a certian
factor $q^\beta$ that is determined by
(rspec,m,k)
. Details can be found in
equation labelled eq:beta
in the file
qeta.tex.
It is described by the second term in the definition of
$\alpha$ in the abstract of
Radu's article or
the $q$-factor in equation (10.4) of the article of
Chen, Du, and Zhao.
idxs := [[5,1],[5,2]]
sspec := cofactInfM1(5, idxs, rspec, 5, 4)
modular?(sspec,rspec,5,4)$QMOD1
-- == z:=[zinhom=[[4, 2]], zhom=[], zfree=[]]
In fact, (sspec,rspec,5,4)
represents the
following expression.
ai := alphaInfinity(sspec,rspec,5,[4])$SPEC;
beta := ai-rhoInfinity(sspec);
qQuotient(sspec, varEta, beta) * sum('a(5*n+4)*q^n,n=0,%Infinity)
The expansion at $\infty$ can then be done like this.
specM1A1(QQ)(sspec,rspec,5,4)
That expansion suggests that there is a congruence modulo 5 hidden in the coefficients. And indeed, here is a corresponding witness identity.
id := findIdM1(5, rspec, 5, 4, idxs);
pretty(id, formatWithQFactor() + formatExpanded() + formatAsNonModular()_
+ formatAsExpression())
-- == z:=[zinhom=[[4, 2]], zhom=[], zfree=[]] -- numOfGaps:=[0, 0]
Choosing other index sets, one can also get an identity with eta-quotients with those indices.
id := findIdM1(5, rspec, 5, 4, [[1],[5],[5,1]]);
pretty(id, formatWithQFactor() + formatExpanded() + formatAsNonModular()_
+ formatAsExpression())
-- == z:=[zinhom=[[4, 2]], zhom=[], zfree=[]] -- numOfGaps:=[0, 0]
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
$\Gamma_0(N)$, $\Gamma_1(N)$, cusps and more¶
-------------------------------------------------------------------
--test:Gamma
-------------------------------------------------------------------
QEta provides the domains
CongruenceSubgroupGamma0
and
CongruenceSubgroupGamma1
for a number of functions connected to
$\Gamma_0(N)$ and $\Gamma_1(N)$.
These domains are abbreviated by GAMMA0
and GAMMA1
,
respectively through qetamacros.input
.
nn := 22
genus()$GAMMA0(nn)
numberOfCusps()$GAMMA0(nn)
spitzen := cusps()$GAMMA0(nn)
ws := [width(c)$GAMMA0(nn) for c in spitzen]
assertEquals(ws, [22,2,11,1])
[cuspToMatrix(c)$GAMMA0(nn) for c in spitzen]
doubleCosetRepresentatives()$GAMMA0(nn)
We can do similar things for $\Gamma_1(22)$.
nn := 22
genus()$GAMMA1(nn)
numberOfCusps()$GAMMA1(nn)
spitzen := cusps()$GAMMA1(nn)
[width(c)$GAMMA1(nn) for c in spitzen]
[cuspToMatrix(c)$GAMMA1(nn) for c in spitzen]
doubleCosetRepresentatives()$GAMMA1(nn)
Which of the cusps of $\Gamma_1(22)$ are $\Gamma_0(22)$-equivalent to $\infty$.
cs := [c for c in spitzen | equivalentCusps?(oo, c)$GAMMA0(nn)]
assertEquals(cs, [cusp(3,22),cusp(5,22),cusp(7,22),cusp(9,22),oo])
So when we "normalize" these cusps, they should all look the same. When we do this over all cusps of $\Gamma_1(22)$, they collapse to the cusps of $\Gamma_0(22)$.
assertEquals([normalizeCusp(c)$GAMMA0(nn) for c in cs], [oo,oo,oo,oo,oo])
ll := [normalizeCusp(c)$GAMMA0(nn) for c in spitzen]
cs := cusps()$GAMMA0(nn)
assertEquals(ll, [cs.n for n in [1,2,3,1,3,4,1,3,2,1,4,3,2,4,1,2,4,2,3,4]])
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
Expansion at cusps¶
-------------------------------------------------------------------
--test:expansion-at-cusps
-------------------------------------------------------------------
Let us consider the Rogers-Ramanujan continued fraction. \begin{gather*} R(q) = q^{\frac15} \dfrac{1}{1+\dfrac{q}{1+\dfrac{q^2}{1+\dfrac{q^3}{1+\ddots}}}} = q^{\frac15} \frac{\qPochhammer{q,q^4}{q^5}} {\qPochhammer{q^2,q^3}{q^5}} = \frac{\eta_{5,1}(\tau)}{\eta_{5,2}(\tau)} \end{gather*}
rspec := eqSPEC [[5,1,1],[5,2,-1]];
r5spec := rspec^5
modular?(r5spec)$QMOD1
QEta precomputes data about eta-quotients into a
data structure that we call symbolic eta-qutient.
The transformation of a specification into such a
data structure is done by
specYM1EQ
(specification to sYmbolic Modular
(for $\Gamma_1$) Eta-Quotient).
Since the data structure is rather big, we put a semicolon
at the end of the line, so that nothing is printed.
yr5 := specYM1EQ r5spec;
For specifications without dissections, the order at the cusps can be directly read off from the following command. We also print the respective cusps for the orders of expansion.
trfs := transformationMatrices yr5
map(cusp, trfs)
orders yr5
Let us check the following identity.
\begin{align*} \frac{1}{R(q)^5} - R(q)^5 &= 11 + \frac{\eta(\tau)^6}{\eta(5\tau)^6} \end{align*}
\begin{align} \frac{\eta_{5;2}(\tau)^5}{\eta_{5;1}(\tau)^5} - \frac{\eta_{5;1}(\tau)^5}{\eta_{5;2}(\tau)^5} &= 11 + \frac{\eta(\tau)^6}{\eta(5\tau)^6} %\tag{1.5} \end{align}
espec := eqSPEC [[1,6],[5,-6]]
modular?(espec)$QMOD1
ye := specYM1EQ espec;
orders ye
Obviously, we have poles not only at $\infty$. Let us show another identity from which the above will follow, namely: \begin{align*} \frac{1}{R(q)^{10}} - 11 \frac{1}{R(q)^5} - \frac{\eta(\tau)^6}{\eta(5\tau)^6 R(q)^5} &= 1 \end{align*}
\begin{align} \frac{\eta_{5;2}(\tau)^{10}}{\eta_{5;1}(\tau)^{10}} - 11 \frac{\eta_{5;2}(\tau)^5}{\eta_{5;1}(\tau)^5} - \frac{\eta(\tau)^6}{\eta(5\tau)^6} \frac{\eta_{5;2}(\tau)^5}{\eta_{5;1}(\tau)^5} &= 1 \end{align}
i10spec := rspec^(-10);
i5spec := rspec^(-5);
gspec := espec*i5spec;
All parts of the equation are modular functions for $\Gamma_1(5)$. Even more, they only have poles at the cusp $\infty$.
[modular?(i5spec)$QMOD1, modular?(gspec)$QMOD1]
yi5 := specYM1EQ i5spec;
yi10 := specYM1EQ i10spec;
yg := specYM1EQ gspec;
orders yi5
orders yi10
orders yg
So we only need to check whether the principal part of the $q$-expansion at infinity of the left-hand side vanishes and the constant term is 1. This is indeed the case.
specM1A1(ZZ)(i10spec) - 11*specM1A1(ZZ)(i5spec) - specM1A1(ZZ)(gspec)
QEta does not only implement the expansion of a modular function at the cusp infinity, but also at other cusps. For example, the expansion of $R(q)^5$ at all cusps of $\Gamma_1(5)$ is given below.
The expansion at all cusps cannot be done with series over $\setQ$, but needs an extension with a primitive root of unity $\xi$. In our case, $\setQ[\xi]$ works as the ring of coefficients when $\xi^{10}=1$.
xiord := minimalRootOfUnity yr5;
assertEquals(xiord,10)
Let us first read another set of macros provided by QEta.
Note that by definition of the macros in convenience.input
,
we must set the variable trfs
appropriately, since this
variable is implicitly used in some macros. This variable
specifies the matrices corresponding the the cusps where
the series expansion is done.
)read convenience.input )quiet
C ==> QQ
EXTENDEDCOEFFICIENTRING(C, xiord, CX, xi);
trfs := transformationMatrices(yr5)
map(cusp, trfs)
)set stream calc 3
r5 := expandM1AnCX yr5
Now we can also show the original identity directly by checking that the principle part (including the constant term) vanishes at all cusps.
one := 1$An(CX)
left := one/r5 - r5
right := 11*one + expandM1AnCX ye
assertTrue(zero?(left - right))
Similarly, we can check \begin{align*} PQ + \frac{9}{PQ} = \frac{Q^3}{P^3} + \frac{P^3}{Q^3} \end{align*} where $P = \frac{\eta(\tau)^2}{\eta(3\tau)^2}$ and $Q = \frac{\eta(2\tau)^2}{\eta(6\tau)^2}$.
This time, we confirm the identity at the cusps of $\Gamma_0(6)$.
Unfortunately, the identity does not consist of terms that are modular for $\Gamma_0(6)$, so we divide by $PQ$ and check this identity.
pspec := eqSPEC [[1,2],[3,-2]];
qspec := eqSPEC [[2,2],[6,-2]];
pqspec := pspec*qspec
s1 := pqspec^(-2)
s2 := qspec^3/pspec^3/pqspec
s3 := pspec^3/qspec^3/pqspec
[modular?(x)$QMOD0 for x in [s1,s2,s3]]
Here we actually need no field extension.
ys := [specYM0EQ(s) for s in [s1,s2,s3]];
xiord := lcm [minimalRootOfUnity y for y in ys]
C ==> QQ
EXTENDEDCOEFFICIENTRING(C, xiord, CX, xi);
trfs := transformationMatrices(ys.1)
one := 1$An(CX);
)set stream calc 3
exs := [expandM0AnCX y for y in ys];
left := one + 9*exs.1
right := exs.2 + exs.3
assertTrue(zero?(left - right))
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------
Recognize series as (generalized) eta-quotients¶
-------------------------------------------------------------------
--test:recognize-eta-quotients
-------------------------------------------------------------------
QEta is able to guess a representation of a $q$-series in terms of a (generalized) eta-quotient. As an example we use the identity of the Rogers-Ramanujan continued fraction. \begin{align} \frac{\eta_{5;2}(\tau)^5}{\eta_{5;1}(\tau)^5} - \frac{\eta_{5;1}(\tau)^5}{\eta_{5;2}(\tau)^5} &= 11 + \frac{\eta(\tau)^6}{\eta(5\tau)^6} %\tag{1.5} \end{align}
We try to recognize $\frac{\eta(\tau)^6}{\eta(5\tau)^6}$ from the $q$-series.
)set stream calc 30
rrspec := eqSPEC [[5,1,1],[5,2,-1]];
rr5 := expansion specEQI(ZZ)(rrspec^5);
ir5 := expansion specEQI(ZZ)(inv(rrspec^5));
)set stream calc 40
f := ir5 - rr5 - 11
We use the coefficient of $f$ up to $q^{20}$ in
order to find the specification.
The value in fser
is what remains after cancelling
the eta-quotient given by fspec
from the input series.
rec := guessEtaQuotientSpecification([[1],[5]],f,20)
assertEquals(rec.fspec, eqSPEC [[1,6],[5,-6]])
Of course rec.fspec
is just a guess and must be
verified by other means.
Similarly, we can guess a generalized eta-quotient by simply listing the indices that we allow in the eta-quotient.
rec := guessEtaQuotientSpecification([[5,1],[5,2]],f,20)
assertEquals(rec.fspec, eqSPEC [[5,1,6],[5,2,6]])
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------