$ \newcommand{\modularOrbit}[1]{\mathcal{O}_{#1}} \newcommand{\qPochhammer}[3][\infty]{\left( #2;#3 \right)_{#1}} \newcommand{\setC}{\mathbb{C}} \newcommand{\setH}{\mathbb{H}} \newcommand{\setQ}{\mathbb{Q}} $ Via jupytext this file can be shown as a jupyter notebook.
QEta is able to prove and find identities of eta-quotients (or their related $q$-Pochhammer counterparts).
This notebook demonstrates the ways to specify the input in QEta. In particular, it is shown, how to enter eta-quotients, quotients of $q$-Pochhammer symbols, dissections of such and linear combinations of those quotients.
It is available in text form as [qetaspex.input-test]
)cd ..
)read input/jfricas-test-support.input )quiet
)type on
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
The following cell should only be evaluated, if you want the traditional 2D ASCII output of FriCAS.
)set output formatted off
)set output algebra on
SpecificationExpressions¶
-------------------------------------------------------------------
--test:specifications
-------------------------------------------------------------------
Overview¶
Historically, QEta started to work with 2-element lists of
integers so that [d,e]stands for $\eta(d\tau)^e$ where $d>0$ and
\begin{align*}
\eta_{\delta}(\tau)
&:=
\eta(\delta\tau)
:=
q^{\frac{\delta}{24}} \qPochhammer{q^\delta}{q^\delta} =
q^{\frac{\delta}{24}} \prod_{n\ge1} (1-q^{\delta n}) =
q^{\frac{\delta}{24}} \qPochhammer{q^\delta}{q^\delta}
\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)$.
Products of such expressions where given by lists of such pairs.
After extension of QEta to generalized eta-quotients, we added triples
[d,g,e] to stand for the $e$-th power of the generalized eta-function
($0 \le g \le \delta$)
\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*}
where
\begin{gather*}
{P_2(x)} = B(\{x\}) = \{x\}^2 - \{x\} + \frac{1}{6}.
\end{gather*}
and
\begin{gather*}
\{x\} = x - \lfloor x \rfloor
\end{gather*}
denotes the fractional part of $x$.
See
@InProceedings{Robins_GeneralizedDedekindEtaProducts_1994,
author = {Sinai Robins},
title = {Generalized Dedekind $\eta$-products},
booktitle = {The Rademacher Legacy to Mathematics},
year = 1994,
editor = {G. E. Andrews and David M. Bressoud and L. Alayne
Parson},
volume = 166,
series = {Contemporary Mathematics},
pages = {119--128},
address = {Providence, RI},
publisher = {American Mathematical Society},
ISBN = {978-0-8218-7757-9}
}
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}. \end{gather*}
Since lists of lists are too easily confused with other things,
we chose to introduce the special type QEtaSpecificatioon
(abbreviated by the macro SPEC) that holds the data
for one eta-quotient.
Since initially we aimed at computing Ramanujan-Kolberg identities
by an algorithm from the
paper by Cristian-Silviu Radu,
we also needed to specify dissections of eta-quotients together with
an additional eta-quotient that had to be multiplied to the
dissection in order to produce a modular function for a certain
congruence subgroup.
Up to QEta 4.0, we just carried around the quadruple
[sspec, rspec, m, t].
For newer versions, we tried to improve the user interface
and therefore, added another type QEtaSpecificationExpression.
This type can be considered to represent products and quotients of eta-functions, $q$-Pochhammer symbols and dissections of them, so that it is possible to express identities in a purely symbolic manner while at the same time it would be possible to compute expansions at the cusps for expressions that represent modular functions.
To understand the structure, a QEtaSpecificationExpression
(abbreviated by the macro SPEX) is essentially a monoid ring
where the coefficients are from a coefficient ring C (often the
rational numbers $\setQ$) and the monomials are of type
QEtaSpecificationExpressionMonomial (abbreviated by the macro
SPEXMON). Such monomials are power products
(negative exponents are allowed) of eta-functions,
$q$-Pochhammer-symbols and (extended) dissections thereof. In fact,
we have already introduced SPEC above. There is also
QPochhammerSpecification (abbreviated by the macro QSPEC),
QGeneratingFunctionVariable (abbreviated by the macro QGFVAR),
QGeneratingFunctionSpecification (abbreviated by the macro
QGFSPEC), and XGeneratingFunctionSpecification (abbreviated by
the macro XGFSPEC).
For a list of all macros see input/qetamacros.input.
An element of QSPEC is a product of a (fractional) power of
the variable $q=\exp(2\pi i \tau)$ and a quotient of
$q$-Pochhammer symbols.
qspec := qPower(3/5) * qPochhammer(q^2,q^5)^2/qPochhammer(q)
An elements of SPEC is an eta-quotient.
spec := eqSPEC([[1,1],[2,-3],[5,1,2]])
An element of QGFSPEC is a power product
(negative exponents are allowed) of elements from
QGeneratingFunctionVariable (abbreviated by the macro
QGFVAR).
An element of QGFVAR essentially stands for a dissection
of a (generalized) $q$-Pochhammer quotient.
gfv := generatingFunction(spec)
Note that from the specification in the argument of
generatingFuncttion only the that corresponds to
products of the form $(1-q^n)$ are considered.
In other words, if expanded such a $q$-series is
a Taylor series with constant term 1.
Therefore, the following specifications all give the
same element of QGeneratingFunctionVariable.
qspec := eulerProduct spec
gfv1 := generatingFunction(qspec)
assertEquals(gfv, gfv1)
gfv2 := generatingFunction(qPower(10)*qspec)
assertEquals(gfv, gfv2)
From that we can choose the $q$ powers that should be in the dissection.
gfv54 := choose(5,4)(gfv)
qgfspec := gfv * gfv54
An element of XGFSPEC is an element of QGFSPEC multiplied by a
certain power of $q=\exp(2 \pi i \tau)$. The exponent of $q$ is automatically
computed by the function lift and corresponds to the summand of
the second sum in the definition of $\alpha$ in the abstract of
Radu's article.
xgfspec := lift qgfspec
The respective inverse function (to remove that extra $q$ power)
is called project.
assertEquals(project xgfspec, qgfspec)
An element from SPEXMON is simply a product of an element from
QSPEC, an element from SPEC, and an element from XGFSPEC.
spexmon := qspec * spec::SPEXMON * xgfspec
It is also possible to use qgfspec directly. QEta takes care
of the extra $q$ power.
qspexmon := qgfspec :: SPEXMON
xspexmon := xgfspec :: SPEXMON
assertEquals(qPochhammerPart qspexmon, qPower(- rhoInfinity qgfspec))
assertEquals(qPochhammerPart xspexmon, 1$QSPEC)
An element of SPEX(C) is a C-linear combination of elements
from SPEXMON.
Let us first assign C to stand for the rational numbers.
C ==> QQ
spex := qPower(-3/5)* qP(q) * (eqSPEC([[5,1,-2]]) * (qspec::SPEX(C) + spec + 3*spexmon))
The partition function is given by the inverse of the
$q$-Pochhammer symbol $\qPochhammer{q}{q}$.
The file
qetamacros.input
provides a number of macros
to simplify the work with QEta. In particular
the qPochhammer function is abbreviated by qP.
Thus, we can simply specify the generating funtion for
the partition numbers $p(n)$ as.
pqspec := inv qP(q)
gfv := [pqspec, 1, 0, 'p, 'n] $ QGFVAR
Note that the variables p and n are only used for the output
of the dissection.
The $(7n+5)$-dissection of this series, we get as follows.
gfv := [pqspec, 7, 5, 'p, 'n] $ QGFVAR
Of course, from gfv one can easily get all the parameters back.
assertEquals(qPochhammerSpecification gfv, pqspec)
assertEquals(multiplier gfv, 7)
assertEquals(offset gfv, 5)
An element of QGFVAR can be coerced into other types.
gfv :: QGFSPEC
gfv :: SPEXMON
pspex := gfv :: SPEX(C)
xspex := lift(gfv) :: SPEX(C)
In the same way, this type conversion works for QSPEC and SPEC.
[pqspec :: SPEXMON, spec :: SPEXMON]
[pqspex := pqspec :: SPEX(C), spex := spec :: SPEX(C)]
If the specification at hand is of the right format, one can also convert from the more general to the more specific type.
pqspex :: QSPEC
spex :: SPEC
pspex :: QGFSPEC
pspex :: QGFVAR
xspex :: XGFSPEC
QEta allows to convert an eta-quotient into the corresponding $q$-Pochhammer expression.
spec
spec :: QSPEC
The reverse way also works, if the $q$-Pochhammer quotient comes with the right (fractional) $q$-power to turn it into an eta-quotient.
retractIfCan(pqspec) @ Union(SPEC, "failed")
(qPower(-1/24)*pqspec) :: SPEC
It is also easy to compute the part that is missing for turning a $q$ Pochhammer quotient into an eta-quotient.
missingSpecificationForEta pqspec
The function lift adds this missing part automatically.
lift(pqspec)
[pqspec, lift(pqspec)::QSPEC]
Things get interesting, when it comes to the SPEX notation.
We can have eta-quotients and $q$-Pochhammer quotients at the
same time.
spexmon := inv(pqspec)::SPEXMON * eqSPEC([[2,3]])
This value can be turned into a $q$-Pochhammer notation
or an eta-quotient (with possibly non-convertible remainders).
The functions qExpression and etaExpression also work
on elements of SPEX(C).
qspexmon := qExpression spexmon
espexmon := etaExpression spexmon
Such expressions can be added and count as different until they are converted into a $q$-Pochhammer- or an eta-expression.
spex := qspexmon :: SPEX(C) + espexmon
qex := qExpression spex
eex := etaExpression spex
assertEquals(qex, 2 * qspexmon)
assertEquals(eex, 2 * espexmon)
If an element of SPEXMON is an appropriate monomial.
It can be converted to the more specific type.
espexmon
assertEquals(retractIfCan(espexmon) @ Union(SPEC, "failed"), "failed")
assertEquals((qPower(1/24)*espexmon)::SPEC, eqSPEC([[1],[2,3]]))
assertEquals((qPower(1/24)*espexmon)::QSPEC, qPower(7/24)*qP(q)*qP(q^2,q^2)^3)
Because of the factor 2, the following fails.
assertEquals(retractIfCan(qPower(1/24) * spex) @ Union(SPEC,"failed"), "failed")
Clearly, the specification is not of generating function form.
assertEquals(retractIfCan(spex) @ Union(QGFSPEC, "failed"), "failed")
Although sspex is symbolically a sum, the following conversion
works, because the input is normalized before it is retracted
to the more specific type.
sspex := 1/2 * qPower(1/24) * spex
assertEquals(sspex :: SPEC, eqSPEC([[1],[2,3]]))
assertEquals(sspex :: QSPEC, qPower(7/24)*qP(q)*qP(q^2,q^2)^3)
Other ways to enter specifications¶
Instead of entering the specification for $\eta(\tau)\eta(2\tau)^3$
via the eqSPEC macro and a list of lists of integers,
it is also possible to do it from a polynomial
or a rational function expression.
Essentially, this is done by the function specification
of the respective domain. However, since this function
is heavily overloaded, there are macros like
eqSPEC, qpSPEC, eqSPEX(C), and pqSPEX(C) that
implicitly name the target domains
SPEC, QSPEC, and SPEX(C).
The eq in the name stands for "eta quotient", and
qp for "$q$-Pochhammer", i.e., the input must be in a form
to interpret them as eta-quotients or $q$-Pochhamer quotients.
By default, the variable name "e" is used as the variable name
that is then replaced by the eta-function, but it is possible
to use any other variable by specifying it as the second parameter
of the eqSPEC macro.
aspec := eqSPEC([[1],[2,3]])
assertEquals(eqSPEC(e1 * e2^3), aspec)
assertEquals(eqSPEC(f1 * f2^3, "f"), aspec)
Generalized eta-functions are entered with a variable name that contains an underscore character.
rspec := eqSPEC([[5,1,1], [5,2,-1]])
assertEquals(eqSPEC(e5_1/e5_2), rspec)
It also works for $q$-Pochhammer specifications like
$\qPochhammer{q}{q}^{-1} \qPochhammer{q^2}{q^2}$ with
the difference that the default variable name is "f".
bqspec := qP(q^2,q^2)/qP(q)
assertEquals(qpSPEC(f2/f1), bqspec)
assertEquals(qpSPEC(u2/u1, "u"), bqspec)
With a similar command, it is possible to directly create expressions from rational functions (with a monomial denominator).
spex := eqSPEX(C)(e2^4 * e5^2 / (e1^2 * e10^4) + _
e2 * e5^5 / (e1 * e10^5) + _
e1^3 * e5 / (e2 * e10^3))
In fact, the monomials of the expression above
are the generators of all eta-quotients of $\Gamma_0(10)$
that have a pole only at infinity, i.e.
any other eta-quotient is a powerproduct (with non-negative
exponents) of the monomials of spex.
The function to compute such generators is abbreviated
by the macro mSPECSInf.
idxs := etaFunctionIndices 10
mspecs := mSPECSInf(MGAMMA0 10)(idxs)
assertEquals(sort support spex, [x::SPEX(C) for x in mspecs])
We can enter the same expression in $q$-Pochhammer notation as follows.
qspex := qpSPEX(C)((f2^4 * f5^2 / (f1^2 * f10^4) + _
f2 * f5^5 / (f1 * f10^5) + _
f1^3 * f5 / (f2 * f10^3)) / q)
assertEquals(etaExpression qspex, spex)
The specification can be turned into a polynomial where the variables ed stand for $\eta(d\tau)$ and yd for $\eta(d\tau)^{-1}$.
polynomial spex
rationalFunction spex
Of course, we can also turn it into an expression where fd stands for $\qPochhammer{q^d}{q^d}$, gd for $\qPochhammer{q^d}{q^d}^{-1}$, and qn for $q^{1/n}$.
polynomial(qPower(1)*qExpression spex)
rationalFunction qExpression spex
bspec := eqSPEC(e2)
bqspec := bspec :: QSPEC
monomial(bspec)
monomial(bqspec)
Of course, we get the original specifications back, if we use the resulting polynomials for a specification expression.
assertEquals(eqSPEC(e2), bspec)
assertEquals(qpSPEC(q12*f2), bqspec)
assertEquals(eqSPEX(C)(e2), bspec :: SPEX(C))
assertEquals(qpSPEX(C)(q12*f2), bqspec::SPEX(C))
Also specification involving dissections can be translated input polynomials, but there is corrently no way to transform such polynomials back into a specification expression.
Note that the respective variable (here p7_5) actually stands for
$q^\rho \sum_{n=0} p(7n+5)q^n$ with
$\rho=\frac{5+\rho_\infty(r)}{7}$ and $r$ corresponding to
definingSpecification of this dissection, see
eqref{eq:beta} in qeta.tex. The symbol q24 stands for $q^{1/24}$.
gfv
rationalFunction(gfv::SPEX(C))
However, if gfv is not in the context of SPEX(C) or
SPEXMON, i.e. rather when it is of type QGFVAR or QGFSPEC,
then the symbol p7_5 stands directly for $\sum_{n=0} p(7n+5)q^n$.
The symbol q12 stands for $q^{1/12}$.
monomial gfv
quotient(gfv^(-2))
rationalFunction((gfv^(-2))::SPEX(C))
-------------------------------------------------------------------
--endtest
-------------------------------------------------------------------